diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml
new file mode 100644
index 00000000..dfe8c29b
--- /dev/null
+++ b/.github/workflows/build-and-deploy.yml
@@ -0,0 +1,40 @@
+name: Build and deploy
+on:
+ workflow_dispatch:
+jobs:
+ compile-and-deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check
+ uses: actions/checkout@v4
+ - name: Build
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y --no-install-recommends zip
+ docker run --rm -v ${PWD}:/docs registry.fit2cloud.com/public/mkdocs-material:latest build
+ zip -r -q -9 site.zip site
+ ls -la site.zip
+ - name: Upload
+ uses: appleboy/scp-action@v0.1.7
+ with:
+ host: ${{ secrets.PANEL_CN_HOST }}
+ username: ${{ secrets.PANEL_CN_HOST_USERNAME }}
+ port: 22
+ key: ${{ secrets.PANEL_CN_HOST_KEY }}
+ source: "site.zip"
+ target: /tmp
+ - name: Deploy
+ uses: appleboy/ssh-action@v1.0.3
+ with:
+ host: ${{ secrets.PANEL_CN_HOST }}
+ username: ${{ secrets.PANEL_CN_HOST_USERNAME }}
+ key: ${{ secrets.PANEL_CN_HOST_KEY }}
+ port: 22
+ script: |
+ cd /tmp
+ rm -rf site
+ unzip site.zip
+ rm -rf /opt/1panel/docs/*
+ mv /tmp/site/* /opt/1panel/docs
+ /usr/local/nginx/sbin/nginx -s reload
+ rm -rf /tmp/site*
diff --git a/.github/workflows/deploy-to-server.yml b/.github/workflows/deploy-to-server.yml
deleted file mode 100644
index 95304f6f..00000000
--- a/.github/workflows/deploy-to-server.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-name: Deploy to server
-on:
- workflow_dispatch:
-jobs:
- deploy-to-server:
- runs-on: ubuntu-latest
- steps:
- - name: Check
- uses: actions/checkout@v4
- - name: ssh deploy
- uses: easingthemes/ssh-deploy@v2.2.11
- with:
- SSH_PRIVATE_KEY: ${{ secrets.PANEL_CN_HOST_KEY }}
- REMOTE_HOST: ${{ secrets.PANEL_CN_HOST }}
- REMOTE_USER: ${{ secrets.PANEL_CN_HOST_USERNAME }}
- SOURCE: ./
- TARGET: /opt/1panel/docs/
- # Arguments to pass to rsync
- ARGS: "-rltgoDzvO --delete"
- # An array of folder to exclude
- EXCLUDE: ".git/"
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..8311d1ba
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+.idea/
+*.iml
+target/
+.vscode
+.DS_Store
+*/.DS_Store
+site/
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..e72bfdda
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..adee36a0
--- /dev/null
+++ b/README.md
@@ -0,0 +1,37 @@
+本仓库保存了 [1Panel 项目](https://github.com/1Panel-dev/1Panel) 的 [官方文档](https://1panel.cn/docs/),该文档使用 [MkDocs](https://github.com/mkdocs/mkdocs) 文档框架下的 [Material for MkDocs](https://github.com/squidfunk/mkdocs-material) 主题进行构建。
+
+## 本地开发
+
+### 克隆本仓库
+```bash
+git clone https://github.com/1Panel-dev/docs.git
+```
+
+### 安装依赖
+```bash
+cd docs
+pip install -r requirements/requirements.txt
+```
+
+### 修改文档内容
+
+本文档的文档结构定义在 `mkdocs.yml` 文件中,文档的具体内容均在 `docs` 目录中。
+
+文档内容使用 markdown 语法编写,若要添加新的文档,需要先在 `mkdocs.yml` 文件中的 `nav` 部分增加对应章节导航。
+
+### 本地调试文档
+```bash
+mkdocs serve
+```
+执行上述命令后,可通过 `http://127.0.0.1:8000` 地址查看生成的文档内容,当修改文档后,页面内容会自动更新。
+
+### 构建文档
+```bash
+mkdocs build
+```
+
+执行上述命令后,会在 `site` 目录下生成文档站点的静态文件,将目录中的内容复制到任意 HTTP 服务器上即可完成文档的部署。
+
+## 问题反馈
+
+如果您发现文档中存在错误,或对文档内容存在疑问,请提交 GitHub Issue 到 [1Panel 项目的主仓库](https://github.com/1Panel-dev/1Panel/issues)
diff --git a/docs/changelog.md b/docs/changelog.md
new file mode 100644
index 00000000..d3e81b94
--- /dev/null
+++ b/docs/changelog.md
@@ -0,0 +1,2940 @@
+## 1 版本说明
+
+!!! note ""
+ **版本号说明:*- 像其它优秀开源项目一样,1Panel 将保持每月发布一个新的功能版本,功能版本中如遇较为紧急或严重的 Bug,将及时推出 Bug 修复的小版本。
+ **1Panel 版本号命名规则为:*- v 大版本.功能版本. Bug 修复版本,示例如下:
+
+ - v1.0.1 是 v1.0.0 之后的 Bug 修复版本
+ - v1.1.0 是 v1.0.0 之后的功能版本
+
+## 2 更新内容
+
+### v1.10.29-lts
+
+2025年4月10日
+
+!!! note "新增功能 :star2:"
+
+ * 【网站】DNS 账户支持 西部数码;
+ * 【网站】DNS 账户支持 ClouDNS;
+ * 【AI】新增 MCP Server 管理功能。
+
+!!! note "功能优化 :sunflower:"
+
+ * 【数据库】优化数据库密码和 IP 权限的校验规则;
+ * 【计划任务】支持删除计划时保留远程备份文件;
+ * 【面板设置】优化未开启密码复杂度验证时的面板密码校验规则;
+ * 【系统】升级 SQLite 依赖,以支持在 LoongArch 上构建。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【应用商店】修复了巴西葡萄牙语创建应用时未加载参数标签的问题;
+ * 【容器】修复了某些情况下容器终端连接失败的问题;
+ * 【容器】修复了编辑 bridge 容器网络类型时可能因 IP 冲突导致编辑失败的问题;
+ * 【计划任务】修复了多个备份账号计划任务中一个失败导致全部失败的问题;
+ * 【面板设置】修复了系统快照同步时默认数据目录不存在却仍可跳转到文件管理的问题;
+ * 【系统】修复了 Swagger 文档中部分注释的路由备注错误的问题。
+
+### v1.10.28-lts
+
+2025年3月19日
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【系统】修复了部分繁体中文翻译错误的问题;
+ * 【系统】修复了部分简体中文翻译错误的问题;
+ * 【系统】修复了国际版本许可证同步异常的问题;
+ * 【容器】修复了容器终端执行 exit 等命令后服务器 CPU 占用率异常升高的问题。
+
+### v1.10.27-lts
+
+2025年3月12日
+
+!!! note "新增功能 :star2:"
+
+ * 【X-Pack】新增许可证到期短信告警功能。
+
+!!! note "功能优化 :sunflower:"
+
+ * 【容器】优化容器内存占用百分比排除缓存计算;
+ * 【文件】优化文件下载进度条的样式;
+ * 【文件】优化文件编辑框适配超长文件路径显示问题;
+ * 【系统】未登录访问 Swagger 时默认返回用户设置的未认证页面。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【容器】修复了创建容器时添加只读类型存储卷异常的问题;
+ * 【容器】修复了容器终端执行 exit 等命令后服务器 CPU 占用率异常升高的问题;
+ * 【工具箱】修复了 Fail2ban 日志路径配置错误的问题。
+
+### v1.10.26-lts
+
+2025年2月26日
+
+!!! note "新增功能 :star2:"
+
+ * 【网站】DNS 账户支持 FreeMyIP。
+
+!!! note "功能优化 :sunflower:"
+
+ * 【AI】GPU 监控支持 CUDA 11 版本;
+ * 【AI】优化英文模式下模型列表页面的显示布局;
+ * 【防火墙】支持强制删除端口转发规则;
+ * 【面板设置】API 接口的 IP 白名单支持 IPv6;
+ * 【系统】优化部分繁体中文翻译;
+ * 【系统】查看日志时取消追踪后默认定位到最后一行。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【概览】修复了部分场景下刷新主页出现“暂时不可用”页面的问题;
+ * 【AI】修复了 AI 代理增强功能在部分场景下证书解析错误的问题;
+ * 【AI】修复了异常状态模型无法删除的问题;
+ * 【AI】修复了编辑 AI 代理增强功能时 SSL 证书未正确回显的问题;
+ * 【容器】修复了编辑容器时数据加载错误的问题。
+
+### v1.10.25-lts
+
+2025年2月20日
+
+!!! note "新增功能 :star2:"
+
+ * 【AI】支持 Ollama 模型管理功能;
+ * 【AI】支持 AI 代理增强功能;
+ * 【AI】GPU 监控功能开放给社区版本;
+ * 【X-Pack】发布 1Panel App。
+
+!!! note "功能优化 :sunflower:"
+
+ * 【应用商店】部分应用支持一键配置 GPU 加速功能;
+ * 【网站】默认文档设置支持下划线等特殊字符;
+ * 【文件】优化了同名文件复制和移动操作的逻辑;
+ * 【文件】上传文件前检查是否存在同名文件。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【应用商店】修复了本地应用描述信息未显示的问题;
+ * 【应用商店】修复了部分场景下可升级应用列表布局错乱的问题;
+ * 【防火墙】修复了复杂网络环境下删除端口转发异常的问题;
+ * 【面板设置】修复了安全入口验证错误的问题。
+
+### v1.10.24-lts
+
+2025年2月10日
+
+!!! note "新增功能 :star2:"
+
+ * 【面板设置】系统语言支持韩语。
+
+!!! note "功能优化 :sunflower:"
+
+ * 【应用商店】应用分类和安装表单字段等适配多语言;
+ * 【应用商店】优化应用名称中特殊字符的限制;
+ * 【数据库】MySQL 和 MariaDB 数据库备份添加 function 备份功能;
+ * 【面板设置】优化部分标签页的样式;
+ * 【面板设置】优化许可证类型显示;
+ * 【系统】统一 API 接口的响应体;
+ * 【系统】为部分接口新增后端校验;
+ * 【系统】优化部分繁体中文翻译;
+ * 【系统】对登录接口的用户密码进行加密处理。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【应用商店】修复了应用详情接口 tags 字段为空的问题;
+ * 【网站】修复了部分场景下网站反向代理配置无法删除的问题;
+ * 【网站】修复了部分场景下反向代理网站防盗链未生效的问题;
+ * 【防火墙】修复了删除复杂端口转发规则报错的问题。
+
+### v1.10.23-lts
+
+2025年1月10日
+
+!!! note "新增功能 :star2:"
+
+ * 【网站】DNS 账户支持雨云;
+ * 【面板设置】支持配置 API 接口密钥的有效期;
+ * 【面板设置】系统语言支持马来语;
+ * 【面板设置】系统语言支持日语;
+ * 【面板设置】系统语言支持巴西葡萄牙语;
+ * 【面板设置】系统语言支持俄语;
+ * 【X-Pack】国际版本开放专业版功能。
+
+!!! note "功能优化 :sunflower:"
+
+ * 【概览】优化概览页整体样式布局;
+ * 【网站】优化了网站状态栏在缩放时提示按钮的显示效果;
+ * 【网站】优化 OpenResty 全局配置;
+ * 【网站】优化了反向代理缓存的默认配置;
+ * 【网站】更新默认 PHP 扩展;
+ * 【容器】优化了删除容器镜像时的提示信息;
+ * 【防火墙】支持复杂网络环境下防火墙端口转发;
+ * 【工具箱】优化 FTP 同步功能;
+ * 【计划任务】优化了计划任务的执行周期显示效果;
+ * 【日志审计】优化了系统登录日志中登录地址的显示方式;
+ * 【面板设置】面板别名支持使用常见特殊字符;
+ * 【面板设置】支持保存自定义主题;
+ * 【系统】优化繁体中文翻译;
+ * 【系统】优化了右下角系统版本的垂直居中显示;
+ * 【系统】完善了 Swagger API 定义;
+ * 【系统】支持异步获取备份文件大小。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【应用商店】修复了应用名称含大写字母时多个同类型应用重启异常的问题;
+ * 【数据库】修复了 PostgreSQL 数据库密码包含部分特殊字符时导致备份失败的问题;
+ * 【容器】修复了拉取镜像页面中日志背景颜色缺失的问题;
+ * 【防火墙】修复了某些情况下无法获取防火墙状态的问题;
+ * 【系统】修复了备份列表分页错误的问题;
+ * 【系统】修复了允许通过旧安全入口进行访问的问题;
+ * 【系统】修复了启用安全入口后,通过 Cloudflare CDN 访问面板时无法正常加载的问题;
+ * 【系统】修复了 API 文档允许匿名访问的问题;
+ * 【系统】修复了 Swagger API endpoints 中缺少的响应类型的问题;
+ * 【系统】修复了演示环境中语言切换功能异常的问题。
+
+### v1.10.22-lts
+
+2024年12月18日
+
+!!! note "新增功能 :star2:"
+
+ * 【网站】新增 .NET 运行环境;
+ * 【面板设置】新增 API 接口功能;
+ * 【X-Pack】短信告警新增自定义通知手机号功能;
+ * 【X-Pack】短信告警新增自定义发送时间段功能。
+
+!!! note "功能优化 :sunflower:"
+
+ * 【应用商店】优化已安装应用的操作按钮布局;
+ * 【网站】优化网站 error_log 配置;
+ * 【数据库】优化数据库连接信息中密码操作按钮的样式;
+ * 【面板设置】优化未认证设置,增强系统安全性;
+ * 【面板设置】未认证设置功能新增 444 和 500 响应;
+ * 【系统】优化英文翻译;
+ * 【系统】优化英文版部分页面的布局;
+ * 【系统】安装脚本新增多语言支持;
+ * 【系统】安装脚本新增葡萄牙语(巴西)支持。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【应用商店】修复了编辑已安装应用时 CPU 和内存限制警告缺失的问题;
+ * 【网站】修复了 PHP 运行环境网站切换 PHP 版本后显示异常的问题;
+ * 【网站】修复了关闭日志界面后仍持续请求日志的问题;
+ * 【网站】修复了 Podman 无法创建 PHP 运行环境网站的问题;
+ * 【网站】修复了更新证书验证方式后 DNS 账户仍无法删除的问题;
+ * 【网站】修复了 CloudDNS 拼写错误的问题;
+ * 【数据库】修复了部分场景下 PostgreSQL 数据库备份失败的问题;
+ * 【数据库】修复了 PostgreSQL 数据库密码包含特殊字符时添加远程数据库失败的问题;
+ * 【容器】修复了编辑 Compose 控制台报错的问题;
+ * 【容器】修复了部分场景下容器命令解析错误的问题;
+ * 【容器】修复了 Compose 编辑窗口快捷键注释错误的问题;
+ * 【主机】修复了部分服务器端口转发功能不能正常使用的问题;
+ * 【面板设置】修复了面板开启 HTTPS 后,证书续签未及时更新的问题;
+ * 【面板设置】修复了更新 1Panel 系统端口后防火墙规则未同步更新的问题。
+
+### v1.10.21-lts
+
+2024年11月20日
+
+!!! note "新增功能 :star2:"
+
+ * 【网站】DNS 服务商新增支持 CloudDNS;
+ * 【网站】DNS 服务商新增支持火山引擎;
+ * 【X-Pack】支持主题颜色自定义设置;
+ * 【X-Pack】支持将代理服务器配置同步至 Docker。
+
+!!! note "功能优化 :sunflower:"
+
+ * 【概览】状态栏磁盘数量过多时默认收起;
+ * 【主机】禁止在文件列表中删除 1Panel 安装目录;
+ * 【主机】优化关于防火墙端口转发不支持 nftables 的提示信息;
+ * 【面板设置】在快照恢复过程中忽略应用恢复失败的情况;
+ * 【系统】导入网站、应用和数据库备份时限制为单文件上传;
+ * 【系统】优化暗色主题的配色方案。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【应用商店】修复了由于应用镜像拉取时间过长导致安装状态持续未完成的问题;
+ * 【容器】修复了某些场景下编辑容器镜像仓库失败的问题;
+ * 【容器】修复了容器编排路径为空时导致删除失败的问题;
+ * 【数据库】修复了远程数据库切换失败的问题;
+ * 【主机】修复了编辑端口转发规则时保存失败的问题;
+ * 【工具箱】修复了 Pure-FTPd 上传文件速度慢的问题;
+ * 【日志审计】修复了部分操作日志错误打印的问题;
+ * 【日志审计】修复了清空网站日志时页面闪烁的问题;
+ * 【面板设置】修复了部分场景下无法获取面板 SSL 证书信息的问题;
+ * 【系统】修复了未认证设置状态码返回不一致的问题;
+ * 【系统】修复了网页全屏后直接关闭浏览器导致左侧菜单消失的问题。
+
+### v1.10.20-lts
+
+2024年10月24日
+
+!!! note "新增功能 :star2:"
+
+ * 【网站】新增 Python 运行环境;
+ * 【网站】支持创建华为云 DNS 账户;
+ * 【X-Pack】WAF 拦截记录支持通过动作进行筛选;
+ * 【X-Pack】新增病毒扫描和计划任务的短信告警提醒。
+
+!!! note "功能优化 :sunflower:"
+
+ * 【应用商店】优化应用升级页面的文件对比弹出框样式;
+ * 【网站】创建运行环境时增加构建超时时间;
+ * 【网站】PHP 运行环境新增 BookStack 扩展模板;
+ * 【数据库】支持添加 17.x 版本的 PostgreSQL 远程数据库;
+ * 【容器】容器日志下载功能修改为下载所有日志内容;
+ * 【容器】编排和编排模板列表支持按名称进行排序;
+ * 【容器】编排列表新增编排目录列并支持跳转功能;
+ * 【容器】重启 Docker 前统一增加配置文件正确性校验;
+ * 【容器】支持通过 Snap 方式安装的 Docker;
+ * 【面板设置】面板 SSL 设置新增证书续签后自动重启 1Panel 服务选项;
+ * 【面板设置】快照列表的大小字段调整为异步获取;
+ * 【系统】优化登录页面软件许可协议提示信息样式;
+ * 【系统】优化了因日志过长导致页面卡顿或无响应的问题;
+ * 【系统】全屏查看日志功能统一修改为网页全屏模式;
+ * 【系统】文件夹选择控件未勾选目录时默认选中当前目录。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【应用商店】修复了 MySQL 忽略升级后依然提示升级的问题;
+ * 【网站】修复了网站启用 HTTPS 后缺失 404 配置条目的问题;
+ * 【网站】修复了 Java 和 Node.js 运行环境页面左侧菜单未选中的问题;
+ * 【数据库】修复了切换 MySQL 和 MariaDB 时频繁出现服务未启动提示的问题;
+ * 【主机】修复了在移动端视图下多文件删除报错的问题;
+ * 【面板设置】修复了快照列表按时间排序报错的问题;
+ * 【系统】修复了系统中提示组件标题存在链接时文字错位的问题。
+
+### v1.10.19-lts
+
+2024年10月15日
+
+!!! note "功能优化 :sunflower:"
+
+ * 【概览】状态栏忽略 overlay 类型的磁盘;
+ * 【网站】自签证书支持 IPv6;
+ * 【网站】反向代理网站配置回源 SNI 后支持 proxy_ssl_name 参数;
+ * 【容器】容器列表页面缓存是否显示应用商店容器的选项;
+ * 【主机】优化服务器同时存在 firewalld 和 ufw 时的防火墙逻辑;
+ * 【面板设置】优化未认证设置页面的样式。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【网站】修复了反向代理网站设置文本替换后配置文件缺失 sub_filter_types 参数的问题;
+ * 【数据库】修复了上传数据库备份文件后,点击恢复按钮提示信息显示错误的问题;
+ * 【主机】修复了当文件的用户和用户组只有 ID 没有名称时,进入权限页面显示为空并导致保存报错的问题;
+ * 【系统】修复了部分页面按钮组边框宽度不一致的问题。
+
+### v1.10.18-lts
+
+2024年09月29日
+
+!!! note "功能优化 :sunflower:"
+
+ * 【网站】优化网站日志的加载逻辑;
+ * 【容器】优化创建和编辑 Compose 时环境变量的配置逻辑;
+ * 【容器】优化 Compose 删除逻辑。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【容器】修复了启动 Compose 时容器列表页面无法正常加载的问题。
+
+### v1.10.17-lts
+
+2024年09月25日
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【系统】修复了在暗色模式下页面底部出现白色横向滚动条的问题;
+ * 【系统】修复了概览页底部未对齐的问题;
+ * 【系统】修复了 WAF 和网站监控概览页状态栏显示错位的问题。
+
+### v1.10.16-lts
+
+2024年09月24日
+
+!!! note "功能优化 :sunflower:"
+
+ * 【概览】优化概览页面布局;
+ * 【容器】容器编排的创建和编辑操作支持配置环境变量;
+ * 【容器】提供彻底删除容器编排的选项,让用户可以自定义是否删除相关条目;
+ * 【容器】容器编排列表显示容器状态;
+ * 【容器】统一容器编排模板列表页日期格式;
+ * 【面板设置】添加 S3 云存储备份账号时,支持 Path 和 Virtual Hosted 两种资源访问方式;
+ * 【系统】调整 Logo 的长宽比,避免出现拉伸变形。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【主机】修复了预览图片和视频资源时,重命名文件导致浏览器缓存内容的问题;
+ * 【主机】修复了因包含 socket 服务监听而导致 SSH 服务未完全关闭的问题;
+ * 【系统】修复了部分浏览器无法访问文件菜单的问题;
+ * 【X-Pack】修复了磁盘类型告警任务日志输出错误的问题。
+
+### v1.10.15-lts
+
+2024年09月12日
+
+!!! note "功能优化 :sunflower:"
+
+ * 【网站】优化了网站页面在不同设备上的样式布局;
+ * 【数据库】优化了数据库页面在不同设备上的样式布局;
+ * 【容器】优化了容器页面在不同设备上的样式布局;
+ * 【主机】统一了主机监控和短信告警获取资源使用率的频率;
+ * 【主机】优化了文件管理页面在不同设备上的样式布局;
+ * 【主机】优化了系统防火墙页面在不同设备上的样式布局;
+ * 【主机】防火墙操作支持添加 IPv6 网段;
+ * 【面板设置】优化了面板设置页面在不同设备上的样式布局;
+ * 【面板设置】备份账号支持手动输入 Bucket 名称;
+ * 【X-Pack】GPU 监控支持 Intel Arc 显卡。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【应用商店】修复了备份恢复弹窗在打开后无法关闭的问题;
+ * 【网站】修复了在网站配置页面删除域名后导致网站访问异常的问题;
+ * 【网站】修复了直接创建反向代理网站和在网站设置页面添加反向代理配置文件不一致的问题;
+ * 【容器】修复了停止状态容器在编辑后会导致端口丢失的问题;
+ * 【主机】修复了文件管理导航栏中输入文本文件路径时显示异常问题;
+ * 【主机】修复了文件管理页面进入终端时,文件路径包含空格导致终端报错的问题;
+ * 【主机】修复了文件夹软链接被误识别为文件的问题;
+ * 【工具箱】修复了 FreshClam 服务关闭失败的问题;
+ * 【系统】修复了部分场景下缓存目录被异常进程占用导致启动失败的问题。
+
+### v1.10.14-lts
+
+2024年08月29日
+
+!!! note "新增功能 :star2:"
+
+ * 【X-Pack】新增短信告警通知功能。
+
+!!! note "功能优化 :sunflower:"
+
+ * 【概览】系统信息栏显示服务器地址;
+ * 【应用商店】将更新应用列表按钮移动到页面顶部;
+ * 【应用商店】应用升级时,默认保留三份备份文件;
+ * 【应用商店】同时支持四个 MySQL LTS 版本;
+ * 【网站】优化申请泛域名证书时手动解析模式下的解析值配置;
+ * 【网站】优化反向代理网站的默认 Connection 请求头配置;
+ * 【网站】创建运行环境网站时,增加对 PHP 镜像存在性的校验;
+ * 【网站】优化运行环境日志的卡顿问题;
+ * 【网站】优化非 PHP 运行环境网站的删除提示信息;
+ * 【数据库】MySQL 数据库绑定用户时增加输入校验;
+ * 【数据库】优化数据库备份页面的界面样式;
+ * 【容器】拉取容器镜像时,镜像名校验支持 digest 格式;
+ * 【容器】修复了因容器端口范围过大导致容器编辑页面无法打开的问题;
+ * 【主机】支持在新建文件夹名称中添加空格;
+ * 【主机】优化文件列表的搜索框长度;
+ * 【主机】文件回收站支持按时间排序;
+ * 【主机】主机防火墙启动时不再自动添加容器端口规则;
+ * 【主机】修复了由于字段值过长导致文件属性页面表格显示异常的问题;
+ * 【计划任务】增加对创建计划任务时备份内容不能为空的校验;
+ * 【面板设置】优化两步验证的校验逻辑;
+ * 【面板设置】创建快照时默认排除套接字相关文件;
+ * 【系统】统一服务器时区的获取方式;
+ * 【系统】支持鼠标点击复制版本号。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【应用商店】修复了部分应用在查看参数页面时,引用的服务名称显示不正确的问题;
+ * 【应用商店】修复了 Redis 密码为空时应用关联失败的问题;
+ * 【网站】修复了由于运行环境日志过多导致页面被撑高的问题;
+ * 【网站】修复了网站日志在处理每行数据量较大的情况下读取失败的问题;
+ * 【网站】修复了删除 PHP 运行环境网站之后未能同时删除关联应用的问题;
+ * 【网站】修复了安装本地已有的过期 PHP 运行环境版本失败的问题;
+ * 【数据库】修复了 MySQL v8.4.2 版本进入设置页面出现报错的问题;
+ * 【容器】修复了删除镜像加速配置后 Docker 服务未重启的问题;
+ * 【主机】修复了通过 IDE 拖拽文件上传时控制台报错的问题;
+ * 【工具箱】修复了病毒扫描引擎卸载后定时任务无法停止的问题。
+
+### v1.10.13-lts
+
+2024年07月23日
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【应用商店】修复了安装 Gitea 应用时选择 PostgreSQL 数据库,点击去安装按钮报错的问题;
+ * 【应用商店】修复了 Go 和 Java 运行环境应用在详情页面点击安装按钮时跳转错误的问题;
+ * 【网站】修复了上传文件权限与 index 目录权限不一致的问题;
+ * 【网站】修复了网站设置页面上传的证书在证书列表页面显示异常的问题;
+ * 【日志审计】修复了部分操作日志解析错误的问题;
+ * 【系统】修复了系统中部分潜在的 SQL 注入漏洞;
+ * 【X-Pack】修复了 1Panel 服务重启后可能导致防篡改状态显示异常的问题。
+
+### v1.10.12-lts
+
+2024年07月18日
+
+!!! note "新增功能 :star2:"
+
+ * 【网站】支持创建 Java 运行环境;
+ * 【网站】支持创建 Go 运行环境;
+ * 【网站】证书申请成功后,支持执行自定义脚本;
+ * 【网站】增加自签证书下载根证书功能;
+ * 【网站】增加修改网站默认页面功能;
+ * 【网站】创建静态或 PHP 运行环境网站时,默认增加一个 404 页面;
+ * 【容器】增加制作容器镜像功能;
+ * 【主机】文件编辑器新增左侧目录树功能;
+ * 【主机】文件列表组件新增创建文件、文件夹功能;
+ * 【主机】文件回收站支持批量还原操作;
+ * 【主机】文件管理功能增加使用 VS Code 打开的选项;
+ * 【主机】文件管理功能支持预览图片、视频、音频、PDF、Word、Excel 等常见文件格式;
+ * 【主机】防火墙支持端口转发功能;
+ * 【工具箱】增加 ClamAV 病毒扫描功能。
+
+!!! note "功能优化 :sunflower:"
+
+ * 【应用商店】优化应用升级逻辑,拉取镜像失败时无需回滚;
+ * 【应用商店】应用升级过程中将忽略按钮设置为不可用状态;
+ * 【网站】网站列表默认按名称排序;
+ * 【网站】反向代理支持配置回源 SNI;
+ * 【网站】网站列表支持根据过期时间排序;
+ * 【网站】屏蔽网站运行目录中特定辅助开发包目录;
+ * 【网站】默认禁用 SSL 证书的 OCSP 校验;
+ * 【网站】更新默认的 SSL 证书加密算法;
+ * 【网站】网站开启 HTTPS 后,默认添加 HSTS 配置;
+ * 【网站】在网站列表中增加显示证书过期时间;
+ * 【网站】续签证书时不重置私钥;
+ * 【网站】推送证书到本地目录时,默认会自动创建所需的文件夹;
+ * 【网站】为 WordPress 模版添加 gd 扩展;
+ * 【数据库】优化远程数据库解绑提示信息;
+ * 【容器】优化容器编排的创建、镜像拉取等前端逻辑;
+ * 【容器】修改多容器编排后,只重新生效修改过的容器;
+ * 【容器】支持添加带端口的 Docker 镜像加速地址;
+ * 【容器】针对容器仓库镜像下载地址进行部分有效性校验;
+ * 【主机】防火墙端口规则全面支持 IPv6;
+ * 【主机】文件编辑器支持网页全屏模式;
+ * 【主机】文件解压操作保留文件的更新时间;
+ * 【主机】文件夹属性显示大小调整为计算所有内部文件的总大小;
+ * 【主机】文本编辑器支持 TypeScript、Vue 等更多语言;
+ * 【主机】文本编辑后,退出前增加未保存提示;
+ * 【主机】文件编辑器风格统一与 Prettier 保持一致;
+ * 【主机】支持查看大于10M的文件属性;
+ * 【主机】计算文件夹大小调整为局部加载;
+ * 【主机】监听编辑器内容变化事件优化;
+ * 【主机】查看文件属性时,解除对二进制文件等的限制;
+ * 【工具箱】查看进程守护日志时支持全屏模式;
+ * 【计划任务】计划任务备份类型任务支持多选应用、网站和数据库;
+ * 【面板设置】优化代理服务器设置页面部分提示信息;
+ * 【面板设置】优化 OneDrive 刷新令牌的更新策略;
+ * 【面板设置】快照恢复操作前,增加服务器磁盘空间是否充足的检测;
+ * 【系统】升级部分前端依赖优化打包速度;
+ * 【系统】移除前端打包时生成的 gzip 文件;
+ * 【系统】将 ctx err 的等号检查替换为 error.is;
+ * 【系统】优化部分代码风格;
+ * 【系统】优化网站日志的加载方式;
+ * 【系统】优化部分页面的英文翻译;
+ * 【X-Pack】WAF 拦截页面增加 IP 黑名单编辑功能。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【概览】修复了概览页数据库统计中未包括 PostgreSQL 数量的问题;
+ * 【概览】修复了概览页中由于磁盘挂载点路径带空格导致无法正常显示的问题;
+ * 【应用商店】修复了部分应用卡片位置不对齐的问题;
+ * 【网站】修复了申请证书页面中 Acme 账号被账号类型覆盖的问题;
+ * 【数据库】修复了 MariaDB 数据库同步失败的问题;
+ * 【容器】修复了使用本地已登录仓库创建容器时仍提示未登录的问题;
+ * 【容器】修复了部分场景下容器日志下载功能异常的问题;
+ * 【主机】修复了部分场景下防火墙列表解析错误的问题;
+ * 【主机】修复了文件上传拖拽栏上传多文件失败的问题;
+ * 【系统】修复了部分后端代码中 orderBy 字段未经过校验,可能存在 SQL 注入问题;
+ * 【系统】修复了代码中一些未正确关闭的文件句柄被忽略的问题;
+ * 【系统】修复了压缩密码包含部分特殊字符会导致 gzip 压缩失败的问题。
+
+### v1.10.11-lts
+
+2024年06月27日
+
+!!! note "功能优化 :sunflower:"
+
+ * 【应用商店】新增 Screego;
+ * 【应用商店】新增 TeamSpeak;
+ * 【应用商店】OpenResty 版本升级至 1.21.4.3-3-3;
+ * 【网站】支持创建 PHP 8.3 版本运行环境;
+ * 【主机】优化文件上传逻辑以减少临时空间占用;
+ * 【系统】优化主机终端全屏按钮样式;
+ * 【系统】演示环境适配网站监控部分功能;
+ * 【系统】统一系统中的启用按钮样式;
+ * 【X-Pack】CC 防御增加 URL 模式;
+ * 【X-Pack】网站监控增加排除 IP 和 User-Agent 设置;
+ * 【X-Pack】网站监控增加状态展示;
+ * 【X-Pack】优化网站监控 CDN 适配功能;
+ * 【X-Pack】优化请求日志中 URL 的显示。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【概览】修复了设置默认网卡后重新登录系统未生效的问题;
+ * 【应用商店】修复了应用升级失败导致原有容器被删除的问题;
+ * 【应用商店】修复了应用升级页面官网等超链接无法跳转的问题;
+ * 【应用商店】修复了由于应用安装包中的 services 为空而导致的系统错误问题;
+ * 【应用商店】修复了 DataEase 导出数据集时出现的异常问题;
+ * 【网站】修复了非 80 端口网站在开启和关闭 HTTPS 时生成配置错误的问题;
+ * 【网站】修复了 PHP 运行环境安装 xmlrpc 扩展失败的问题;
+ * 【网站】修复了 PHP 运行环境安装 maxminddb 扩展失败的问题;
+ * 【主机】修复了部分情况下文件打开时出现中文乱码的问题;
+ * 【计划任务】修复了部分类型计划任务执行周期错误的问题;
+ * 【计划任务】修复了部分场景下计划任务未执行的问题;
+ * 【面板设置】修复了未认证设置表单中初始值保存异常的问题;
+ * 【系统】修复了暗色主题下版本号显示异常的问题;
+ * 【系统】修复了面板主题设置为跟随系统时自动切换失效的问题;
+ * 【X-Pack】修复了部分场景下 WAF 拦截记录与网站不匹配的问题;
+ * 【X-Pack】修复了 404 频率拦截设置白名单失效的问题;
+ * 【X-Pack】修复了使用域名端口方式访问导致访问日志记录异常的问题;
+ * 【X-Pack】修复了社区版本仍然记录网站监控日志的问题;
+ * 【X-Pack】修复了开启网站防篡改后无法在排除目录中创建保护文件的问题;
+ * 【X-Pack】修复了界面设置恢复默认时可能导致主题重置的问题;
+ * 【X-Pack】修复了界面设置中主题色不一致的问题。
+
+### v1.10.10-lts
+
+2024年06月08日
+
+!!! note "新增功能 :star2:"
+
+ * 【数据库】支持多版本 Redis 数据库的切换功能;
+ * 【数据库】支持添加远程 Redis 数据库功能;
+ * 【数据库】支持创建 Redis 数据库的快速命令功能;
+ * 【容器】新增清理构建缓存功能;
+ * 【主机】tar.gz 类型文件压缩和解压功能支持设置密码;
+ * 【工具箱】新增 FTP 功能;
+ * 【面板设置】新增代理服务器设置功能;
+ * 【系统】支持为应用、数据库和目录的备份恢复以及快照创建恢复功能设置压缩密码;
+ * 【X-Pack】新增网站监控功能;
+ * 【X-Pack】支持黑金主题。
+
+!!! note "功能优化 :sunflower:"
+
+ * 【应用商店】应用升级时支持对比 Compose 文件,以确保兼容手动修改的配置;
+ * 【应用商店】优化应用查询接口的响应速度;
+ * 【应用商店】优化应用同步接口的响应速度;
+ * 【网站】添加 Node.js 类型的运行环境时可选择使用 pnpm 作为包管理器;
+ * 【网站】网站目录快速跳转至 index 目录;
+ * 【网站】创建运行环境和静态网站时支持创建 FTP 用户;
+ * 【数据库】添加远程数据库时增加名称校验;
+ * 【数据库】优化 Redis 数据库页面的样式;
+ * 【数据库】Redis 数据库在安装时不再要求强制设置密码;
+ * 【主机】收藏夹悬浮框显示文件夹全路径;
+ * 【工具箱】缓存清理功能支持容器垃圾清理;
+ * 【面板设置】删除快照页面增加是否删除备份文件的选项;
+ * 【网站】网站日志使用主配置文件参数;
+ * 【系统】演示环境禁用容器终端功能;
+ * 【系统】提升移动端登录时勾选开源许可复选框的用户体验;
+ * 【系统】取消右侧抽屉页面的 ESC 按钮关闭功能;
+ * 【系统】定时清理 cache 缓存以优化性能;
+ * 【系统】优化文件分段上传的用户体验;
+ * 【系统】优化安全入口页面的样式特征;
+ * 【X-Pack】优化 CDN IP 的获取方式。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【概览】修复了部分磁盘类型状态显示不完整的问题;
+ * 【应用商店】修复了本地应用升级后版本信息未显示的问题;
+ * 【应用商店】修复了应用安装过程中切换版本时校验条件未同步更改的问题;
+ * 【应用商店】修复了部分场景下应用安装失败后未正确显示的问题;
+ * 【网站】修复了自签证书关闭页面后未刷新的问题;
+ * 【网站】修复了编辑证书页面未显示证书秘钥算法的问题;
+ * 【网站】修复了 PHP 运行环境镜像构建中可以被删除的问题;
+ * 【网站】修复了删除网站后备份文件未同步删除的问题;
+ * 【网站】修复了清空伪静态配置报错的问题;
+ * 【网站】修复了使用本地 PHP 环境启动、停止网站后出现配置错误的问题;
+ * 【网站】修复了网站域名带有多个端口时,快速跳转导航链接错误的问题;
+ * 【数据库】修复了远程 MariaDB 数据库备份失败的问题;
+ * 【数据库】修复了远程数据库列表按名称排序显示错误的问题;
+ * 【主机】修复了部分场景 SSH 登录日志解析失败的问题;
+ * 【主机】修复了文本编辑器在打开 GBK 编码文件时出现乱码的问题;
+ * 【主机】修复了非文本文件打开报错的问题;
+ * 【计划任务】修复了计划任务执行周期解析错误的问题;
+ * 【计划任务】修复了计划任务列表和报告页面上次执行时间显示不一致的问题;
+ * 【系统】修复了系统升级过程中数据库文件备份异常的问题;
+ * 【X-Pack】修复了低版本 OpenResty 打开 WAF 概览页时报错的问题;
+ * 【X-Pack】修复了清空 WAF 日志时未同步删除首页统计数据的问题;
+ * 【X-Pack】修复了网站防篡改状态切换异常的问题。
+
+### v1.10.9-lts
+
+2024年05月24日
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【系统】修复了部分场景下系统升级失败的问题;
+ * 【主机】修复了部分日志文件未及时释放的问题;
+ * 【主机】修复了分块上传文件资源未及时释放的问题。
+
+### v1.10.8-lts
+
+2024年05月23日
+
+!!! note "功能优化 :sunflower:"
+
+ * 【概览】概览页监控上下行流量数据单位自动格式化显示;
+ * 【主机】文件列表中的权限按钮支持更改用户和用户组;
+ * 【工具箱】进程守护列表增加运行目录跳转功能。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【应用商店】修复了部分应用图标无法显示的问题;
+ * 【应用商店】修复了由于应用名称大写而导致升级失败的问题;
+ * 【网站】修复了网站列表在按名称排序时翻页显示错误的问题;
+ * 【网站】修复了编辑证书时多个其他域名未能正确换行显示的问题;
+ * 【网站】修复了上传证书状态显示异常的问题;
+ * 【容器】修复了存储卷清理功能未能完全删除未使用的存储卷的问题;
+ * 【工具箱】修复了进程守护命令无法接受空格输入的问题。
+
+### v1.10.7-lts
+
+2024年05月10日
+
+!!! note "新增功能 :star2:"
+
+ * 【网站】新增证书编辑功能。
+ * 【主机】文件管理页面新增前进和后退功能。
+ * 【面板设置】新增预览体验计划,允许用户升级至 beta 预发布版本。
+ * 【X-Pack】新增清理 WAF 日志功能。
+ * 【X-Pack】新增封锁记录 IP 拉黑功能。
+ * 【X-Pack】WAF 拦截记录增新增添加 URL 至白名单功能。
+
+!!! note "功能优化 :sunflower:"
+
+ * 【应用商店】支持失败状态的应用进行恢复操作。
+ * 【应用商店】备份列表页面支持快速跳转至文件列表页面。
+ * 【网站】申请证书页面新增 CNAME 和 DNS 相关配置。
+ * 【网站】创建网站时限制使用 default 名称作为代号。
+ * 【网站】网站默认配置增加支持 CDN 真实 IP。
+ * 【网站】网站设置页面支持手动输入来设置运行目录。
+ * 【网站】优化反向代理源文编辑页面的默认大小。
+ * 【网站】优化运行环境删除时的提示信息。
+ * 【数据库】远程数据库支持添加 MariaDB 11.x 版本。
+ * 【数据库】优化数据库备份过程中错误信息的显示。
+ * 【工具箱】优化进程守护名称的验证规则。
+ * 【计划任务】切割网站日志类型计划任务增加默认周期。
+ * 【计划任务】优化部分类型计划任务错误信息的显示位置。
+ * 【计划任务】创建备份应用和备份网站类型计划任务时支持设置排除规则。
+ * 【系统】优化系统升级回滚逻辑。
+ * 【X-Pack】WAF 概览页中添加关闭提示信息。
+ * 【X-Pack】增加许可证同步失败重试机制。
+ * 【X-Pack】增强 WAF 并提升 CDN 的兼容性。
+ * 【X-Pack】优化 WAF 拦截记录页面样式。
+ * 【X-Pack】创建 WAF 黑白名单规则时不再强制填写名称。
+ * 【X-Pack】WAF 拦截记录和网站设置页面支持搜索功能。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【应用商店】修复了部分场景下应用升级失败后未能回滚的问题。
+ * 【应用商店】修复了已安装应用由于错误日志过长导致部分信息隐藏的问题。
+ * 【应用商店】修复了部分场景下应用图标丢失的问题。
+ * 【网站】修复了部分场景下使用备份文件进行恢复时导致网站列表页面显示异常的问题。
+ * 【网站】修复了因使用自签名证书而导致火狐浏览器提示异常的问题。
+ * 【网站】修复了创建中文域名运行环境类型网站失败的问题。
+ * 【容器】修复了终端退出导致容器内非主进程异常结束的问题。
+ * 【容器】修复了部分容器客户端连接未释放的问题。
+ * 【容器】修复了部分场景下镜像推送失败的问题。
+ * 【容器】修复了容器编排页面快速跳转到文件列表时默认目录缺失的问题。
+ * 【主机】修复了计算文件夹大小时线程没有回收的问题。
+ * 【主机】修复了英文状态下删除文件时提示信息过长的问题。
+ * 【工具箱】修复了创建进程守护时因启动命令带有空格而导致的报错问题。
+ * 【系统】修复了部分场景下禁用菜单标签页选项后刷新会跳转至概览页的问题。
+ * 【X-Pack】修复了部分场景下网站防篡改状态修改失败的问题。
+ * 【X-Pack】修复了部分场景下 WAF 黑名单修改未生效的问题。
+ * 【X-Pack】修复了部分场景下许可证显示异常的问题。
+ * 【X-Pack】修复了部分场景下编辑 IP 组时异常问题。
+ * 【X-Pack】修复了文件上传限制过滤未生效的问题。
+ * 【X-Pack】修复了部分场景下修改 WAF 拦截页面不生效的问题。
+ * 【X-Pack】修复了拦截趋势数字超过1000后导致 Y 轴显示不全的问题。
+
+### v1.10.6-lts
+
+2024年04月30日
+
+!!! note "功能优化 :sunflower:"
+
+ * 【概览】优化多核 CPU 弹框显示;
+ * 【网站】网站伪静态设置页面增加部分提示信息;
+ * 【网站】优化网站列表备注信息长度限制;
+ * 【网站】创建网站时增加其他域名包含主域名等提示信息;
+ * 【主机】主机快速命令页面支持关键字筛选;
+ * 【主机】优化终端页面在快速切换主机时的提示框信息展示方式;
+ * 【主机】支持连续上传同名文件;
+ * 【X-Pack】优化概览页面的中国地图显示。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【概览】修复了概览页流量、磁盘监控图选择特定指标后因刷新而失效的问题;
+ * 【网`站】修复了由于反向代理匹配规则为空而导致无法删除网站的问题;
+ * 【网站】修复了低版本 OpenResty 创建网站报错的问题;
+ * 【容器】修复了因为设置镜像加速时含有空行而导致 Docker 服务启动失败的问题;
+ * 【计划任务】修复了备份文件保留份数与实际情况不匹配的问题;
+ * 【X-Pack】修复了 WAF 概览页拦截数量显示错误的问题;
+ * 【X-Pack】修复了英文模式下概览页面地图显示错误的问题;
+ * 【X-Pack】修复了攻击地图不显示攻击次数的问题;
+ * 【X-Pack】修复了 SQLite 数据库连接操作异常的问题。`
+
+### v1.10.5-lts
+
+2024年04月19日
+
+!!! note "功能优化 :sunflower:"
+
+ * 【面板设置】优化面板安全入口长度限制。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【网站】修复了网站开启防盗链失败的问题;
+ * 【容器】修复了容器日志文件被删除但进程未结束的问题;
+ * 【系统】修复了许可证接口可以未授权访问的问题;
+ * 【X-Pack】修复了多显卡编号显示异常的问题;
+ * 【X-Pack】修复了未授权域名访问功能返回 500 错误的问题。
+
+### v1.10.4-lts
+
+2024年04月19日
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【网站】修复了因文件权限异常而导致新建运行环境网站报错的问题;
+ * 【主机】修复了文件列表上传文件夹异常的问题;
+ * 【系统】修复了系统升级过程中因监控数据迁移异常而导致失败的问题。
+
+### v1.10.3-lts
+
+2024年04月18日
+
+!!! note "新增功能 :star2:"
+
+ * 【X-Pack】新增 WAF 功能;
+ * 【X-Pack】新增网站防窜改功能;
+ * 【X-Pack】新增 GPU 监控功能;
+ * 【X-Pack】新增界面设置功能。
+
+!!! note "功能优化 :sunflower:"
+
+ * 【概览】点击系统 Logo 支持跳转到概览页面;
+ * 【网站】优化 IP 类型网站名称显示;
+ * 【网站】优化 OpenResty 端口提示信息;
+ * 【容器】创建容器时支持指定 IP 地址;
+ * 【主机】提升文件上传体验;
+ * 【主机】监控数据存储于专用数据库中;
+ * 【主机】文件列表不再支持查看块类型文件;
+ * 【主机】创建文件权限与其父级目录保持一致;
+ * 【主机】上传文件夹的权限与其父级目录保持一致;
+ * 【主机】优化文件修改权限超时时间;
+ * 【主机】取消监控数据天数限制;
+ * 【主机】创建文件时增加部分特殊字符校验;
+ * 【主机】文件列表不再允许访问系统回收站文件夹;
+ * 【工具箱】进程守护名称支持下划线等特殊字符;
+ * 【计划任务】Shell 类型计划任务支持选择容器命令;
+ * 【面板设置】新增菜单标签页功能;
+ * 【面板设置】支持设置未认证响应状态;
+ * 【面板设置】增加高级功能菜单隐藏功能;
+ * 【系统】支持用户首次登录前明文查看用户名信息;
+ * 【系统】优化系统版本的比较逻辑;
+ * 【系统】改进文件复制方式以优化系统升级等过程。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【概览】修复了由于 CPU 核心数较多导致状态信息超出页面范围的问题;
+ * 【概览】修复了部分操作系统下发行版本显示异常的问题;
+ * 【应用商店】修复了安装应用时 deploy 字段被覆盖的问题;
+ * 【应用商店】修复了由于应用 Compose 文件错误而引发系统异常的问题;
+ * 【网站】修复了网站运行目录未完整显示的问题;
+ * 【网站】修复了手动添加 Upstream 配置导致系统异常的问题;
+ * 【容器】修复了编辑容器页面挂载卷回显异常的问题;
+ * 【主机】修复了文件编辑器设置自动换行后,刷新页面导致失效的问题;
+ * 【主机】修复了文件编辑器设置主题后,刷新页面导致失效的问题;
+ * 【主机】修复了文件包含部分特殊字符时放入回收站失败的问题;
+ * 【主机】修复了新建文件夹时指定部分读写权限异常的问题;
+ * 【系统】修复了由于特殊字符过滤不完善可能导致的任意文件写入问题;
+ * 【系统】修复了系统中可能存在的计时攻击漏洞;
+ * 【系统】修复了主机、容器终端功能可能出现僵尸进程的问题。
+
+!!! note "应用商店 :star2:"
+
+ * MaxKB 版本升级至 v1.0.2;
+ * Ollama 版本升级至 v0.1.32;
+ * One API 版本升级至 v0.6.5;
+ * Tomcat 版本升级至 v9.0.88;
+ * Jenkins 版本升级至 v2.440.3;
+ * Umami 版本升级至 v2.11.2;
+ * 南墙版本升级至 v4.1.0;
+ * 禅道版本升级至 v18.12;
+ * 思源笔记版本升级至 v3.0.10;
+ * 幻兽帕鲁服务可视化管理工具版本升级至 v0.7.1;
+ * Domain Admin 版本升级至 v1.6.27;
+ * Metabase 版本升级至 v0.49.6;
+ * MeiliSearch 版本升级至 v1.7.6;
+ * Grafana 版本升级至 v10.4.2;
+ * Home Assistant 版本升级至 v2024.4.3;
+ * Draw.io 版本升级至 v24.2.5;
+ * Tailchat 版本升级至 v1.11.1;
+ * VS Code 版本升级至 v4.23.1;
+ * Material for MkDocs 版本升级至 v9.5.18;
+ * Synapse 版本升级至 v1.105.0;
+ * frp 版本升级至 v0.57.0;
+ * Answer 版本升级至 v1.3.0。
+
+### v1.10.2-lts
+
+2024年03月21日
+
+!!! note "功能优化 :sunflower:"
+
+ * 【应用商店】增加外部访问地址类型校验规则;
+ * 【应用商店】优化部分应用标签;
+ * 【网站】新增苹果CMS-V10 和 SeaCMS PHP 模板;
+ * 【网站】优化网站搜索功能以匹配相关域名;
+ * 【网站】优化网站设置导入证书页面部分描述信息;
+ * 【数据库】同步数据库时为已删除的远程数据库添加已删除标签;
+ * 【容器】拉取镜像日志增加 Unicode 转义功能;
+ * 【主机】修改 SSH 端口后,同时更新终端本地服务器端口;
+ * 【工具箱】将重启面板和服务器功能迁移至工具箱页面;
+ * 【工具箱】守护进程所有操作添加页面加载效果;
+ * 【计划任务】查看计划任务报告支持 ANSI 转义序列;
+ * 【面板设置】支持在创建快照时设置排除目录;
+ * 【系统】优化卸载面板的流程;
+ * 【系统】优化防止命令注入的逻辑;
+ * 【系统】优化系统升级时对服务器架构的判断逻辑。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【应用商店】修复了安装应用过程中可能出现状态异常的问题;
+ * 【应用商店】修复了应用商店详情页面中部分应用图标比例错误的问题;
+ * 【网站】修复了网站配置文件更新后导致参数丢失的问题;
+ * 【网站】修复了 Node.js 运行环境状态显示异常的问题;
+ * 【主机】修复了在部分场景下回收站文件放置错误的问题;
+ * 【计划任务】修复了报告页面因自动刷新而导致查看日志时自动滚动到底部的问题;
+ * 【计划任务】修复了 Shell 脚本等任务列表显示默认备份账号的问题;
+ * 【面板设置】修复了快照恢复时校验 daemon.json 路径失败的问题;
+ * 【面板设置】修复了部分情况下 OneDrive 上传大文件失败的问题;
+ * 【系统】修复了面板安装过程中可能出现端口号被占用的问题;
+ * 【系统】修复了系统中存在的未经授权漏洞。
+
+!!! note "应用商店 :star2:"
+
+ * 新增 MaxKB;
+ * JumpServer 版本升级至 v3.10.6;
+ * Ollama 版本升级至 0.1.29;
+ * 幻兽帕鲁服务端版本升级至 v0.33.0;
+ * Jenkins 版本升级至 v2.440.2;
+ * Answer 版本升级至 1.2.5;
+ * Apache Tomcat 版本升级至 v9.0.87;
+ * ddns-go 版本升级至 v6.2.2;
+ * Draw.io 版本升级至 v24.0.7;
+ * One API 版本升级至 v0.6.2;
+ * Audiobookshelf 版本升级至 v2.8.1;
+ * Stirling-PDF 版本升级至 v0.22.3;
+ * Tailchat 版本升级至 v1.10.1;
+ * Material for MkDocs 版本升级至 v9.5.14;
+ * MongoDB 版本升级至 v7.0.7;
+ * Portainer 版本升级至 v2.20.0;
+ * ClickHouse 版本升级至 v24.2.2;
+ * Domain Admin 版本升级至 v1.6.16;
+ * Synapse 版本升级至 v1.103.0;
+ * Prometheus 版本升级至 v2.51.0;
+ * Twikoo 版本升级至 v1.6.32;
+ * cloudflared 版本升级至 v2024.3.0;
+ * AdGuardHome 版本升级至 v0.107.46;
+ * MeiliSearch 版本升级至 v1.7.2。
+
+### v1.10.1-lts
+
+2024年03月06日
+
+!!! note "功能优化 :sunflower:"
+
+ * 【应用商店】优化本地应用同步功能,增加对 data.yml 文件的正确性验证。
+ * 【应用商店】优化部分应用的描述信息。
+ * 【应用商店】更新 Node.js 运行环境版本。
+ * 【数据库】优化远程 MySQL 数据库备份恢复逻辑。
+ * 【主机】优化添加主机页面的部分内容显示。
+ * 【计划任务】优化 Shell 脚本类型计划任务输出的内容格式。
+ * 【面板设置】执行恢复快照操作时限制跨服务器架构的恢复。
+ * 【面板设置】重试恢复快照操作时跳过已成功的步骤。
+ * 【面板设置】创建快照时重置已配置的服务器地址。
+ * 【系统】封装表格搜索组件,以避免按下回车键时触发两次请求的问题。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【概览】修复了由于获取资源使用率命令执行超时而导致页面报错的问题。
+ * 【网站】修复了部分网站日志查看时出现错误的问题。
+ * 【应用商店】修复了 filebrowser 配置文件默认数据库地址读取错误的问题。
+ * 【应用商店】修复了在 PHP8 运行环境中安装 Swoole 扩展失败的问题。
+ * 【容器】修复了部分场景下获取容器资源利用率错误的问题。
+ * 【容器】修复了由于单位转换错误导致部分服务器内存限制获取异常的问题。
+ * 【面板设置】修复了恢复快照后未加载容器编排列表的问题。
+ * 【系统】修复了页面刷新时右下角版本号显示 `undefined` 的问题。
+ * 【安全漏洞】修复了系统中存在的未经授权漏洞。
+
+!!! note "应用商店 :star2:"
+
+ * Halo 版本升级至 v2.13.0。
+ * JumpServer 版本升级至 v3.10.5。
+ * AList 版本升级至 v3.32.0。
+ * Umami 版本升级至 v2.10.1。
+ * 幻兽帕鲁服务端版本升级至 v0.30.1。
+ * 幻兽帕鲁服务可视化管理工具版本升级至 v0.6.0。
+ * Draw.io 版本升级至 v24.0.1。
+ * VS Code 版本升级至 v4.22.0。
+ * Nacos 版本升级至 v2.3.1。
+ * One API 版本升级至 v0.6.0。
+ * MongoDB 版本升级至 v7.0.6。
+ * ClickHouse 版本升级至 v24.2.1。
+ * 青龙版本升级至 v2.17.2。
+ * Nextcloud 版本升级至 v28.0.3。
+ * Bitwarden 版本升级至 v1.30.5。
+ * Redpanda Console 版本升级至 v2.4.4。
+ * Kafka 版本升级至 v3.7.0。
+ * Metabase 版本升级至 v0.48.8。
+ * Domain Admin 版本升级至 v1.6.15。
+ * Synapse 版本升级至 v1.102.0。
+ * Nexus Repository 版本升级至 v3.66.0。
+ * ShowDoc 版本升级至 v3.2.5。
+ * Memos 版本升级至 v0.20.1。
+ * Jenkins 版本升级至 v2.448。
+
+### v1.10.0-lts
+
+2024年02月27日
+
+!!! note "功能优化 :sunflower:"
+
+ * 【网站】网站配置文件支持 Lua 模块。
+ * 【应用商店】优化应用安装表单的选择器组件,以支持多选功能。
+ * 【应用商店】优化应用描述页面样式。
+ * 【应用商店】优化应用状态同步逻辑。
+ * 【数据库】优化添加 MySQL 远程服务器时的 SSL 验证规则。
+ * 【容器】优化容器配置页面中镜像加速地址的验证规则。
+ * 【主机】优化上传文件的最大数量限制。
+ * 【计划任务】优化备份数据库任务,在选择数据库时添加实例名称标签。
+ * 【面板设置】优化部分页面上的备份账号提示信息。
+ * 【面板设置】在创建快照时,排除已存在于备份目录下的快照文件。
+ * 【系统】删除项目中未被使用的代码。
+ * 【系统】忽略关于 WebDAV 端口信息错误的日志。
+ * 【系统】启用 Cookie 的 HttpOnly 属性。
+ * 【系统】优化系统中带有文本和图标的按钮样式。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【网站】修复了删除 OpenResty 后未同步删除 PHP 运行容器的问题。
+ * 【应用商店】修复了系统语言设置为英文时部分页面翻译错误的问题。
+ * 【容器】修复了容器镜像清理页面未显示所有待清理镜像的问题。
+ * 【容器】修复了容器监控页面网络单位显示错误的问题。
+ * 【主机】修复了通过拖拽上传文件时仅能上传最多 100 个文件的问题。
+ * 【主机】修复了部分场景下通过拖拽方式上传文件夹时出现异常的问题。
+ * 【主机】修复了清空文件后保存异常的问题。
+ * 【系统】修复了系统中部分代码拼写错误的问题。
+ * 【系统】修复了由于备份账号异常导致备份记录无法被删除的问题。
+
+!!! note "应用商店 :star2:"
+
+ * 新增 AI 分类。
+ * 新增 幻兽帕鲁服务可视化管理工具。
+ * 新增 中文 DOS 游戏。
+ * 新增 阅读3服务器版。
+ * 新增 ONLYOFFICE Docs。
+ * 新增 cloudflared。
+ * 新增 Obsidian LiveSync。
+ * Halo 版本升级至 v2.12.4。
+ * AList 版本升级至 v3.31.0。
+ * 幻兽帕鲁服务端版本升级至 v0.28.2。
+ * ChatGPT-Next-Web 版本升级至 v2.11.2。
+ * Metabase 版本升级至 v0.48.7。
+ * Elasticsearch 版本升级至 v8.12.2。
+ * Draw.io 版本升级至 v23.1.6。
+ * RabbitMQ 版本升级至 v3.13.0。
+ * Material for MkDocs 版本升级至 v9.5.11。
+ * Domain Admin 版本升级至 v1.6.13。
+ * Prometheus 版本升级至 v2.50.1。
+ * Home Assistant 版本升级至 v2024.2.4。
+
+### v1.9.6
+
+2024年02月05日
+
+!!! note "功能优化 :sunflower:"
+
+ * 【应用商店】忽略应用升级页面移除强制拉取镜像的复选框。
+ * 【应用商店】应用包含多个容器时不再强制修改服务名称。
+ * 【计划任务】优化计划任务执行周期的校验规则。
+ * 【面板设置】优化快照同步过程中的名称校验规则。
+ * 【系统】优化暗黑模式下的应用详情页面样式。
+ * 【系统】SFTP 客户端增加可连接性校验。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【应用商店】修复了应用版本为 latest 时依然提示升级的问题。
+ * 【数据库】修复了 PostgreSQL 备份文件删除异常的问题。
+ * 【容器】修复了移动设备上容器列表页面中容器名称丢失的问题。
+ * 【计划任务】修复了系统升级后备份数据未正确同步的问题。
+ * 【计划任务】修复了在查看保留份数页面时未正确过滤失败任务的问题。
+ * 【面板设置】修复了部分场景下无法正确添加 AList WebDAV 备份账号的问题。
+ * 【系统】修复了会话 Cookie 未设置 Secure 标识的漏洞。
+
+!!! note "应用商店 :star2:"
+
+ * 新增 MySQL 8.0.36 版本。
+ * Halo 版本升级至 v2.12.2。
+ * Gitea 版本升级至 v1.21.5。
+ * PHP 8.1、8.2 升级至最新版本。
+ * ddns-go 版本升级至 v6.1.1。
+ * frp 版本升级至 v0.54.0。
+ * ClickHouse 版本升级至 v24.1.2。
+ * Redpanda Console 版本升级至 v2.4.1。
+ * 幻兽帕鲁服务端版本升级至 v0.21.0。
+ * Koishi 版本升级至 v1.13.8。
+ * Stirling-PDF 版本升级至 v0.20.2。
+ * Material for MkDocs 版本升级至 v9.5.7。
+
+### v1.9.5
+
+2024年02月02日
+
+!!! note "新增功能 :star2:"
+
+ * 【网站】新增腾讯云 DNS 类型账户。
+ * 【容器】列表增加选择列功能。
+ * 【主机】文件编辑器新增支持 Lua 和 XML 语言。
+ * 【计划任务】创建任务时支持选择多个周期。
+ * 【计划任务】创建任务时支持备份到多个账号。
+ * 【面板设置】OneDrive 类型备份账号添加 Token 刷新机制。
+ * 【面板设置】OneDrive 支持世纪互联账号。
+
+!!! note "功能优化 :sunflower:"
+
+ * 【网站】添加 CloudFlare DNS 账号时增加部分提示信息。
+ * 【应用商店】安装或升级应用时增加是否强制拉取镜像的选项。
+ * 【应用商店】在制作应用安装包时,镜像字段支持包含参数。
+ * 【数据库】优化数据库连接信息页面的样式。
+ * 【数据库】添加远程 PostgreSQL 数据库页面增加有关超级用户等的提示信息。
+ * 【主机】SSH 配置兼容 prohibit-password。
+ * 【主机】优化文件上传页面已上传文件的显示样式。
+ * 【主机】快速命令列表默认按照名称排序。
+ * 【工具箱】优化缓存清理页面的样式。
+ * 【计划任务】同步服务器任务页面添加有关 NTP 服务器的提示信息。
+ * 【计划任务】创建计划任务时名称不得包含空格。
+ * 【计划任务】优化计划任务列表的样式。
+ * 【计划任务】服务重启后将现有运行中的任务置为错误状态。
+ * 【计划任务】优化报告页面的样式。
+ * 【计划任务】优化计划任务备份列表的打开速度。
+ * 【计划任务】备份账号适配世纪互联版本。
+ * 【面板设置】优化快照恢复页面的样式。
+ * 【面板设置】支持在创建快照时使用本地磁盘。
+ * 【面板设置】支持添加 TLS 类型的 WebDAV 备份账号。
+ * 【面板设置】系统主题默认为跟随系统。
+ * 【面板设置】优化同步快照接口的返回信息。
+ * 【面板设置】优化创建快照页面备份路径的显示样式。
+ * 【系统】统一多行文本输入框的样式。
+ * 【系统】优化部分接口文档描述。
+ * 【系统】增加应用、网站和数据库恢复操作时的确认提示框。
+ * 【系统】在页脚中增加项目导航链接。
+ * 【系统】优化列表页面名称的字体,取消加粗效果。
+ * 【系统】优化部分页面显示样式。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【网站】修复了网站日志清空后页面没有刷新的问题。
+ * 【网站】修复了反向代理网站文本替换不兼容引号的问题。
+ * 【网站】修复了停止 Node.js 运行环境网站后依然可以访问的问题。
+ * 【网站】修复了因 PHP 扩展模板内容过长而无法保存的问题。
+ * 【网站】修复了部分场景下网站目录删除异常的问题。
+ * 【网站】修复了切换运行环境之后 PHP 高级设置依然存在的问题。
+ * 【数据库】修复了修改 Redis 配置文件报错的问题。
+ * 【数据库】修复了 Redis 终端在输入 Ctrl + C 命令时导致浏览器崩溃的问题。
+ * 【容器】修复了镜像清理列表显示不全的问题。
+ * 【主机】修复了删除包含特殊符号文件时报错的问题。
+ * 【主机】修复了由于文件下载路径中包含空格而导致下载失败的问题。
+ * 【工具箱】修复了切换 Fail2ban 禁用方式导致禁用 IP 失败的问题。
+ * 【计划任务】修复了通过计划任务创建快照时在特定场景下可能导致失败的问题。
+ * 【计划任务】修复了应用恢复导致计划任务执行失败的问题。
+ * 【计划任务】修复了容器未启动时无法编辑计划任务的问题。
+ * 【面板设置】修复了部分用户添加 OneDrive 备份账号时失败的情况。
+ * 【系统】修复了由于日志中存在非 UTF-8 编码字符而导致的读取错误的问题。
+ * 【系统】修复了已登录状态下再次访问安全入口仍需重新登录的问题。
+
+!!! note "应用商店 :star2:"
+
+ * 新增 Stirling-PDF。
+ * 新增 Nacos。
+ * 新增 Sentinel Dashboard。
+ * 新增在线安装版本 Palworld Server。
+ * JumpServer 版本升级至 v3.10.3。
+ * DataEase 版本升级至 v2.3.0。
+ * Halo 版本升级至 v2.12.0。
+ * WordPress 版本升级至 v6.4.3。
+ * KubePi 版本升级至 v1.7.0。
+ * uuWAF 版本升级至 v3.0.1。
+ * Draw.io 版本升级至 v23.1.0。
+ * Jenkins 版本升级至 v2.443。
+ * ddns-go 版本升级至 v6.1.0。
+ * Elasticsearch 版本升级至 v8.12.0。
+ * Nginx Proxy Manager 版本升级至 v2.11.1。
+ * Mailserver 版本升级至 v13.3.1。
+ * Roundcube 版本升级至 v1.6.6。
+ * Dockge 版本升级至 v1.4.2。
+ * Komga 版本升级至 v1.10.3。
+ * Elasticsearch 版本升级至 v7.17.17。
+ * Maddy Mail Server 版本升级至 v0.7.1。
+ * Consul 版本升级至 v1.17.2。
+ * Twikoo 版本升级至 v1.6.31。
+ * VS Code 版本升级至 v4.20.1。
+ * Grafana 版本升级至 v10.3.1。
+ * Memos 版本升级至 v0.19.1。
+ * Redpanda Console 版本升级至 v2.4.0。
+ * Material for MkDocs 版本升级至 v9.5.6。
+ * Domain Admin 版本升级至 v1.6.5。
+ * Metabase 版本升级至 v0.48.4。
+ * Koishi 版本升级至 v1.13.7。
+ * Umami 版本升级至 v2.9.0。
+ * Synapse 版本升级至 v1.100.0。
+ * ClickHouse 版本升级至 24.1.1。
+ * Bitwarden 版本升级至 v1.30.3。
+ * Wiki.js 版本升级至 v2.5.301。
+ * MeiliSearch 版本升级至 v1.6.1。
+ * Nextcloud 版本升级至 v28.0.2。
+ * EMQX 版本升级至 v5.5.0。
+ * Redpanda Console 支持选择 Kafka 服务。
+ * OpenLiteSpeed 移除 logging。
+ * Wiki.js 支持选择 PostgreSQL 数据库。
+ * Umami 支持选择 PostgreSQL 数据库。
+ * Typecho 兼容 PostgreSQL 数据库。
+
+### v1.9.4
+
+2024年01月15日
+
+!!! note "功能优化 :sunflower:"
+
+ * 【容器】优化容器列表页面以适应移动端。
+ * 【工具箱】优化设置 hosts 页面的提示信息。
+ * 【计划任务】优化计划任务保存份数的最大限制。
+ * 【面板设置】优化添加 WebDav 备份账号的逻辑。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【网站】修复了创建 PHP 运行环境后切换版本时无法正常选择模板的问题。
+ * 【主机】修复了 zip 压缩前后文件大小不变的问题。
+ * 【面板设置】修复了备份账号中无法编辑服务器磁盘路径的问题。
+ * 【面板设置】修复了因校验异常而导致无法正常添加 WebDav 备份账号的问题。
+
+!!! note "应用商店 :star2:"
+
+ * uuWAF 版本升级至 v2.8.0。
+ * ddns-go 版本升级至 v6.0.2。
+ * PGAdmin4 版本升级至 v8.2。
+ * Metabase 版本升级至 v0.48.3。
+ * Komga 版本升级至 v1.10.1。
+ * Twikoo 版本升级至 v1.6.30。
+
+### v1.9.3
+
+2024年01月11日
+
+!!! note "新增功能 :star2:"
+
+ * 【网站】PHP 运行环境页面增加扩展模版。
+ * 【网站】OpenResty 状态栏增加清除反向代理缓存功能。
+ * 【数据库】新增 PostgreSQL 数据库管理功能。
+ * 【容器】列表增加与容器相关联的网站和应用资源。
+
+!!! note "功能优化 :sunflower:"
+
+ * 【网站】创建网站时支持输入中文域名。
+ * 【应用商店】支持根据应用名称和描述信息进行搜索。
+ * 【应用商店】Halo、Gitea 支持选择 PostgreSQL 数据库。
+ * 【应用商店】phpMyAdmin 隐藏部分系统数据库。
+ * 【数据库】同步服务器数据库信息时不再创建关联用户。
+ * 【容器】支持用户选择是否展示应用商店容器。
+ * 【容器】优化容器监控请求频率。
+ * 【主机】自动清理压缩失败的 ZIP 文件。
+ * 【工具箱】适配 Fail2ban v0.10.2 版本。
+ * 【计划任务】支持备份 PostgreSQL 数据库。
+ * 【系统】优化部分校验的提示信息。
+ * 【系统】更新系统中所使用的 IP 地址库。
+ * 【系统】添加类型转换安全检查。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【网站】修复了证书申请界面复制按钮在复制内容时出现的错误。
+ * 【网站】修复了因网站文件层级过多而导致的授权超时问题。
+ * 【网站】修复了反向代理网站在开启 HTTPS 后 HSTS 配置失效的问题。
+ * 【网站】修复了部分场景下申请证书超时的问题。
+ * 【数据库】修复了 MySQL root 密码输入框在部分场景下出现换行问题。
+ * 【容器】修复了镜像清理仅显示当前页中未使用镜像的问题。
+ * 【主机】修复了文件列表跳转每页条数限制不生效的问题。
+ * 【工具箱】修复了工具箱中 hosts 解析没有忽略 # 注释的问题。
+ * 【计划任务】修复了网站日志正在写入时可能会导致日志切割失败的问题。
+ * 【日志审计】修复了网站日志页面在网站为空时报错的问题。
+ * 【日志审计】修复了部分场景下网站日志清理日志按钮无法点击的问题。
+ * 【面板设置】修复了部分场景下创建和恢复快照提示 .db-wal 等事务文件被删除的问题。
+ * 【面板设置】修复了关闭面板 SSL 异常的问题。
+ * 【系统】修复了部分页面因右侧抽屉内容过多而导致显示不完整的问题。
+
+!!! note "应用商店 :star2:"
+
+ * 新增 One API。
+ * 新增 Dockge。
+ * 添加 Twikoo。
+ * DataEase 版本升级至 v2.2.0。
+ * Alist 版本升级至 v3.30.0。
+ * uuWAF 版本升级至 v2.7.0。
+ * IT-Tools 版本升级至 2023.12.21。
+ * ddns-go 版本升级至 v5.7.1。
+ * Redis 版本升级至 v7.2.4。
+ * Jenkins 版本升级至 v2.440。
+ * MinIO 版本升级至 2024-01-05。
+ * Flarum 版本升级至 v1.8.3。
+ * Audiobookshelf 版本升级至 v2.7.1。
+ * OpenLiteSpeed 版本升级至 v1.7.19。
+ * File Browser 版本升级至 v2.27.0。
+ * Memos 版本升级至 v0.18.2。
+ * Mailserver 版本升级至 v13.2.0。
+ * ClickHouse 版本升级至 v23.12.2。
+ * EMQX 版本升级至 v5.4.1。
+ * Draw.io 版本升级至 v22.1.18。
+ * Nexus Repository 版本升级至 v3.64.0。
+ * Metabase 版本升级至 v0.48.2。
+ * RabbitMQ 版本升级至 v3.12.12。
+ * MongoDB 版本升级至 v7.0.5。
+
+### v1.9.2
+
+2023年12月20日
+
+!!! note "功能优化 :sunflower:"
+
+ * 【网站】同一个邮箱可用于多种不同类型的 ACME 账号。
+ * 【网站】优化网站证书的部分提示信息。
+ * 【容器】更改镜像标签时,允许删除与该镜像 ID 相关的其他标签。
+ * 【容器】优化容器升级逻辑。
+ * 【容器】在容器页面不支持更改已安装应用的容器名称。
+ * 【主机】防火墙增加重启选项。
+ * 【主机】SSH 可以设置同时监听 IPv4 和 IPv6 地址。
+ * 【主机】优化主机终端搜索样式和显示条目。
+ * 【工具箱】增加部分工具箱操作的超时时间。
+ * 【面板设置】面板别名支持设置中文和部分特殊字符。
+ * 【系统】优化部分界面滚动条的样式。
+ * 【系统】优化系统中文本域换行符的验证逻辑。
+ * 【系统】调整主菜单排列顺序。
+
+!!! note "问题修复 :palm_tree:"
+
+ * 【网站】修复了自签名证书导入机构根证书后仍显示不安全的问题。
+ * 【网站】修复了同名网站备份恢复功能异常的问题。
+ * 【主机】修复了部分文件类型上传失败的问题。
+ * 【主机】修复了 SSH 登录日志未能记录非系统用户登录失败状态的问题。
+ * 【主机】修复了暗黑模式下主机编辑页面主机地址显示异常的问题。
+ * 【系统】修复了因本地备份文件删除而导致备份列表读取错误的问题。
+
+!!! note "应用商店 :star2:"
+
+ * Memos 版本升级至 v0.18.1。
+ * frp 版本升级至 v0.53.0。
+ * Jenkins 版本升级至 v2.437。
+ * SFTPGo 版本升级至 v2.5.6。
+ * Draw.io 版本升级至 v22.1.11。
+ * PGAdmin4 版本升级至 v8.1。
+ * Elasticsearch 版本升级至 v7.17.16。
+ * Elasticsearch 版本升级至 v8.11.3。
+ * Consul 版本升级至 v1.17.1。
+ * Metabase 版本升级至 v0.48.0。
+ * ddns-go 版本升级至 v5.6.7。
+ * Komga 版本升级至 v1.9.2。
+ * Grafana 版本升级至 v10.2.3。
+
+
+### v1.9.1
+
+2023年12月14日
+
+!!! note "功能优化 :sunflower:"
+
+ - 【主机】远程文件下载功能添加可选择忽略不受信任证书的选项。
+ - 【工具箱】增加了部分执行命令的超时时间。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【应用商店】修复了部分已安装应用因特殊版本号而提示升级的问题。
+ - 【容器】修复了创建容器时因拉取需要认证的仓库镜像而导致失败的问题。
+ - 【主机】修复了文件夹选择控件不能选择隐藏文件夹的问题。
+ - 【工具箱】修复了失败状态下无法编辑 Fail2ban 配置的问题。
+ - 【日志审计】修复了部分场景下 SSH 登录日志解析错误的问题。
+
+!!! note "应用商店 :star2:"
+
+ - Koishi 版本升级至 v1.13.2。
+ - MeiliSearch 版本升级至 v1.5.1。
+ - ClickHouse 版本升级至 v23.11.2。
+
+### v1.9.0
+
+2023年12月13日
+
+!!! note "新增功能 :star2:"
+
+ - 【概览】概览页状态栏增加 Swap 分区监控。
+ - 【网站】增加多个 DNS 服务商。
+ - 【网站】Acme 账号增加 ZeroSSL、BuyPass 和 Google Cloud。
+ - 【网站】支持导入 IP 证书。
+ - 【网站】支持申请 ECC 类型证书。
+ - 【网站】增加创建自签名证书功能。
+ - 【网站】增加证书推送到本地目录功能。
+ - 【网站】增加批量删除证书功能。
+ - 【网站】增加手动创建证书更新功能。
+ - 【网站】增加证书下载功能。
+ - 【网站】证书支持设置备注信息。
+ - 【网站】申请证书页面支持从网站列表选取域名。
+ - 【网站】支持查看证书申请过程日志。
+ - 【网站】创建 PHP 运行环境时支持第三方商店应用。
+ - 【网站】增加 OpenResty 重载功能。
+ - 【网站】支持创建相同域名不同端口网站。
+ - 【网站】网站列表支持根据状态排序。
+ - 【应用商店】应用升级页面版本列表支持排序。
+ - 【应用商店】应用列表增加是否显示本地应用。
+ - 【应用商店】应用安装增加 IPV6 地址端口监听功能。
+ - 【数据库】MySQL 数据库管理支持跳转到 Adminer 应用。
+ - 【数据库】添加 Mysql 远程数据库时支持设置 SSL。
+ - 【容器】容器配置页面增加 IPv6 相关配置。
+ - 【容器】创建容器时支持选择是否开启特权模式。
+ - 【容器】支持自定义 .sock 文件路径。
+ - 【主机】支持同时拖拽上传文件和文件夹。
+ - 【主机】增加是否开启文件回收站功能。
+ - 【主机】文件编辑器增加换行功能。
+ - 【工具箱】增加主机工具箱管理功能。
+ - 【工具箱】增加 Fail2Ban 管理功能。
+ - 【工具箱】增加 Swap 管理功能。
+ - 【面板设置】增加面板主题跟随系统自动切换功能。
+ - 【面板设置】SSL 设置支持选择本地证书。
+ - 【面板设置】备份账号增加 WebDAV。
+ - 【系统】1pctl 命令行工具支持修改面板信息。
+ - 【系统】备份列表页展示备份文件大小。
+
+!!! note "功能优化 :sunflower:"
+
+ - 【网站】优化证书申请流程。
+ - 【网站】PHP 网站设置页面增加 pathinfo 相关配置。
+ - 【网站】优化 PHP 运行环境日志显示。
+ - 【网站】创建 CloudFlare DNS 证书修改为使用 Token。
+ - 【应用商店】应用升级界面增加应用官网等相关链接。
+ - 【应用商店】已安装应用页面可查看应用详情。
+ - 【应用商店】应用依赖 MongoDB 和 MinIO 时自动回显用户名和密码。
+ - 【应用商店】优化应用升级逻辑。
+ - 【应用商店】优化更新应用商店请求超时逻辑。
+ - 【数据库】创建数据库时自动填充用户名。
+ - 【容器】容器端口跳转功能增加 IPv4、IPv6 判断。
+ - 【容器】优化容器列表端口展示样式。
+ - 【容器】优化容器名称规则提示信息。
+ - 【容器】修改编排功能增加失败回滚机制。
+ - 【计划任务】优化备份所有数据库时下载备份文件的提示信息。
+ - 【主机】优化主机测试连接功能逻辑。
+ - 【主机】优化 zip 文件解、压缩逻辑。
+ - 【主机】远程下载文件时忽略不可信证书。
+ - 【工具箱】缓存清理功能迁移至工具箱菜单。
+ - 【面板设置】面板证书自动续签增加重启提示信息。
+ - 【系统】优化系统中未安装提示信息的快速跳转按钮样式。
+ - 【系统】优化部分可编辑表格样式。
+ - 【系统】优化复制按钮组件。
+ - 【系统】增加 Yii 2.0 框架的重写规则。
+ - 【系统】部分日志页面实现滚动更新。
+ - 【系统】增加部分表单校验。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【网站】修复了添加 User-Agent 过滤失败的问题。
+ - 【网站】修复了非 80 端口网站域名快速跳转地址错误的问题。
+ - 【容器】修复了容器编辑时删除暴露端口 IP 不生效的问题。
+ - 【容器】修复了容器镜像 Tag 为空导致升级失败的问题。
+ - 【容器】修复了存储卷创建时间加载错误的问题。
+ - 【容器】修复了删除已使用状态的镜像后导致镜像标签为空的问题。
+ - 【主机】修复了上传小文件未展示进度的问题。
+ - 【主机】修复了部分场景下删除文件报错的问题。
+ - 【主机】修复了手动删除目标文件后导致后续删除操作报错的问题。
+ - 【工具箱】修复了编辑进程守护名称、进程数量报错的问题。
+ - 【面板设置】修复了面板证书续期后未同步的问题。
+ - 【系统】修复了部分场景下清空搜索框内容会导致浏览器抖动问题。
+
+!!! note "应用商店 :star2:"
+
+ - 新增 Umami。
+ - 新增 DataEase v2。
+ - 新增 ChatGPT-Next-Web。
+ - 新增 filebrowser。
+ - 新增 Elasticsearch。
+ - 新增 Consul。
+ - 新增 Prometheus。
+ - 新增 Grafana。
+ - 新增 Koishi。
+ - 新增 FileCodeBox。
+ - Gitea 版本升级至 v1.21.2。
+ - Jenkins 版本升级至 v2.436。
+ - WordPress 版本升级至 v6.4.2。
+ - Nexus Repository 版本升级至 v3.63.0。
+ - Portainer-CE 版本升级至 v2.19.4。
+ - Komga 版本升级至 v1.8.4 - autoclosed。
+ - Draw.io 版本升级至 v22.1.8。
+ - Redpanda Console 版本升级至 v2.3.8。
+ - ClickHouse 版本升级至 v23.11.1。
+ - Kafka 版本升级至 v3.6.1。
+ - Tailchat 版本升级至 v1.10.0。
+ - Memos 版本升级至 v0.18.0。
+ - Uptime Kuma 版本升级至 v1.23.10。
+ - Material for MkDocs 版本升级至 v9.5.2。
+ - AdGuardHome 版本升级至 v0.107.43。
+ - Nextcloud 版本升级至 28.0.0。
+ - Synapse 版本升级至 v1.98.0。
+
+### v1.8.5
+
+2023年11月29日
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【概览】修复了概览页偶发出现磁盘显示不完整和顺序不固定的问题。
+
+### v1.8.4
+
+2023年11月28日
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【概览】修复了由于部分磁盘无法访问而导致概览页加载失败的问题。
+ - 【网站】修复了网站创建 404 重定向提示重定向次数过多的问题。
+
+!!! note "应用商店 :star2:"
+
+ - 禅道版本升级至 v18.9。
+ - AList 版本升级至 v3.29.1。
+ - Uptime Kuma 版本升级至 v1.23.7。
+ - Draw.io 版本升级至 v22.1.4。
+ - PGAdmin4 版本升级至 8.0。
+ - Nextcloud 版本升级至 v27.1.4。
+ - ClickHouse 版本升级至 v23.10.5。
+ - Domain Admin 版本升级至 v1.5.33。
+ - Material for MkDocs 版本升级至 v9.4.14。
+ - Audiobookshelf 版本升级至 v2.6.0。
+ - Komga 版本升级至 v1.8.0。
+ - Mailserver 版本升级至 13.0.0。
+
+### v1.8.3
+
+2023年11月23日
+
+!!! note "功能优化 :sunflower:"
+
+ - 【数据库】MySQL 本地数据库进行备份与还原操作时,字符编码保持一致。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【网站】修复了部分场景下网站设置会提示服务器内部错误的问题。
+ - 【主机】修复了再次打开文件权限页面显示的是缓存数值的问题。
+ - 【容器】修复了部分场景下镜像仓库编辑失败的问题。
+ - 【系统】修复了启用两步验证后,输入令牌立即按回车键会导致菜单无法加载的问题。
+
+### v1.8.2
+
+2023年11月13日
+
+!!! note "功能优化 :sunflower:"
+
+ - 【概览】概览页重启操作增加确认信息。
+ - 【概览】优化概览页中重启功能按钮的样式。
+ - 【容器】优化清理容器镜像时的弹框提示信息。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【网站】修复了设置网站密码访问异常的问题。
+ - 【网站】修复了 Openresty 性能调整保存报错的问题。
+ - 【容器】修复了针对容器的任何操作都提示删除成功的问题。
+ - 【主机】修复了多文件上传过程中可能导致文件列表丢失的问题。
+
+!!! note "应用商店 :star2:"
+
+ - OpenResty 版本升级至 v1.21.4.3。
+ - SFTPGo 版本升级至 v2.5.5。
+ - ClickHouse 版本升级至 v23.10.3。
+ - Portainer-CE 版本升级至 v2.19.2。
+ - MinIO 版本升级至 RELEASE.2023-11-11T08-14-41Z。
+ - Nginx Proxy Manager 版本升级至 github-pr-3281。
+
+### v1.8.1
+
+2023年11月10日
+
+!!! note "功能优化 :sunflower:"
+
+ - 【系统】优化证书续签、文件管理等操作的超时时间。
+ - 【系统】增加控制台静态资源 /assets/ 浏览器缓存。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【网站】修复了部分场景下网站设置保存报错的问题。
+ - 【网站】修复了反向代理类型网站设置缓存时间选择年报错的问题。
+ - 【网站】修复了部分场景下设置默认站点失败的问题。
+ - 【应用商店】修复了本地应用备份恢复报错的问题。
+ - 【主机】修复了文件名称带有空格时复制粘贴操作失败的问题。
+ - 【日志审计】修复了检测文件是否存在的接口记录到操作日志列表的问题。
+
+!!! note "应用商店 :star2:"
+
+ - ClickHouse 版本升级至 v23.10.2。
+ - Draw.io 版本升级至 v22.1.0。
+ - Komga 版本升级至 v1.7.2。
+
+### v1.8.0
+
+2023年11月08日
+
+!!! note "新增功能 :star2:"
+
+ - 【概览】增加重启服务器和重启面板功能。
+ - 【网站】支持查看创建 PHP 运行环境日志。
+ - 【网站】证书管理页面增加上传证书功能。
+ - 【网站】创建网站时支持批量添加域名。
+ - 【网站】添加 Node.js 运行环境时支持自定义启动命令。
+ - 【网站】添加 Node.js 运行环境时支持设置多端口。
+ - 【容器】增加容器状态筛选功能。
+ - 【计划任务】增加备份日志类型计划任务。
+ - 【计划任务】增加缓存清理类型计划任务。
+ - 【主机】增加文件回收站功能。
+ - 【主机】增加文件收藏夹功能。
+ - 【主机】增加文件终端功能。
+ - 【主机】增加上传文件夹功能。
+ - 【主机】增加文件列表排序功能。
+ - 【主机】增加批量修改文件权限功能。
+ - 【主机】提供 SSH 服务的开机自启选项。
+ - 【主机】增加主机快速命令分组功能。
+ - 【主机】修改 SSH 端口时自动添加防火墙端口规则。
+ - 【面板设置】支持设置面板监听地址。
+ - 【系统】1pctl 命令行工具支持切换监听地址。
+
+!!! note "功能优化 :sunflower:"
+
+ - 【概览】服务升级、重启等操作时取消前端定时请求。
+ - 【网站】网站 WAF 增加 user-agent 过滤。
+ - 【网站】创建网站时增加其他域名的端口校验。
+ - 【网站】延长证书申请超时时间。
+ - 【网站】添加 Node.js 运行环境时增加外部映射端口校验。
+ - 【网站】创建 PHP 运行环境网站时持久化扩展目录。
+ - 【应用商店】优化应用商店同步逻辑。
+ - 【应用商店】安装 host 网络模式应用时增加部分提示信息。
+ - 【容器】缓存容器列表刷新频率。
+ - 【计划任务】优化部分页面样式。
+ - 【主机】优化文件列表部分样式。
+ - 【主机】文件复制、粘贴操作时支持修改文件及文件夹名称。
+ - 【主机】添加主机时支持 IPv6 地址。
+ - 【主机】优化进程守护判断 service 文件是否存在的逻辑。
+ - 【日志审计】系统日志文件取消压缩。
+ - 【面板设置】腾讯 COS 备份账号支持分片上传大文件。
+ - 【面板设置】新增备份账号时增加文件上传测试。
+ - 【系统】系统安装成功后显示局域网和公网 IP。
+ - 【系统】重新执行安装程序避免重复下载安装包。
+ - 【系统】优化两步验证登录方式。
+ - 【系统】登录接口增加参数校验。
+ - 【系统】统一系统删除弹框样式和提示信息。
+ - 【系统】服务启动时自动同步服务器时间。
+ - 【系统】优化部分接口报错和页面显示样式。
+ - 【系统】统一修改部分接口参数校验。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【概览】修复了概览页样式不统一的问题。
+ - 【网站】修复了部分场景下创建网站提示端口被占用的问题。
+ - 【网站】修复了部分场景下可以创建同名网站的问题。
+ - 【网站】修复了网站域名可以重复添加的问题。
+ - 【网站】修复了 PHP 网站切换版本导致 serviceName 变更的问题。
+ - 【网站】修复了编辑 PHP 运行环境时版本显示错误的问题。
+ - 【网站】修复了切换 PHP 运行环境版本时可以选择 Node.js 的问题。
+ - 【网站】修复了反向代理网站后端代理地址为域名时创建失败的问题。
+ - 【网站】修复了 PHP 5.6 运行环境安装 redis 扩展失败的问题。
+ - 【数据库】修复了由于未设置默认字符集导致数据库导入备份失败的问题。
+ - 【容器】修复了部分容器端口解析失败的问题。
+ - 【容器】修复了查看容器日志后产生僵尸进程的问题。
+ - 【主机】修复了 tar 文件解压失败的问题。
+ - 【主机】修复了部分场景下 zip 文件解压缩失败的问题。
+ - 【主机】修复了 IPv6 环境下 firewalld 防火墙规则不生效的问题。
+ - 【主机】修复了部分场景下移动文件失败的问题。
+ - 【主机】修复了暗色主题时文件导航栏显示异常问题。
+ - 【主机】修复了 UFW 防火墙规则为空时创建规则失败的问题。
+ - 【主机】修复了部分场景下 UFW 防火墙启用失败的问题。
+ - 【日志审计】修复了网站日志切换时显示错误的问题。
+ - 【系统】修复了文件夹中存在 .sock 套接字导致压缩失败的问题。
+ - 【系统】修复了部分场景下服务重启会导致运行环境状态异常的问题。
+
+!!! note "应用商店 :star2:"
+
+ - 新增 Answer。
+ - 新增 Audiobookshelf。
+ - 新增 Calibre-Web。
+ - 新增 Changedetection.io。
+ - 新增 focalboard。
+ - 新增 Heimdall。
+ - 新增 IT-Tools。
+ - 新增 OpenLiteSpeed。
+ - 新增 YOURLS。
+ - 新增 YesPlayMusic。
+ - 新增 Navidrome。
+ - 新增 ClickHouse。
+ - 新增 Redpanda Console。
+ - 新增 Komga。
+ - 新增 Mailserver。
+ - 新增 Maddy Mail Server。
+ - 新增 Material for MkDocs。
+ - 新增 Roundcube。
+ - DataEase 版本升级至 v1.18.12。
+ - Halo 版本升级至 v2.10.2。
+ - Kodbox 版本升级至 v1.4505。
+ - Redis 版本升级至 v7.2.3。
+ - ddns-go 版本升级至 v5.6.6。
+ - Jellyfin 版本升级至 v10.8.12。
+ - Bitwarden 版本升级至 v1.30.0。
+ - Tailchat 版本升级至 v1.9.4。
+ - Jenkins 版本升级至 v2.431。
+ - Nexus Repository 版本升级至 v3.62.0。
+ - Metabase 版本升级至 v0.47.7。
+ - WordPress 版本升级至 v6.4.0。
+
+### v1.7.4
+
+2023年10月26日
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【网站】修复了部分 PHP 运行环境安装部分依赖失败的问题。
+ - 【数据库】修复了部分远程数据库同步异常的问题。
+ - 【计划任务】修复了部分类型计划任务执行失败的问题。
+ - 【主机】修复了终端页面导航栏显示异常的问题。
+ - 【系统】修复了部分页面分页缓存加载错误的问题。
+
+!!! note "应用商店 :star2:"
+
+ - frp 版本升级至 v0.52.3。
+ - Jenkins 版本升级至 v2.429。
+ - Draw.io 版本升级至 v22.0.8。
+ - Synapse 版本升级至 v1.95.0。
+
+### v1.7.3
+
+2023年10月23日
+
+!!! note "功能优化 :sunflower:"
+
+ - 【计划任务】优化报告页面左侧导航栏样式。
+ - 【计划任务】优化 Shell 脚本类型计划任务执行后的错误显示。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【网站】修复了部分网站 SSL 协议设置 TLS 1.3 不生效的问题。
+ - 【数据库】修复了当存在多个 MySQL 数据库时修改端口未生效的问题。
+ - 【容器】修复了创建容器时,获取 Entrypoint 默认值失败导致无法创建的问题。
+ - 【主机】修复了部分场景下 SSH 日志识别错误的问题。
+ - 【面板设置】修复了 E5 账户授权码格式校验失败的问题。
+
+!!! note "应用商店 :star2:"
+
+ - MeiliSearch 版本升级至 v1.4.2。
+ - PGAdmin4 版本升级至 v7.8。
+ - Memcached 版本升级至 v1.6.22。
+ - Metabase 版本升级至 v0.47.5。
+ - Memos 版本升级至 v0.16.1。
+ - JumpServer 版本升级至 v3.8.0。
+ - VS Code 版本升级至 v4.18.0。
+ - Draw.io 版本升级至 v22.0.6。
+ - MinIO 版本升级至 RELEASE.2023-10-16。
+ - Domain Admin 版本升级至 v1.5.25。
+
+### v1.7.2
+
+2023年10月22日
+
+!!! note "功能优化 :sunflower:"
+
+ - 【数据库】同步 MySQL 数据库时,忽略 recycle_bin 数据库。
+ - 【面板设置】优化 OneDrive 备份账号授权码的格式校验。
+ - 【系统】对面板用户名和密码进行空格等校验的优化。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【容器】修复了创建 host 网络模式容器时导致失败的问题。
+ - 【容器】修复了部分场景下无法正确编辑容器内存限额的问题。
+ - 【主机】修复了 Debian 12 服务器 SSH 登录日志显示异常的问题。
+
+### v1.7.1
+
+2023年10月15日
+
+!!! note "功能优化 :sunflower:"
+
+ - 【容器】优化容器编辑页面部分提示信息。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【网站】修复了证书详情页面其他域名一直为空的问题。
+ - 【网站】修复了部分反向代理网站在 Firefox 浏览器中打开失败的问题。
+ - 【容器】修复了部分容器无法打开编辑页面的问题。
+
+!!! note "应用商店 :star2:"
+
+ - JumpServer 版本升级至 v3.7.2。
+ - WordPress 版本升级至 v6.3.2。
+ - frps 版本升级至 v0.52.1。
+ - frpc 版本升级至 v0.52.1。
+ - MeiliSearch 版本升级至 v1.4.1。
+
+### v1.7.0
+
+2023年10月12日
+
+!!! note "新增功能 :star2:"
+
+ - 【网站】增加 Node.js 运行环境。
+ - 【应用商店】应用安装时支持选择远程数据库。
+ - 【面板设置】增加系统缓存清理功能。
+
+!!! note "功能优化 :sunflower:"
+
+ - 【网站】网站主域名支持设置端口。
+ - 【网站】反向代理网站配置默认增加协议转发。
+ - 【网站】修改网站日志的关闭参数。
+ - 【网站】优化设置页面日志按钮样式。
+ - 【网站】优化运行环境下拉列表样式。
+ - 【应用商店】已安装应用列表支持查看应用日志。
+ - 【应用商店】调整部分已安装应用按钮位置。
+ - 【应用商店】增加分类标签排序。
+ - 【应用商店】应用列表顶部增加分页显示。
+ - 【应用商店】同步所有应用状态增加提示信息。
+ - 【数据库】支持复制并查看详细的 Redis 外部连接地址。
+ - 【数据库】统一 MySQL 数据库设置页面样式。
+ - 【数据库】MySQL 部分性能参数区分版本显示。
+ - 【数据库】远程数据库增加删除提示。
+ - 【容器】修改创建容器页面选择挂载卷时的交互方式。
+ - 【容器】容器升级操作时支持忽略版本比较。
+ - 【容器】容器镜像列表增加是否使用标签。
+ - 【容器】容器镜像列表增加详情显示。
+ - 【容器】容器列表资源使用率增加详情显示。
+ - 【容器】容器支持自定义控制台交互方式。
+ - 【容器】优化删除编排弹出框提示信息。
+ - 【容器】优化容器名称校验规则。
+ - 【主机】防火墙范围端口规则显示占用详情。
+ - 【日志审计】SSH 登录日志增加详情显示。
+ - 【日志审计】1Panel 系统日志支持根据日期筛选,并支持追踪读取。
+ - 【面板设置】支持设置服务器默认网卡。
+ - 【面板设置】系统授权 IP 支持 IP 段。
+ - 【面板设置】两步验证区分操作系统并支持设置标题。
+ - 【面板设置】优化暗色模式下面板设置按钮样式。
+ - 【系统】系统重启成功后同步应用商店应用。
+ - 【系统】优化监控采集方式。
+ - 【系统】统一部分页面全屏按钮样式。
+ - 【系统】缓存部分页面分页条数。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【网站】修复了域名暂停或者移除后无法重新创建该域名的问题。
+ - 【网站】修复了相同域名和端口可以重复添加的问题。
+ - 【网站】修复了 HTTP 模式下证书会保存部分错误数据的问题。
+ - 【应用商店】修复了强制删除 Openresty 后没有同步删除 PHP 应用的问题。
+ - 【容器】修复了编辑存储卷失败导致容器丢失的问题。
+ - 【容器】修复了编辑容器失败时未更新容器 ID 的问题。
+ - 【主机】修复了部分场景下系统防火墙未显示具体应用占用情况的问题。
+ - 【主机】修复了 UFW 防火墙并发导致的批量操作失败的问题。
+ - 【主机】修复了部分操作系统添加防火墙端口备注时不生效的问题。
+ - 【系统】修复了演示环境部分功能不能正常查看的问题。
+
+!!! note "应用商店 :star2:"
+
+ - 新增 Metabase。
+ - 新增 ShowDoc。
+ - JumpServer 版本升级至 v3.7.1。
+ - Halo 版本升级至 v2.10.0。
+ - Jenkins 版本升级至 v2.427。
+ - Alist 版本升级至 v3.28.0。
+ - PGAdmin4 版本升级至 v7.7。
+ - Jellyfin 版本升级至 v10.8.11。
+ - Tailchat 版本升级至 v1.9.1。
+ - RabbitMQ 版本升级至 v3.12.6。
+ - 青龙 版本升级至 v2.16.3。
+ - MeiliSearch 版本升级至 v1.4.0。
+ - EMQX 版本升级至 v5.3.0。
+ - VS Code 版本升级至 v4.17.1。
+ - MongoDB 版本升级至 v7.0.2。
+ - Docker Registry 版本升级至 v2.8.3。
+ - Nexus Repository 版本升级至 v3.61.0。
+ - Gitea 版本升级至 v1.20.5。
+ - Memos 版本升级至 v0.16.0。
+ - Cloudreve 版本升级至 v3.8.3。
+ - Draw.io 版本升级至 v22.0.3。
+ - Nextcloud 版本升级至 v27.1.2。
+ - Kodbox 版本升级至 v1.4405。
+ - Uptime Kuma 版本升级至 v1.23.3。
+ - ddns-go 版本升级至 v5.6.3。
+ - Synapse 版本升级至 v1.94.0。
+ - AdGuardHome 版本升级至 v0.107.39。
+
+### v1.6.2
+
+2023年09月27日
+
+!!! note "功能优化 :sunflower:"
+
+ - 【网站】创建 PHP 运行环境支持自定义扩展源。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【网站】修复了网站设置 PHP 源文之后没有立即生效的问题。
+ - 【容器】修复了部分容器创建失败的问题。
+ - 【主机】修复了守护进程停止后一直处于同步状态的问题。
+
+### v1.6.1
+
+2023年09月16日
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【概览】修复了推荐应用列表可以安装受限制应用的问题。
+ - 【网站】修复了网站日志下载不是全部记录的问题。
+ - 【应用商店】修复了部分场景下恢复应用导致数据库备份文件丢失的问题。
+ - 【数据库】修复了部分场景下数据库列表页样式错乱的问题。
+ - 【数据库】修复了调整 MySQL 数据库性能导致服务重启的问题。
+ - 【容器】修复了容器界面部分提示信息和具体操作不一致的问题。
+ - 【主机】修复了部分场景下修改 UFW 防火墙备注信息无效的问题。
+ - 【系统】修复了暗色模式下导航样式冲突的问题。
+ - 【系统】修复了由于数据冲突导致系统升级失败的问题。
+
+### v1.6.0
+
+2023年09月14日
+
+!!! note "新增功能 :star2:"
+
+ - 【网站】支持不同域名使用同一个端口。
+ - 【网站】网站目录支持设置三级运行目录。
+ - 【网站】更新 PHP 运行环境后,自动重新配置该运行环境关联应用。
+ - 【应用商店】安装应用时支持选择本地 MySQL 或 MariaDB 数据库。
+ - 【应用商店】在执行安装、升级或卸载操作之前,支持执行自定义脚本。
+ - 【应用商店】安装 OpenResty 时支持非 80 和 443 端口。
+ - 【应用商店】在涉及到关联网站的情况下,OpenResty 提供了强制删除的功能。
+ - 【数据库】MySQL 数据库列表支持添加 MariaDB 数据库。
+ - 【数据库】支持配置多个 MySQL 本地数据库。
+ - 【主机】防火墙端口规则和 IP 规则,支持设置描述信息。
+ - 【计划任务】支持定时备份应用商店已安装应用。
+ - 【计划任务】支持定时备份系统快照。
+ - 【面板设置】重构快照功能,消除在生成快照期间对系统全局 loading 的影响。
+ - 【系统】1pctl 命令行工具增加回滚功能。
+
+!!! note "功能优化 :sunflower:"
+
+ - 【概览】支持自定义是否显示安全入口提示信息。
+ - 【网站】日志读取功能取消文件大小限制,支持读取超过 10MB 的日志文件。
+ - 【网站】网站设置页面增加网站目录权限校验的提示信息。
+ - 【应用商店】重建应用操作修改为响应式请求。
+ - 【应用商店】应用安装流程优化。
+ - 【应用商店】应用商店全部列表页样式优化。
+ - 【数据库】数据库密码加密存储。
+ - 【数据库】MySQL 页面数据库筛选框增加跳转功能。
+ - 【容器】创建容器表单支持设置 ENTRYPOINT 参数。
+ - 【容器】容器列表增加容器内网络地址列。
+ - 【容器】查看容器日志行数选择框增加所有选项。
+ - 【容器】批量操作时,弹框提示信息增加详情显示。
+ - 【容器】存在连续端口时,显示方式优化。
+ - 【容器】容器列表加载方式优化。
+ - 【容器】移除容器日志中的 ANSI 转义序列。
+ - 【主机】文件删除时的提示信息优化。
+ - 【主机】防火墙列表支持根据状态和策略进行结果筛选。
+ - 【主机】添加、编辑防火墙端口和 IP 规则时,可以输入多个 IP 地址或 IP 地址段。
+ - 【主机】文件列表增加 UID 和 GID 显示。
+ - 【主机】防火墙响应速度优化。
+ - 【面板设置】服务器地址支持设置为空。
+ - 【面板设置】设置按钮样式优化。
+ - 【系统】添加日本语 README 文件。
+ - 【系统】系统消息提示框弹出方式优化。
+ - 【系统】系统弹窗提示文字样式优化。
+ - 【系统】部分页面状态栏样式统一。
+ - 【系统】部分页面按钮样式优化。
+ - 【系统】登录接口增加安全入口的校验。
+ - 【系统】1pctl 获取用户信息命令返回内容优化。
+ - 【系统】系统升级过程中暂停计划任务。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【网站】修复了 PHP 运行环境 5.5.38 版本安装 composer 失败的问题。
+ - 【网站】修复了 PHP 运行环境 7.x 版本安装 pdo_sqlsrv 失败的问题。
+ - 【网站】修复了 PHP 运行环境部分版本构建失败的问题。
+ - 【应用商店】修复了多容器应用升级失败的问题。
+ - 【应用商店】修复了部分场景下应用停止之后不能启动的问题。
+ - 【数据库】修复了 MySQL 数据库同步时,由于存在特殊字符导致同步失败的问题。
+ - 【数据库】修复了 MySQL 8.x 切换数据库访问权限导致创建数据库失败的问题。
+ - 【容器】修复了容器切换端口选项时,仍然进行端口校验的问题。
+ - 【容器】修复了 Docker 低版本无法读取容器日志的问题。
+ - 【主机】修复了 Deepin 操作系统获取 SSH 服务状态异常的问题。
+ - 【主机】修复了守护进程停止之后状态读取异常的问题。
+ - 【主机】修复了文件名带空格时,导致的设置权限失败的问题。
+ - 【系统】修复了部分页面像素不对齐的问题。
+ - 【系统】修复了导航按钮左侧边框显示异常的问题。
+ - 【系统】修复了快照恢复后应用重建无法拉起的问题。
+
+!!! note "应用商店 :star2:"
+
+ - 新增 Drawio。
+ - 新增 Portainer。
+ - Halo 版本升级至 v2.9.1。
+ - DataEase 版本升级至 v1.18.10。
+ - Alist 版本升级至 v3.27.0。
+ - 青龙版本升级至 v2.16.2。
+ - 南墙 Web 应用防火墙版本升级至 v2.6.1。
+ - 禅道版本升级至 v18.7。
+ - Gitea 版本升级至 v1.20.4。
+ - Jenkins 版本升级至 v2.423。
+ - MongoDB 版本升级至 v7.0.1。
+ - Tailchat 版本升级至 v1.8.12。
+ - Bitwarden 版本升级至 v1.29.2。
+ - Redis 版本升级至 v6.2.13。
+ - Redis 版本升级至 v7.2.1。
+ - Nexus Repository 版本升级至 v3.60.0。
+ - ddns-go 版本升级至 v5.6.2。
+ - emqx 版本升级至 v5.2.0。
+ - Synapse 版本升级至 v1.92.1。
+ - Domain Admin 版本升级至 v1.5.23。
+ - AdGuardHome 版本升级至 v0.107.38。
+ - MeiliSearch 版本升级至 v1.3.4。
+
+### v1.5.5
+
+2023年09月01日
+
+!!! note "功能优化 :sunflower:"
+
+ - 【主机】防火墙支持删除 1Panel 系统端口规则。
+ - 【系统】1pctl 命令行工具增加权限相关提示信息。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【概览】修复了进入概览页瞬间获取流量监控数值可能异常的问题。
+ - 【系统】修复了侧边栏收起状态下菜单长度不一致的问题。
+
+### v1.5.4
+
+2023年08月31日
+
+!!! note "功能优化 :sunflower:"
+
+ - 【应用商店】应用商店更新应用列表增加版本控制。
+ - 【容器】允许删除 1Panel 默认创建的容器网络。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【数据库】修复了由于 MySQL root 用户密码存在特殊字符导致无法创建数据库的问题。
+ - 【主机】修复了部分场景下打开进程守护页面报错的问题。
+ - 【主机】修复了解压文件时可能由于父目录不存在导致解压失败的问题。
+ - 【主机】修复了防火墙 IP 规则删除失败的问题。
+
+!!! note "应用商店 :star2:"
+
+ - 新增 uuWAF。
+ - Alist 版本升级至 v3.26.0。
+ - WordPress 版本升级至 v6.3.1。
+ - Jenkins 版本升级至 v2.421。
+ - 禅道版本升级至 v18.6。
+ - 青龙版本升级至 v2.16.1。
+ - PGAdmin4 版本升级至 v7.6。
+ - ddns-go 版本升级至 v5.6.1。
+ - MongoDB 版本升级至 7.0.0。
+ - QianDao 版本升级至 20230821。
+ - Gitea 版本升级至 v1.20.3。
+ - Tailchat 版本升级至 v1.8.11。
+ - Domain Admin 版本升级至 v1.5.21。
+ - emqx 版本升级至 v5.1.6。
+ - MeiliSearch 版本升级至 v1.3.2。
+ - RabbitMQ 版本升级至 v3.12.4。
+ - Uptime Kuma 版本升级至 v1.23.1。
+ - Synapse 版本升级至 v1.91.0。
+
+### v1.5.3
+
+2023年08月22日
+
+!!! note "功能优化 :sunflower:"
+
+ - 【面板设置】服务器地址支持设置为空。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【网站】修复了运行环境网站切换 PHP 版本导致已安装应用消失的问题。
+ - 【数据库】修复了由于数据库用户名超长导致数据同步失败的问题。
+ - 【容器】修复了清空容器日志导致服务器 CPU 占用异常的问题。
+
+### v1.5.2
+
+2023年08月17日
+
+!!! note "功能优化 :sunflower:"
+
+ - 【网站】网站设置重定向列表页样式优化。
+ - 【容器】创建容器编排时日志加载逻辑优化。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【网站】修复了编辑反向代理类型网站时后端地址丢失 path 的问题。
+ - 【数据库】修复了部分场景下同步远程数据库失败的问题。
+ - 【主机】修复了 ufw 防火墙创建多端口规则后删除失败的问题。
+ - 【主机】修复了添加守护进程后会激活原来处于暂停状态的任务的问题。
+ - 【主机】修复了部分场景下守护进程状态一直处于加载中的问题。
+ - 【系统】修复了移动端弹出框会覆盖左侧菜单的问题。
+
+!!! note "应用商店 :star2:"
+
+ - WordPress 版本升级至 v6.3.0。
+ - emqx 版本升级至 v5.1.5。
+ - MeiliSearch 版本升级至 v1.3.1。
+ - PostgreSQL 版本升级至 v15.4。
+ - frp 版本升级至 v0.51.3。
+ - Memos 版本升级至 v0.14.4。
+ - Wiki.js 版本升级至 v2.5.300。
+ - Tailchat 版本升级至 v1.8.9。
+ - Nextcloud 版本升级至 v27.0.2。
+ - MariaDB 版本升级至 v10.11.5。
+ - Kodbox 版本升级至 v1.4104。
+ - Jenkins 版本升级至 v2.419。
+ - Synapse 版本升级至 v1.90.0。
+ - Nexus 版本升级至 v3.59.0。
+ - MongoDB 版本升级至 v6.0.9。
+ - Domain Admin 版本升级至 v1.5.15。
+
+### v1.5.1
+
+2023年08月14日
+
+!!! note "功能优化 :sunflower:"
+
+ - 【数据库】MySQL 远程数据库增加连接性测试。
+ - 【数据库】MySQL 远程数据库地址支持输入域名。
+ - 【数据库】连接信息页面增加复制按钮以及连接地址内容超长时悬浮显示。
+ - 【容器】容器创建页面启动命令提示信息优化。
+ - 【容器】容器终端点击断开按钮后保持页面打开状态。
+ - 【容器】容器清理提示信息优化。
+ - 【主机】守护进程列表增加操作列。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【应用商店】修复了应用升级时由于 docker 镜像拉取失败导致应用服务异常的问题。
+ - 【主机】修复了防火墙页面修改分页条数后偶发的数据丢失问题。
+
+### v1.5.0
+
+2023年08月10日
+
+!!! note "新增功能 :star2:"
+
+ - 【网站】支持 PHP 运行环境类型网站切换版本。
+ - 【网站】支持网站设置重定向。
+ - 【数据库】支持添加 MySQL 远程数据库。
+ - 【主机】增加进程守护管理。
+
+!!! note "功能优化 :sunflower:"
+
+ - 【网站】网站设置 IPv6 功能优化。
+ - 【网站】网站防盗链页面样式优化。
+ - 【网站】网站设置页面添加反向代理时支持用户选择传输协议。
+ - 【网站】编辑 PHP 运行环境后增加关联应用重建的提示信息。
+ - 【应用商店】应用升级时增加备份选项。
+ - 【应用商店】已安装应用列表增加 HTTPS 类型端口的跳转功能。
+ - 【应用商店】全部应用和已安装应用列表页面样式优化。
+ - 【应用商店】应用依赖 Redis 时,创建页面自动填充 Redis 密码。
+ - 【数据库】数据库密码校验规则优化。
+ - 【数据库】数据库连接信息样式优化。
+ - 【容器】容器创建页面部分字段翻译优化。
+ - 【主机】文件列表记录文件浏览器最后一次访问的路径。
+ - 【主机】文件列表页面适配移动端。
+ - 【主机】监控页面调整数据默认采集间隔和保存时间。
+ - 【面板设置】创建系统快照前停止所有定时任务。
+ - 【面板设置】服务器地址支持设置域名。
+ - 【面板设置】备份账号页面部分按钮样式优化。
+ - 【面板设置】创建快照逻辑优化。
+ - 【系统】登录页增加切换语言选项。
+ - 【系统】部分页面样式适配移动端。
+ - 【系统】移除不必要的 SSH Session 连接。
+ - 【系统】部分页面分页排序样式优化。
+ - 【系统】创建抽屉页面不再动态显示名称。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 【网站】修复了部分场景下创建 PHP 运行环境异常的问题。
+ - 【应用商店】修复了应用升级后无法编辑最新配置的问题。
+ - 【应用商店】修复了更新应用列表后可能出现多个同名应用的问题。
+ - 【应用商店】修复了 Cloudreve 升级后数据丢失的问题。
+ - 【应用商店】修复了编辑应用时关闭高级设置之后没有提示端口放开的问题。
+ - 【应用商店】修复了安装应用时数据库密码包含 & $ 等特殊字符时提示错误的问题。
+ - 【数据库】修复了数据库日志监听未刷新的问题。
+ - 【容器】修复了编辑容器时不显示手动挂载的挂载卷的问题。
+ - 【容器】修复了编辑容器时由于端口冲突导致容器被删除的问题。
+ - 【主机】修复了文件压缩时无法选择文件夹的问题。
+ - 【主机】修复了当 SSH 登录日志涉及多个年份时导致数据异常的问题。
+ - 【面板设置】修复了同步快照路径错误的问题。
+ - 【系统】修复了系统安装在根目录时导致升级失败的问题。
+ - 【安全】修复了部分文件接口存在任意文件读取漏洞的问题。
+ - 【安全】修复了部分文件接口存在任意文件下载漏洞的问题。
+ - 【安全】修复了部分文件接口存在任意文件写入漏洞的问题。
+
+!!! note "应用商店 :star2:"
+
+ - 新增 JumpServer。
+ - 新增 SFTPGo。
+ - 新增 PGAdmin4。
+ - 新增 frp。
+ - 新增 Discuz。
+ - 新增 Nextcloud。
+ - 新增 Domain Admin。
+ - 新增 emlog。
+ - 新增 ZFile。
+ - 新增 MeiliSearch。
+ - 新增 ChatGPT Web。
+ - 新增 Home Assistant。
+ - AdGuardHome 版本升级至 v0.107.36。
+ - OpenResty 版本升级至 1.21.4.2-0。
+ - Tailchat 版本升级至 v1.8.8。
+ - 青龙 版本升级至 v2.16.0。
+ - ddns-go 版本升级至 v5.6.0。
+ - Memos 版本升级至 v0.14.3。
+ - Jenkins 版本升级至 v2.418。
+ - Cloudreve 版本升级至 v3.8.2。
+ - Alist 版本升级至 v3.25.1。
+
+### v1.4.3
+
+2023年07月18日
+
+!!! note "功能优化 :sunflower:"
+
+ - 应用商店已安装列表支持分页。
+ - PHP 网站设置页面添加禁用函数时支持输入下划线。
+ - 终端快速命令页面增加使用提示信息。
+ - 监控页面线状图表显示优化。
+ - 概览页面布局优化。
+ - 主机终端本地服务器连接失败时,默认打开添加主机页面。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了通过主机密钥连接终端失败的问题。
+ - 修复了创建容器时,端口信息包含 ipv6 地址导致校验失败的问题。
+ - 修复了添加 IP 规则时存在命令注入的问题。
+
+### v1.4.2
+
+2023年07月14日
+
+!!! note "功能优化 :sunflower:"
+
+ - 监控页面 echart 资源释放逻辑优化。
+ - 暗色主题禁用按钮样式优化。
+ - 部分页面国际化显示优化。
+ - 网站上传备份/恢复逻辑优化。
+ - 系统名称输入框长度限制调整。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了重新启动暂停状态的网站时,运行目录会被重置的问题。
+ - 修复了概览页存在多磁盘时,刷新页面会导致展开状态被重置的问题。
+ - 修复了面板设置域名绑定时无法选择已有 HTTPS 证书的问题。
+ - 修复了部分容器编辑页面无法正常打开的问题。
+ - 修复了部分情况下应用状态显示异常的问题。
+ - 修复了当网站主域名与网站目录不一致时,定时任务切割网站日志失败的问题。
+
+### v1.4.1
+
+2023年07月12日
+
+!!! note "功能优化 :sunflower:"
+
+ - 取消安装 OpenResty 应用时的端口开放提示信息。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了部分场景下系统升级失败的问题。
+ - 修复了网站添加 HTTPS 证书后显示异常的问题。
+
+### v1.4.0
+
+2023年07月12日
+
+!!! note "新增功能 :star2:"
+
+ - 增加主机进程管理功能。
+ - 增加主机 SSH 会话管理功能。
+ - 增加容器编辑功能。
+ - 数据库支持 MySQL 5.6。
+ - 备份账号支持微软 OneDrive。
+ - 增加容器升级功能。
+ - 创建容器时支持设置 CPU 权重。
+ - 主机 SSH 登录日志增加一键屏蔽 ip 功能。
+ - 主机监控增加全局过滤功能。
+ - 两步验证支持设置自定义刷新时间。
+ - 添加 S3、OSS、COS 备份账号时支持选择存储类型。
+ - 支持创建容器类型 Shell 计划任务。
+ - 容器、已安装应用支持点击端口跳转。
+ - 容器、数据库、网站、计划任务列表支持根据名称排序。
+ - 系统语言支持设置中文繁体。
+ - 应用商店增加忽略升级功能。
+ - 网站设置开启 HTTPS 时,支持用户选择本地证书文件。
+ - 创建、编辑容器时,支持自定义网络。
+
+!!! note "功能优化 :sunflower:"
+
+ - 优化容器日志加载方式,支持根据日志显示条数过滤。
+ - 创建、编辑容器时增加 CPU、内存最大限制。
+ - 概览页、主机监控等页面监控单位显示优化。
+ - 监控图表纵坐标数字大小和宽度优化,防止数字过长溢出。
+ - 主机终端点击本地服务器支持打开多个新连接。
+ - 统一右侧抽屉警告或提示信息样式。
+ - 面板操作日志显示优化。
+ - 优化同步快照时名称重复的提示信息。
+ - 集成 Tailwind CSS 响应式设计。
+ - 网站日志切割定时任务执行失败时打印失败原因。
+ - 创建 PHP 运行环境时优先拉取最新镜像版本。
+ - 网站启用 https 增加 http2 配置。
+ - 应用商店安装应用时增加端口未放开的提示信息。
+ - 移除部分重复国际化内容。
+ - 创建 PHP 运行环境页面增加扩展列表提示。
+ - 证书申请超时时间优化。
+ - 主机密码加密存储。
+ - 应用商店安装应用前优先拉取镜像。
+ - 计划任务、容器等页面样式适配移动端。
+ - 网站设置页面选择证书时支持通过 acme 账号过滤。
+ - 文件选择逻辑优化。
+ - 创建应用时增加 CPU 和内存的最大值提示。
+ - 修改 MySQL 数据库长度限制。
+ - 随机密码按钮样式统一。
+ - 忽略监控采集的异常数据。
+ - 系统消息弹出框样式统一调整。
+ - 应用同步逻辑优化。
+ - 容器列表调整为异步加载。
+ - 增加终端连接断开时的提示信息。
+ - 计划任务报告页面显示优化。
+ - 日志审计菜单支持网站日志下载和追踪。
+ - 创建容器页面增加强制拉取镜像选项。
+ - 部分页面暗色模式主体样式优化。
+ - 主机上传文件逻辑优化。
+ - 应用商店应用列表页面查询接口优化。
+ - 部分主机地址输入框正则表达式兼容 ipv6。
+ - 创建应用时增加端口的检测范围。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了 SSH 日志为空时不渲染的问题。
+ - 修复了网站添加防盗链保存两次导致访问网站自动下载文件的问题。
+ - 修复了修改上传限制导致 PHP 配置文件显示错误的问题。
+ - 修复了本地应用删除版本文件夹后页面版本没有同步的问题.
+ - 修复了网站删除密码后,无法关闭密码访问的问题。
+ - 修复了重复创建容器编排导致来源显示错误的问题。
+ - 修复了调整终端字体大小时内容显示不全的问题。
+ - 修复了部分计划任务执行周期显示异常的问题。
+ - 修复了监控、概览页面 echarts 资源未释放的问题。
+
+!!! note "应用商店 :star2:"
+
+ - 应用商店新增 AdGuardHome。
+ - 应用商店新增 Memcached。
+ - 应用商店新增 QianDao。
+ - 应用商店新增 Lsky Pro。
+ - 应用商店新增 Bitwarden。
+ - 应用商店新增 RustDesk。
+ - 应用商店新增 KubePi。
+ - 应用商店新增 MySQL 5.6。
+ - 应用商店新增 Synapse。
+ - 应用商店新增 Cloudreve。
+ - 应用商店新增 Nginx Proxy Manager。
+ - 应用商店新增 VS Code server。
+ - 应用商店新增 ddns-go。
+ - 应用商店新增 EMQX。
+ - 应用商店新增 RabbitMQ。
+ - 应用商店新增 MBlog。
+ - 应用商店新增青龙面板。
+ - Halo 版本升级至 v2.7.0。
+ - Jenkins 版本升级至 v2.413。
+ - Tailchat 版本升级至 v1.8.3。
+ - MariaDB 版本升级至 v10.11.4。
+ - Alist 版本升级至 v3.20.1。
+ - Flarum 版本升级至 v1.8.0。
+ - Nexus 版本升级至 v3.57.0。
+ - 禅道 版本升级至 v18.4。
+ - MongoDB 版本升级至 v6.0.7。
+ - Uptime Kuma 版本升级至 v1.22.1。
+ - Gitea 版本升级至 v1.19.4。
+ - Redis 版本升级至 7.0.12。
+
+### v1.3.6
+
+2023年06月26日
+
+!!! note "功能优化 :sunflower:"
+
+ - 应用商店列表增加分页显示。
+ - SSH 登录日志列表查询逻辑优化。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了由于 docker 版本低导致应用无法正常操作的问题。
+ - 修复了执行备份根目录文件夹计划任务失败的问题。
+ - 修复了系统数据库文件无法正常读写时系统提示错误的问题。
+ - 修复了添加镜像仓库和进入容器终端存在命令注入的问题。
+ - 修复了设置容器镜像加速和私有仓库时由于空行导致 docker 无法正常启用的问题。
+
+### v1.3.5
+
+2023年06月17日
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了部分服务器安装面板启动失败的问题。
+
+### v1.3.4
+
+2023年06月15日
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了终端及容器界面 ios 移动端加载失败的问题。
+
+### v1.3.3
+
+2023年06月13日
+
+!!! note "功能优化 :sunflower:"
+
+ - 容器日志查看页面支持全屏显示。
+ - 计划任务增加批量开启和暂停功能。
+ - 应用导入备份、恢复功能优化。
+ - 容器存储卷列表增加快捷进入挂载点目录的功能。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了计划任务执行周期选择周日时,创建失败的问题。
+ - 修复了当创建 MYSQL 数据库提示用户已存在时,回滚操作误删同名数据库用户的问题。
+ - 修复了一些情况下 SSH 登录日志文件被识别成二进制格式,导致无法读取登录成功日志的问题。
+
+### v1.3.2
+
+2023年06月10日
+
+!!! note "功能优化 :sunflower:"
+
+ - 部分页面兼容移动端问题优化。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了应用升级之后状态异常的问题。
+
+### v1.3.1
+
+2023年06月09日
+
+!!! note "功能优化 :sunflower:"
+
+ - SSH 登录日志查询优化。
+ - 应用详情页适配夜间模式。
+ - 容器配置页面日志切割样式优化。
+ - 应用商店安装应用提示信息优化。
+ - 网站 PHP 配置增加默认禁用函数。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了清空 MySQL 日志时报错的问题。
+ - 修复了同步应用失败导致 1Panel 系统启动异常的问题。
+ - 修复了上传大文件到 SFTP 服务器失败的问题。
+ - 修复了部分应用备份或升级出现找不到文件夹导致失败的问题。
+ - 修复了主机终端全屏后导致左侧菜单消失的问题。
+
+### v1.3.0
+
+2023年06月08日
+
+!!! note "新增功能 :star2:"
+
+ - 部分页面兼容移动端。
+ - 新增支持 armv7l、s390x 和 ppc64le 三种架构。
+ - 新增 SSH 配置管理与 SSH 登录日志。
+ - 面板设置增加域名绑定和授权 IP 功能。
+ - 面板设置增加修改服务器系统时区功能。
+ - 新增文件批量上传功能。
+ - 应用商店对接远程仓库。
+ - 应用商店已安装应用增加打开安装目录功能。
+ - 应用商店创建应用时支持高级设置。
+ - 应用商店创建应用时支持用户自定义 Compose 文件。
+ - 应用商店支持多容器的本地应用。
+ - 应用商店本地应用增加同步日志功能。
+ - 应用商店增加定时同步功能。
+ - 网站 HTTPS 配置增加阻止 IP 访问 TLS 握手功能。
+ - 网站设置支持用户启用防盗链。
+ - 网站增加 IPV6 监听设置。
+ - PHP 网站支持禁用函数设置。
+ - PHP 网站增加配置上传限制功能。
+ - 新增网站日志清空功能。
+ - 增加容器日志清理功能。
+ - 容器页面增加容器、镜像、网络、存储卷清理功能。
+ - 容器配置增加日志切割功能。
+ - 计划任务增加切割网站日志类型。
+ - 计划任务增加时间同步类型。
+ - 计划任务执行周期增加每隔 N 秒执行。
+ - 1pctl 工具增加创建本地应用指令。
+ - 主机监控页面支持用户自定义数据采集间隔。
+
+!!! note "功能优化 :sunflower:"
+
+ - 应用商店安装应用时默认填充应用名称。
+ - 应用商店同步应用列表方式优化。
+ - 应用商店已安装应用升级逻辑优化。
+ - 应用商店全部应用列表增加应用已安装提示。
+ - 网站证书列表页增加 acme 账号提示信息。
+ - 创建网站运行环境逻辑优化。
+ - 限制网站在没有初始化用户的情况下开启网站密码访问功能。
+ - 创建 DNS 账号禁止输入空格。
+ - 容器配置页面样式优化。
+ - 容器菜单中 Docker 运行状态的判断逻辑优化。
+ - 容器详情页面高度调整为自适应。
+ - 系统内存占用优化。
+ - 概览页存在多块磁盘时页面显示优化。
+ - 概览页浏览器失去焦点后停止查询、节省开销。
+ - 计划任务 Shell 脚本类型设置执行路径。
+ - 计划任务报告页面样式优化。
+ - 计划任务报告页显示计划任务名称。
+ - 计划任务排除规则修改为换行切割。
+ - 创建计划任务时增加第三方备份账号跳转的提示信息。
+ - 主机监控页面无数据时显示样式优化。
+ - 系统未启用安全入口时跳转逻辑优化。
+ - 系统检查更新错误信息优化。
+ - 1pctl 工具重构 reset 指令。
+ - 同步服务器时间支持用户自定义 NTP 服务器。
+ - 面板设置增加部分输入内容校验和提示信息。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了部分小内存服务器下载大文件超时的问题。
+ - 修复了备份文件过大导致下载超时问题。
+ - 修复了应用商店安装 Nexus 失败的问题。
+ - 修复了应用商店安装 Halo 时,用户名设置为大写之后导致安装失败的问题。
+ - 修复了网站的默认文档不能设置为子目录的文件的问题。
+ - 修复了导入 cloudflare 证书后域名显示错误的问题。
+ - 修复了申请多域名证书时显示异常的问题。
+ - 修复了进入系统容器终端导致容器异常退出的问题。
+ - 修复了添加没有认证的镜像仓库时报错的问题。
+ - 修复了解压 GBK 格式的 zip 文件时中文乱码的问题。
+ - 修复了编辑已停止计划任务时导致任务执行的问题。
+ - 修复了创建 PHP 运行环境时安装 ioncube_loader 依赖失败的问题。
+ - 修复了创建 PHP 运行环境时安装 imagick 依赖失败的问题。
+
+!!! note "应用商店 :star2:"
+
+ - 应用商店支持 Typecho。
+ - 应用商店列表新增 ehang-io/nps。
+ - 应用商店列表新增 Tailchat。
+ - 应用商店增加禅道。
+ - Halo 版本升级至 2.6.0。
+ - Gitea 版本升级至 v1.19.3。
+ - DataEase 版本升级至 v1.18.7。
+ - MySQL 版本升级至 v5.7.42。
+ - MySQL 版本升级至 8.0.33。
+ - Jellyfin 版本升级至 v10.8.10。
+ - MongoDB 版本升级至 v6.0.6。
+ - WordPress 版本升级至 v6.2.2。
+ - Jenkins 版本升级至 v2.407。
+ - Uptime Kuma 版本升级至 v1.21.3。
+ - MariaDB 版本升级至 v10.11.3。
+ - PostgreSQL 版本升级至 v15.3。
+ - Redis 版本升级至 v6.2.12。
+ - AList 版本升级至 3.18.0。
+ - Nexus 版本升级至 3.54.1。
+ - Wiki.js 版本升级至 v2.5.299。
+
+### v1.2.4
+
+2023年05月22日
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了文件编辑页面确认按钮可能被隐藏的问题。
+ - 修复了网站设置伪静态页面光标丢失的问题。
+ - 修复了进入概览页控制台报错的问题。
+ - 修复了搜索子目录模糊查询失败的问题。
+ - 修复了服务器禁用 ipv6 后创建网站失败的问题。
+ - 修复了反向代理 1Panel 并启用 auth_basic 的时候无法登录的问题。
+ - 修复了概览页推荐应用处在窄窗口时显示异常的问题。
+
+### v1.2.3
+
+2023年05月15日
+
+!!! note "功能优化 :sunflower:"
+
+ - 容器配置界面样式优化。
+ - 部分页面右侧抽屉宽度优化。
+ - 限制用户启动失败状态的应用。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了网站日志文件较大时,在界面上查看日志会导致系统短时间卡住的问题。
+ - 修复了创建容器时不支持部分端口的问题。
+ - 修复了网站设置切换到 HTTPS 控制台报错的问题。
+ - 修复了数据库权限指定多 IP 无效的问题。
+ - 修复了计划任务未勾选同步到本地导致数据库恢复失败的问题。
+ - 修复了 HTTPS 类型网站设置默认网站失败的问题。
+ - 修复了上传数据库备份文件后恢复失败的问题。
+ - 修复了用户启用 HTTPS 后跳转登录页 URL 未包含安全入口的问题。
+ - 修复了默认网站开启 HTTPS 后 443 端口没有设置 default_server 的问题。
+
+### v1.2.2
+
+2023年05月10日
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了系统开启安全入口后升级完成无法跳转到登录页的问题。
+
+### v1.2.1
+
+2023年05月10日
+
+!!! note "功能优化 :sunflower:"
+
+ - 暗色模式下部分页面样式优化。
+ - maccms 伪静态配置文件优化。
+ - 应用商店更新应用列表修改为异步操作。
+ - 应用商店已安装应用列表中限制 PHP 应用升级。
+ - 右侧抽屉页面增加对象名称显示。
+ - MinIO 升级至最新稳定版本。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了文件列表总条数显示错误的问题。
+ - 修复了登录情况下用户输入任意路由跳转到安全入口的问题。
+ - 修复了登录页面验证码加载失败的问题。
+ - 修复了概览页流量监控数据出现负值的问题。
+ - 修复了本地备份账号更新失败的问题。
+ - 修复了运行环境版本与已安装应用版本不一致的问题。
+ - 修复了部分单核系统容器 CPU 监控数据读取错误的问题。
+ - 修复了密码过期后重定向到登录页的问题。
+
+### v1.2.0
+
+2023年05月08日
+
+!!! note "新增功能 :star2:"
+
+ - 面板增加安全入口访问功能。
+ - 网站反向代理设置支持同站多条代理功能。
+ - 面板设置增加 ssl 设置功能。
+ - 1pctl user-info 命令返回信息增加 ssl 和安全入口两个参数。
+ - 网站增加密码访问功能。
+ - 1pctl version 命令返回信息增加 mode 参数。
+ - 容器列表显示增加资源使用率、端口。
+ - 创建容器页面端口支持更多形式。
+ - 容器菜单支持创建 nfs 存储卷。
+ - 文件管理增加复制路径功能。
+ - 文件管理支持设置用户/用户组。
+ - 用户删除编排时支持用户选择是否删除源文件。
+ - 文件管理支持同步修改子目录权限。
+ - 1pctl 增加关闭两步验证、取消面板 ssl 和关闭安全入口等命令。
+ - 文件管理增加搜索子目录功能。
+ - 面板设置配置两步验证时支持二维码和密钥两种方式。
+ - 创建网站时 OpenResty 配置支持 ipv6。
+
+!!! note "功能优化 :sunflower:"
+
+ - 用户首次登录不再强制输入验证码。
+ - 系统页脚增加论坛、文档入口。
+ - 创建容器、编排时日志获取方式调整为异步加载。
+ - 创建反向代理网站逻辑优化。
+ - 创建编排页面样式优化。
+ - 文件复制粘贴逻辑优化。
+ - 用户创建编排页面合并验证和提交按钮。
+ - 面板设置页面样式优化。
+ - 面板设置两步验证样式优化。
+ - 应用商店已安装应用操作执行时间优化。
+ - Redis 页面部分按钮位置调整。
+ - 创建快照时限制备注信息长度。
+ - 防火墙创建端口规则页面指定 IP 输入增加提示信息。
+ - 文件列表样式优化。
+ - 创建运行环境页面自定义扩展提示信息优化。
+ - 网站列表页面增加 WAF 入口。
+ - gin 版本升级到 v1.9.0。
+ - 优化了列表页面查询输入框刷新判断条件。
+ - 面板设置统一调整为抽屉实现。
+ - 监控设置选项调整到 主机 - 监控 菜单。
+ - 网站列表页面增加网站目录跳转功能。
+ - 两步验证启用页面增加时间同步提示信息。
+ - 网站新增域名后自动放开相应端口。
+ - 网站域名跳转增加相应端口。
+ - 非静态网站和运行环境网站隐藏网站目录权限。
+ - 创建容器编排页面默认显示编辑模式。
+ - 更新 IP 地址库。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了容器终端断开后未正常退出进程的问题。
+ - 修复了概览页流量监控显示错误的问题。
+ - 修复了文件复制到原路径导致文件内容清空的问题。
+ - 修复了文件编辑之后大小没有改变的问题。
+ - 修复了本地应用升级失败的问题。
+ - 修复了部分页面回车导致页面刷新的问题。
+ - 修复了文件上传成功后可以再次点击导致文件重复上传的问题。
+ - 修复了由于部分节点时区问题导致网站状态停止的问题。
+ - 修复了解压 mac 压缩文件失败的问题。
+ - 修复了创建 MySQL 数据库时用户名重复导致创建失败的问题。
+ - 修复了文件导航栏搜索不存在的资源后,点击下面存在的目录也会提示资源不存在的问题。
+ - 修复了部分 Shell 类型计划任务脚本执行后没有输出的问题。
+ - 修复了应用列表页面搜索之后点击安装没响应的问题。
+
+!!! note "应用商店 :star2:"
+
+ - 应用商店列表新增 Gitea。
+ - 应用商店列表新增 alist。
+ - 应用商店列表新增 Adminer。
+ - 应用商店列表新增 qBittorrent、jellyfin、alist、watchtower。
+ - PHP 运行环境增加 5.4 - 5.5、7.0 - 7.4、8.0 - 8.1 版本。
+ - Halo 版本升级到 2.5.2。
+ - Openresty 隐藏版本号。
+ - MinIO 支持设置文件分享地址。
+ - MySQL 容器时间与宿主机同步。
+
+### v1.1.3
+
+2023年04月21日
+
+!!! note "功能优化 :sunflower:"
+
+ - 添加防火墙端口规则时,指定 IP 支持输入网段。
+ - 登录页面验证码输入错误后清空验证码输入框。
+ - UFW 防火墙状态检测时支持中文状态。
+ - 开启 UFW 防火墙时增加服务器是否已安装 sudo 命令的判断。
+ - 禁止搜索引擎收录面板首页。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了下载网站备份文件时可能超时的问题。
+
+### v1.1.2
+
+2023年04月19日
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了网站名称和代号不一致时,伪静态配置文件目录设置错误的问题。
+ - 修复了网站名称和代号不一致时,网站目录设置用户/用户组报错的问题。
+
+### v1.1.1
+
+2023年04月18日
+
+!!! note "新增功能 :star2:"
+
+ - 网站支持设置伪静态规则。
+ - 网站支持设置运行目录。
+ - 网站支持设置主目录所属用户及用户组。
+
+!!! note "功能优化 :sunflower:"
+
+ - 创建 PHP 运行环境时支持手动添加扩展。
+ - 登录系统后自动检查更新。
+ - 登录页面在英文状态下样式优化。
+ - 打开系统防火墙时,自动放开应用商店创建的应用以及 80、443 和 22 等常用端口。
+ - 创建 PHP 运行环境时同步修改 index 目录文件和文件夹权限。
+ - 创建运行环境类型网站时增加 OpenResty 升级提示。
+ - 防火墙空状态页面样式优化。
+ - 防火墙禁 ping 按钮增加判断条件。
+ - 数据库连接信息提示优化。
+ - 网站目录页面样式优化。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了创建快照时可能超时的问题。
+ - 修复了部分表单页面回车导致提交失败的问题。
+ - 修复了可以删除使用中备份账号的问题。
+ - 修复了使用本地镜像创建容器时,可能失败的问题。
+ - 修复了网站过期时间设置为永久之后再次打开过期时间显示错误的问题。
+
+### v1.1.0
+
+2023年04月13日
+
+!!! note "新增功能 :star2:"
+
+ - 新增 PHP 运行环境。
+ - 新增系统防火墙配置管理功能。
+ - 新增同步本地应用功能。
+ - 备份账号支持腾讯云 COS、七牛云 Kudo。
+ - 文件管理增加批量删除功能。
+ - 计划任务支持备份所有数据库和网站。
+ - 支持清空计划任务执行记录和日志文件。
+ - 终端增加心跳保活。
+ - 终端增加网络延迟显示。
+ - 添加主机页面支持用户输入私钥密码。
+ - 容器配置支持设置 iptables。
+ - 计划任务支持自定义日志文件保留份数。
+ - 添加主机页面增加记住密码功能。
+ - 文件导航栏支持输入 URL 直接访问。
+ - 数据库增加随机密码和复制密码按钮。
+ - 支持查看数据库容器服务名称。
+ - 文件编辑器支持 Python。
+ - 计划任务记录状态实时刷新。
+
+!!! note "功能优化 :sunflower:"
+
+ - 监控数据改为批量插入。
+ - 前端页面打开速度优化。
+ - 服务未启动页面的遮罩样式优化。
+ - 监控界面时间控件居中显示。
+ - 创建容器页面命令输入方式优化。
+ - 创建网站流程优化。
+ - 主机连接测试未通过之前不允许用户添加主机。
+ - 删除网站、应用逻辑优化。
+ - 删除计划任务时增加是否删除数据的提示信息。
+ - 前端启动配置可以通过 IP 访问。
+ - 补全备份列表返回信息。
+ - 增加对象存储服务商与亚马逊 S3 云存储的兼容性提示信息。
+ - 计划任务列表样式调整。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了前端开发时后端接口代理无法正常连接 WebSocket 的问题。
+ - 修复了终端在网络环境较差时无法正常初始化全屏尺寸的问题。
+ - 修复了备份账号创建后未重置 bucket 的问题。
+ - 修复了应用状态一直处于安装中不能停止的问题。
+ - 修复了 Docker 配置修改提示信息错误的问题。
+ - 修复了容器配置文件为空时,保存报错的问题。
+ - 修复了 Swarm 模式下,容器配置页面启用 live-restore 失败的问题。
+ - 修复了修改分组之后,网站页面过滤条件分组没有刷新的问题。
+ - 修复了编辑主机信息时,未输入密码或密钥测试连接失败的问题
+ - 修复了切换 MySQL 远程访问权限后失效的问题。
+ - 修复了证书申请超时后会产生脏数据的问题。
+ - 修复了网站证书续签的定时任务执行周期异常的问题。
+
+### v1.0.5
+
+2023年03月31日
+
+!!! note "功能优化 :sunflower:"
+
+ - 终端支持 Ctrl + 鼠标滚轮缩放字体。
+ - 文件编辑器支持选择 Linux/Windowns 换行符。
+ - opencontainers/runc 依赖包版本升级。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了概览页磁盘监控信息显示异常的问题。
+ - 修复了应用商店安装 Nexus 失败的问题。
+ - 修复了系统重启后部分计划任务执行周期异常的问题。
+
+### v1.0.4
+
+2023年03月30日
+
+!!! note "功能优化 :sunflower:"
+
+ - 概览页监控图表中网卡和磁盘的默认排序规则优化。
+ - 系统初始化过程支持用户自定义端口。
+ - 系统防火墙是否开启的判断逻辑优化。
+ - wiki.js 默认数据源修改为 MySQL。
+ - Jwt 超时时间优化。
+ - 应用软件描述文案优化。
+ - 简化社区软件协议文案。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了部分容器创建完成后直接退出的问题。
+ - 修复了创建容器时自动拉取镜像失败的问题。
+ - 修复了 Jwt 登录失败的问题。
+ - 修复了概览页磁盘 IO 读写延迟数据未实时刷新的问题。
+ - 修复了概览页只识别到系统盘的问题。
+ - 修复了登录页面从大屏切换到小屏后账户信息消失的问题。
+ - 修复了部分应用缺少来源标签的问题。
+ - 修复了部分 Ubuntu 服务器启动 1Panel 可能失败的问题。
+
+### v1.0.3
+
+2023年03月24日
+
+!!! note "功能优化 :sunflower:"
+
+ - 网站证书列表增加设置自动续签功能。
+ - 优化了数据库、应用、网站导入备份文件大小限制。
+ - 优化系统升级逻辑。
+ - 优化构建容器镜像和创建容器编排的路径限制,并支持 config 校验。
+ - 系统数据库 SQLite 启用 WAL 模式,增加连接数与超时设置。
+ - 系统启动完成后同步已安装应用列表。
+ - 应用商店新增 uptime-kuma、wiki.js。
+ - 创建容器编排调整为异步模式。
+ - 系统增加社区软件许可协议。
+ - 优化容器菜单页面状态加载样式。
+ - 编辑应用时支持用户操作下拉框类型。
+ - 系统文件上传操作统一修改为切片处理。
+ - 优化主机分组功能。
+ - 修改主机默认分组名称。
+ - 优化网站分组功能。
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了应用创建时没有默认网络导致创建失败的问题。
+ - 修复了数据库密码修改后同步到关联应用失败的问题。
+ - 修复了网站定时任务没有准时执行的问题。
+ - 修复了计划任务记录状态筛选导致记录不断追加的问题。
+ - 修复了监控页面时间控件显示不全的问题。
+ - 修复了编辑文件时快捷提示不显示的问题。
+ - 修复了容器镜像构建过程中日志部分丢失的问题。
+ - 修复了快照同步恢复失败的问题。
+ - 修复了开启 mfa 后,登录页面回车触发页面刷新的问题。
+
+### v1.0.2
+
+2023年03月18日
+
+!!! note "功能优化 :sunflower:"
+
+ - 阿里云 OSS 支持分片上传、下载备份文件
+ - 加密传输主机等敏感信息
+ - 创建一键部署类型网站时名称与单独部署应用保持一致
+ - 网站域名设置页面增加网站跳转按钮
+ - 优化停用网站提示信息样式
+ - 优化删除使用中容器时的提示信息
+ - 移除了项目中部分调试打印信息
+ - 数据库重启等操作增加 loading
+ - 备份恢复等功能增加失败日志打印
+ - 表格中可点击列信息超长时样式优化
+ - 创建容器时,CPU、内存的默认值修改为不限制
+ - 添加终端主机和 SFTP 主机时,增加 ip 或 域名正则校验
+ - 修改 redis 最大连接数限制
+ - 优化 1Panel 版本升级逻辑
+ - 切换页面时隐藏部分默认配置提示信息
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了打开应用详情页面控制台报错的问题
+ - 修复了容器等已知问题
+ - 修复了部分页面国际化问题
+ - 修复了文件和网站名称过长只显示...的问题
+ - 修复了 MySQL 慢日志设置修改失败的问题
+ - 修复了打开文件编辑控制台报错的问题
+ - 修复了部分场景下手动解析模式申请证书失败的问题
+ - 修复了部分页面国际化换行问题
+ - 修复了计划任务保存到第三方备份账号部分场景不生效的问题
+ - 修复了 Compose 创建错误未存库的问题
+ - 修复了 MySQL 数据库名称带 - 字符时授权失败的问题
+ - 修复了慢日志开启后未刷新导致无法关闭的问题
+ - 修复了计划任务备份文件失效仍显示下载按钮的问题
+
+### v1.0.1
+
+2023年03月15日
+
+!!! note "问题修复 :palm_tree:"
+
+ - 修复了网站、文件等已知问题
+ - 修复了 amd64 环境下文件压缩异常的问题
+ - 修复了数据库、主机、计划任务等已知问题
+ - 取消了网站列表页面的部分提示信息
+ - 部分页面样式优化
+ - 修复了应用删除提示页面没有实时刷新的问题
+ - 修复了删除 MySQL 应用没有同步删除表数据的问题
+ - 优化关于页面的版本信息
+ - 文件下载页面增加 loading
+ - 修复了 1Panel 自身服务升级失败的问题
+
+### v1.0.0
+
+2023年03月13日
+
+!!! note "新增功能 :star2:"
+
+ - **快速建站**:深度集成 Wordpress 和 Halo,域名绑定、SSL 证书配置等一键搞定;
+ - **高效管理**:通过 Web 端轻松管理 Linux 服务器,包括主机监控、文件管理、数据库管理、容器管理及常用应用软件管理;
+ - **安全可靠**:最小漏洞暴露面,提供防火墙和安全审计等功能;
+ - **一键备份**:支持一键备份和恢复,备份数据云端存储,永不丢失。
diff --git a/docs/contact.md b/docs/contact.md
new file mode 100644
index 00000000..ff2cf785
--- /dev/null
+++ b/docs/contact.md
@@ -0,0 +1,19 @@
+## 1 项目地址
+
+!!! note ""
+
+ - [1Panel Issues](https://github.com/1Panel-dev/1Panel/issues)
+
+## 2 社区论坛
+
+!!! note ""
+
+ 飞致云官方开源社区论坛:[开源社区论坛](https://bbs.fit2cloud.com/c/1p)
+ > 大家可以在这里搜索、咨询、讨论问题,发表自己的见解与想法。
+
+## 3 联系方式
+
+!!! note ""
+
+ - 官网:http://www.1panel.cn
+ - 微信交流群:https://bbs.fit2cloud.com/t/topic/2147
diff --git a/v1/css/custom.css b/docs/css/custom.css
similarity index 100%
rename from v1/css/custom.css
rename to docs/css/custom.css
diff --git a/v1/css/extra.css b/docs/css/extra.css
similarity index 100%
rename from v1/css/extra.css
rename to docs/css/extra.css
diff --git a/v1/css/termynal.css b/docs/css/termynal.css
similarity index 100%
rename from v1/css/termynal.css
rename to docs/css/termynal.css
diff --git a/docs/dev_manual/.DS_Store b/docs/dev_manual/.DS_Store
new file mode 100644
index 00000000..dc1eef79
Binary files /dev/null and b/docs/dev_manual/.DS_Store differ
diff --git a/docs/dev_manual/api_manual.md b/docs/dev_manual/api_manual.md
new file mode 100644
index 00000000..5915fc30
--- /dev/null
+++ b/docs/dev_manual/api_manual.md
@@ -0,0 +1,81 @@
+## API 接口配置与使用指南
+
+本文档详细介绍了如何在三方服务中使用自定义 Token 的验证来访问面板接口。
+
+### 以下内容已通过 Swagger 进行验证
+面板 swagger 访问地址:`{host}:{port}/1panel/swagger/index.html`
+
+### 自定义 Token 格式
+
+我们设计了以下自定义 Token 格式,用于接口请求的身份验证:
+
+```text
+Token = md5('1panel' + API-Key + UnixTimestamp)
+```
+组成部分:
+
+- 固定前缀: '1panel'
+- API-Key: 面板 API 接口密钥
+- UnixTimestamp: 当前的时间戳(秒级)
+
+### 请求 Header 设计
+
+每次请求必须携带以下两个 Header:
+
+| Header 名称 | 说明 |
+|------------------|--------------------|
+| 1Panel-Token | 自定义的 Token 值 |
+| 1Panel-Timestamp | 当前时间戳 |
+
+### 示例请求头:
+```bash
+curl -X GET "http://localhost:4004/api/v1/dashboard/current" \
+-H "1Panel-Token: <1panel_token>" \
+-H "1Panel-Timestamp: "
+```
+
+### 示例实现代码(go)
+
+```go
+func validateToken(c *gin.Context) error {
+ panelToken := c.GetHeader("1Panel-Token")
+ panelTimestamp := c.GetHeader("1Panel-Timestamp")
+ systemToken := panelToken
+ systemKey = ******* // 面板 API 密钥
+ expectedToken := md5Sum("1panel" + systemKey + panelTimestamp)
+ if systemToken != expectedToken {
+ return fmt.Errorf("invalid token")
+ }
+ return nil
+}
+
+func md5Sum(data string) string {
+ h := md5.New()
+ h.Write([]byte(data))
+ return hex.EncodeToString(h.Sum(nil))
+}
+```
+
+## 注意事项
+
+1. 时间戳的有效性:
+需要确保服务器与客户端时间同步,否则会导致验证失败。建议使用 NTP 同步时间。
+2. 白名单使用:
+将可信任的 IP 或 IP 段加入白名单,避免频繁 Token 验证的开销;如需放行所有 IP ,可以配置 `0.0.0.0`。
+
+## 常见问题
+
+1. Q: 如果 1Panel-Token或1Panel-Timestamp 错误怎么办?
+ A: 返回 401 Unauthorized,提示 "API 接口密钥错误"。
+2. Q: 如何生成 1Panel-Token?
+ A: 参考以下伪代码:
+```javascript
+const token = md5('1panel' + clientToken + unixTimestamp);
+```
+3. Q: 为什么需要两个 Header?
+ A: 提高验证的复杂度,同时增强安全性。
+
+
+## 结语
+
+通过上述方式可以实现一个安全、高效的 Token 验证系统。如果有任何问题,请参考具体代码实现或联系我们获取支持。
\ No newline at end of file
diff --git a/docs/dev_manual/dev_manual.md b/docs/dev_manual/dev_manual.md
new file mode 100644
index 00000000..a628fc9d
--- /dev/null
+++ b/docs/dev_manual/dev_manual.md
@@ -0,0 +1,79 @@
+## 1 项目结构
+
+```
+.
+├── backend # 后端项目主目录
+├── build # 编译目录
+├── cmd # 后端启动目录
+└── frontend # 前端项目主目录
+
+```
+
+## 2 配置开发环境
+
+### 2.1 环境准备
+
+!!! note "后端"
+ 1Panel 后端使用了 Golang 语言的 Gin 框架,并使用 go.mod 作为项目管理工具。开发者需要先在开发环境中安装 go 1.22 或者以上版本
+
+!!! note "前端"
+ 1Panel 前端使用了 Vue.js 作为前端框架,Element-Plus 作为 UI 框架,并使用 npm 作为包管理工具。开发者请先下载 Node.js 作为运行环境,IDEA 用户建议安装 Vue.js 插件,便于开发。
+ npm 版本 9.6.x ,Node.js 版本 20.2.x
+
+!!! note "安装 npm"
+ [进入网站](https://nodejs.org/en/download/), 选择相应的安装包进行安装即可。
+
+### 2.2 初始化配置
+
+!!! note "配置文件"
+ 1Panel 会默认加载该路径下的配置文件 /opt/1panel/conf/app.yaml,**请参考下面配置创建对应目录及配置文件**。
+
+ ```
+ system:
+ db_file: 1Panel.db
+ base_dir: /opt
+ mode: dev
+ repo_url: https://resource.fit2cloud.com/1panel/package
+ app_repo: https://apps-assets.fit2cloud.com
+ is_demo: false
+ port: 9999
+ username: admin #初始用户名
+ password: admin123 #初始密码
+
+ log:
+ level: debug
+ time_zone: Asia/Shanghai
+ log_name: 1Panel
+ log_suffix: .log
+ max_backup: 10
+ ```
+
+## 3 代码运行
+
+### 3.1 运行后端服务
+
+!!! note ""
+ 新建一个 git 项目 输入主工程 git 地址: git@github.com:1Panel-dev/1Panel.git
+
+{width="900px"}
+
+### 3.2 新建 Go build 启动项
+
+
+
+### 3.3 运行后端
+
+!!! note ""
+
+ - 需要先进入工程目录下的子目录 frontend, 执行 npm run build:dev 打包前端资源
+
+
+
+### 3.4 运行前端
+
+!!! note ""
+
+ - 进入工程目录下的子目录 frontend, 用 npm i 安装前端依赖包
+ - 安装完成后,使用 npm run dev 命名启动前端,前端启动后即可通过 http://localhost:4004/ 地址访问
+ - 使用默认用户名 admin 默认密码 admin123 登录
+
diff --git a/v1/dev_manual/go_build.png b/docs/dev_manual/go_build.png
similarity index 100%
rename from v1/dev_manual/go_build.png
rename to docs/dev_manual/go_build.png
diff --git a/v1/dev_manual/open.png b/docs/dev_manual/open.png
similarity index 100%
rename from v1/dev_manual/open.png
rename to docs/dev_manual/open.png
diff --git a/v1/dev_manual/start.png b/docs/dev_manual/start.png
similarity index 100%
rename from v1/dev_manual/start.png
rename to docs/dev_manual/start.png
diff --git a/docs/faq/.DS_Store b/docs/faq/.DS_Store
new file mode 100644
index 00000000..cb15e0ee
Binary files /dev/null and b/docs/faq/.DS_Store differ
diff --git a/docs/faq/faq.md b/docs/faq/faq.md
new file mode 100644
index 00000000..be285cc0
--- /dev/null
+++ b/docs/faq/faq.md
@@ -0,0 +1,21 @@
+## 1 1Panel 和宝塔有什么区别?
+
+!!! note ""
+ **宝塔是一款被广泛使用的 Linux 面板。与宝塔 Linux 面板相比,1Panel 的特色是开源和现代化。**
+
+ - 开源:1Panel 强调开源开放,广泛获取社区使用反馈,并快速迭代。
+ - 现代化:一方面,1Panel 采纳最新的前端技术,并通过精心设计的 UX 交互,为用户提供更好的用户使用体验;另一方面,1Panel 采用主流的容器技术,让 Linux 服务器的运维管理更简单、更安全。
+
+## 2 是否考虑增加多主机管理?
+
+!!! note ""
+ **1Panel 会关注在单机 Linux 的运维管理。**
+
+ 多主机管理推荐使用 [JumpServer 堡垒机](https://github.com/jumpserver/jumpserver) 来实现。尤其现在 JumpServer 也支持 Web 资产,可以通过Web 可视化连上 1Panel,实现多主机管理。
+
+## 3 1Panel 安装包多大?运行时占用系统资源多吗?会影响其他应用吗?
+
+!!! note ""
+
+ - 1Panel 基于 Golang 语言编写,可执行文件大小约 40MB、运行时占用系系统内存约 150MB。
+ - 1Panel 基于 Docker 来部署管理其他应用,对系统的侵入影响非常小。
diff --git a/docs/faq/operating_system.md b/docs/faq/operating_system.md
new file mode 100644
index 00000000..25a27fc7
--- /dev/null
+++ b/docs/faq/operating_system.md
@@ -0,0 +1,38 @@
+## 1 在线安装 docker 时,提示 "ERROR: Unsupported distribution 'xxx'"
+
+{ width="550px" }
+
+!!! note ""
+ **上图的错误是由于 docker 的在线安装脚本不支持该操作系统导致的,目前最好的解决方案就是先手动在服务器上安装并启动 Docker,然后再安装 1Panel。**
+
+ 可以尝试运行以下脚本:
+ ```bash
+ bash <(curl -sSL https://linuxmirrors.cn/docker.sh)
+ ```
+ 了解更多信息,请访问官方网站:https://linuxmirrors.cn
+
+## 2 使用 windows 的 wsl 子系统安装失败
+
+!!! note ""
+ **System has not been booted with systemd as init system (PID 1). Can't operate. Failed to connect to bus: Host is down**
+
+{ width="550px" }
+
+!!! note ""
+ **上图的错误是由于 wsl 子系统不能使用 systemd 导致的启动 docker 服务失败**
+
+ - 更新 systemd 管理,支持 systemd 后问题即可解决
+ - 参考文档:[Systemd support is now available in WSL!](https://devblogs.microsoft.com/commandline/systemd-support-is-now-available-in-wsl/)
+
+## 3 使用 Fedora 37 安装面板后打开防火墙发现面板创建的端口规则未效果
+
+!!! note ""
+ **Fedora 37 默认区域不是 public 导致的,可以通过以下命令手动将默认区域设置为 public**
+
+ ```bash
+ firewall-cmd --set-default-zone=public
+ ```
+
+ ```bash
+ firewall-cmd --reload
+ ```
diff --git a/docs/faq/server_architecture.md b/docs/faq/server_architecture.md
new file mode 100644
index 00000000..311c077f
--- /dev/null
+++ b/docs/faq/server_architecture.md
@@ -0,0 +1,86 @@
+## 1 s390x 架构
+
+### 安装 MySQL
+
+!!! note ""
+ **由于 MySQL 官方未提供 s390x 架构镜像,所以在应用商店启用 MySQL 前,需要手动修改 MySQL 镜像版本**
+
+!!! note "MySQL 5.7"
+
+ - 1、下载 s390x 架构最新版本镜像
+
+ ```bash
+ docker pull ibmcom/mysql-s390x:5.7.34
+ ```
+
+ - 2、将镜像重命名为 1Panel 应用商店中使用的 MySQL 版本
+
+ ```bash
+ docker tag ibmcom/mysql-s390x:5.7.34 mysql:5.7.42
+ ```
+
+ - 3、在应用商店中安装 MySQL,版本选择 5.7.42
+
+!!! note "MySQL 8.0"
+
+ - 1、下载 s390x 架构最新版本镜像
+
+ ```bash
+ docker pull ibmcom/mysql-s390x:8.0.25
+ ```
+
+ - 2、将镜像重命名为 1Panel 应用商店中使用的 MySQL 版本
+
+ ```bash
+ docker tag ibmcom/mysql-s390x:8.0.25 mysql:8.0.33
+ ```
+
+ - 3、在应用商店中安装 MySQL,版本选择 8.0.33
+
+## 2 armv7l 架构
+
+### 安装 MySQL
+
+!!! note ""
+ **由于 MySQL 官方未提供 armv7l 架构镜像,所以在应用商店启用 MySQL 前,需要手动修改 MySQL 镜像版本**
+
+!!! note "MySQL 5.7"
+
+ - 1、下载 armv7l 架构最新版本镜像
+
+ ```bash
+ docker pull biarms/mysql:5.7.33-beta-circleci
+ ```
+
+ - 2、将镜像重命名为 1Panel 应用商店中使用的 MySQL 版本
+
+ ```bash
+ docker tag biarms/mysql:5.7.33-beta-circleci mysql:5.7.42
+ ```
+
+ - 3、在应用商店中安装 MySQL,版本选择 5.7.42
+
+!!! note "MySQL 8.0"
+
+ **1Panel 当前版本还不支持在 armv7l 架构服务器上安装 MySQL 8.0**
+
+### 安装 OpenResty
+
+!!! note ""
+ **由于 OpenResty 官方未提供 armv7l 架构镜像,所以在应用商店启用 OpenResty 前,需要手动修改 OpenResty 镜像版本**
+
+!!! note ""
+
+ - 1、下载 armv7l 架构最新版本镜像
+
+ ```bash
+ docker pull imzcc/openresty:1.21.4.1-7-alpine
+ ```
+
+ - 2、将镜像重命名为 1Panel 应用商店中使用的 OpenResty 版本
+
+ ```bash
+ docker tag imzcc/openresty:1.21.4.1-7-alpine openresty/openresty:1.21.4.1-7-focal
+ ```
+
+ - 3、在应用商店中安装 OpenResty
diff --git a/docs/faq/system_function.md b/docs/faq/system_function.md
new file mode 100644
index 00000000..c4cc9f09
--- /dev/null
+++ b/docs/faq/system_function.md
@@ -0,0 +1,14 @@
+## 1 使用自建 Nginx 反向代理 1Panel,导致主机和容器终端均不能正常使用。
+
+!!! note ""
+ **需要在 Nginx 配置文件中增加以下配置:**
+
+ ```properties
+ location / {
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ }
+ ```
+
+> **或者直接在 1Panel 系统中新建反向代理网站也可以实现上述功能**
diff --git a/v1/img/ai/api_proxy.png b/docs/img/ai/api_proxy.png
similarity index 100%
rename from v1/img/ai/api_proxy.png
rename to docs/img/ai/api_proxy.png
diff --git a/v1/img/ai/connection_info.png b/docs/img/ai/connection_info.png
similarity index 100%
rename from v1/img/ai/connection_info.png
rename to docs/img/ai/connection_info.png
diff --git a/v1/img/ai/create_mcp_server.png b/docs/img/ai/create_mcp_server.png
similarity index 100%
rename from v1/img/ai/create_mcp_server.png
rename to docs/img/ai/create_mcp_server.png
diff --git a/v1/img/ai/gpu_acceleration.png b/docs/img/ai/gpu_acceleration.png
similarity index 100%
rename from v1/img/ai/gpu_acceleration.png
rename to docs/img/ai/gpu_acceleration.png
diff --git a/v1/img/ai/gpu_monitor.png b/docs/img/ai/gpu_monitor.png
similarity index 100%
rename from v1/img/ai/gpu_monitor.png
rename to docs/img/ai/gpu_monitor.png
diff --git a/v1/img/ai/mcp_binary.png b/docs/img/ai/mcp_binary.png
similarity index 100%
rename from v1/img/ai/mcp_binary.png
rename to docs/img/ai/mcp_binary.png
diff --git a/v1/img/ai/mcp_list.png b/docs/img/ai/mcp_list.png
similarity index 100%
rename from v1/img/ai/mcp_list.png
rename to docs/img/ai/mcp_list.png
diff --git a/v1/img/ai/mcp_server_config.png b/docs/img/ai/mcp_server_config.png
similarity index 100%
rename from v1/img/ai/mcp_server_config.png
rename to docs/img/ai/mcp_server_config.png
diff --git a/v1/img/ai/mcp_website.png b/docs/img/ai/mcp_website.png
similarity index 100%
rename from v1/img/ai/mcp_website.png
rename to docs/img/ai/mcp_website.png
diff --git a/v1/img/ai/model_pull.png b/docs/img/ai/model_pull.png
similarity index 100%
rename from v1/img/ai/model_pull.png
rename to docs/img/ai/model_pull.png
diff --git a/v1/img/ai/model_run.png b/docs/img/ai/model_run.png
similarity index 100%
rename from v1/img/ai/model_run.png
rename to docs/img/ai/model_run.png
diff --git a/v1/img/ai/overview.png b/docs/img/ai/overview.png
similarity index 100%
rename from v1/img/ai/overview.png
rename to docs/img/ai/overview.png
diff --git a/docs/img/app/.DS_Store b/docs/img/app/.DS_Store
new file mode 100644
index 00000000..5008ddfc
Binary files /dev/null and b/docs/img/app/.DS_Store differ
diff --git a/v1/img/app/app_backup.png b/docs/img/app/app_backup.png
similarity index 100%
rename from v1/img/app/app_backup.png
rename to docs/img/app/app_backup.png
diff --git a/v1/img/app/app_delete.png b/docs/img/app/app_delete.png
similarity index 100%
rename from v1/img/app/app_delete.png
rename to docs/img/app/app_delete.png
diff --git a/v1/img/app/app_detail.png b/docs/img/app/app_detail.png
similarity index 100%
rename from v1/img/app/app_detail.png
rename to docs/img/app/app_detail.png
diff --git a/v1/img/app/app_install.png b/docs/img/app/app_install.png
similarity index 100%
rename from v1/img/app/app_install.png
rename to docs/img/app/app_install.png
diff --git a/v1/img/app/app_modify.png b/docs/img/app/app_modify.png
similarity index 100%
rename from v1/img/app/app_modify.png
rename to docs/img/app/app_modify.png
diff --git a/v1/img/app/app_param.png b/docs/img/app/app_param.png
similarity index 100%
rename from v1/img/app/app_param.png
rename to docs/img/app/app_param.png
diff --git a/v1/img/app/app_rebuild.png b/docs/img/app/app_rebuild.png
similarity index 100%
rename from v1/img/app/app_rebuild.png
rename to docs/img/app/app_rebuild.png
diff --git a/v1/img/app/app_restart.png b/docs/img/app/app_restart.png
similarity index 100%
rename from v1/img/app/app_restart.png
rename to docs/img/app/app_restart.png
diff --git a/v1/img/app/app_restore.png b/docs/img/app/app_restore.png
similarity index 100%
rename from v1/img/app/app_restore.png
rename to docs/img/app/app_restore.png
diff --git a/v1/img/app/app_sync.png b/docs/img/app/app_sync.png
similarity index 100%
rename from v1/img/app/app_sync.png
rename to docs/img/app/app_sync.png
diff --git a/v1/img/app/app_upgrade.png b/docs/img/app/app_upgrade.png
similarity index 100%
rename from v1/img/app/app_upgrade.png
rename to docs/img/app/app_upgrade.png
diff --git a/v1/img/app/appstore.png b/docs/img/app/appstore.png
similarity index 100%
rename from v1/img/app/appstore.png
rename to docs/img/app/appstore.png
diff --git a/v1/img/app/install_detail.png b/docs/img/app/install_detail.png
similarity index 100%
rename from v1/img/app/install_detail.png
rename to docs/img/app/install_detail.png
diff --git a/v1/img/app/installed_list.png b/docs/img/app/installed_list.png
similarity index 100%
rename from v1/img/app/installed_list.png
rename to docs/img/app/installed_list.png
diff --git a/v1/img/app/upgrade_list.png b/docs/img/app/upgrade_list.png
similarity index 100%
rename from v1/img/app/upgrade_list.png
rename to docs/img/app/upgrade_list.png
diff --git a/v1/img/containers/compose_create.png b/docs/img/containers/compose_create.png
similarity index 100%
rename from v1/img/containers/compose_create.png
rename to docs/img/containers/compose_create.png
diff --git a/v1/img/containers/compose_detail.png b/docs/img/containers/compose_detail.png
similarity index 100%
rename from v1/img/containers/compose_detail.png
rename to docs/img/containers/compose_detail.png
diff --git a/v1/img/containers/compose_template_create.png b/docs/img/containers/compose_template_create.png
similarity index 100%
rename from v1/img/containers/compose_template_create.png
rename to docs/img/containers/compose_template_create.png
diff --git a/v1/img/containers/container_create.png b/docs/img/containers/container_create.png
similarity index 100%
rename from v1/img/containers/container_create.png
rename to docs/img/containers/container_create.png
diff --git a/v1/img/containers/container_inspect.png b/docs/img/containers/container_inspect.png
similarity index 100%
rename from v1/img/containers/container_inspect.png
rename to docs/img/containers/container_inspect.png
diff --git a/v1/img/containers/container_log.png b/docs/img/containers/container_log.png
similarity index 100%
rename from v1/img/containers/container_log.png
rename to docs/img/containers/container_log.png
diff --git a/v1/img/containers/container_monitor.png b/docs/img/containers/container_monitor.png
similarity index 100%
rename from v1/img/containers/container_monitor.png
rename to docs/img/containers/container_monitor.png
diff --git a/v1/img/containers/container_terminal.png b/docs/img/containers/container_terminal.png
similarity index 100%
rename from v1/img/containers/container_terminal.png
rename to docs/img/containers/container_terminal.png
diff --git a/v1/img/containers/image_build.png b/docs/img/containers/image_build.png
similarity index 100%
rename from v1/img/containers/image_build.png
rename to docs/img/containers/image_build.png
diff --git a/v1/img/containers/ipv6-01.png b/docs/img/containers/ipv6-01.png
similarity index 100%
rename from v1/img/containers/ipv6-01.png
rename to docs/img/containers/ipv6-01.png
diff --git a/v1/img/containers/ipv6-02.png b/docs/img/containers/ipv6-02.png
similarity index 100%
rename from v1/img/containers/ipv6-02.png
rename to docs/img/containers/ipv6-02.png
diff --git a/v1/img/containers/ipv6-03.png b/docs/img/containers/ipv6-03.png
similarity index 100%
rename from v1/img/containers/ipv6-03.png
rename to docs/img/containers/ipv6-03.png
diff --git a/v1/img/containers/network_create.png b/docs/img/containers/network_create.png
similarity index 100%
rename from v1/img/containers/network_create.png
rename to docs/img/containers/network_create.png
diff --git a/v1/img/containers/repo_create.png b/docs/img/containers/repo_create.png
similarity index 100%
rename from v1/img/containers/repo_create.png
rename to docs/img/containers/repo_create.png
diff --git a/v1/img/containers/setting.png b/docs/img/containers/setting.png
similarity index 100%
rename from v1/img/containers/setting.png
rename to docs/img/containers/setting.png
diff --git a/v1/img/containers/volume_create.png b/docs/img/containers/volume_create.png
similarity index 100%
rename from v1/img/containers/volume_create.png
rename to docs/img/containers/volume_create.png
diff --git a/v1/img/cronjobs/cronjob_create.png b/docs/img/cronjobs/cronjob_create.png
similarity index 100%
rename from v1/img/cronjobs/cronjob_create.png
rename to docs/img/cronjobs/cronjob_create.png
diff --git a/v1/img/cronjobs/cronjob_record.png b/docs/img/cronjobs/cronjob_record.png
similarity index 100%
rename from v1/img/cronjobs/cronjob_record.png
rename to docs/img/cronjobs/cronjob_record.png
diff --git a/v1/img/databases/backup_mysql_db.png b/docs/img/databases/backup_mysql_db.png
similarity index 100%
rename from v1/img/databases/backup_mysql_db.png
rename to docs/img/databases/backup_mysql_db.png
diff --git a/v1/img/databases/backup_postgresql_db.png b/docs/img/databases/backup_postgresql_db.png
similarity index 100%
rename from v1/img/databases/backup_postgresql_db.png
rename to docs/img/databases/backup_postgresql_db.png
diff --git a/v1/img/databases/container_monitor.png b/docs/img/databases/container_monitor.png
similarity index 100%
rename from v1/img/databases/container_monitor.png
rename to docs/img/databases/container_monitor.png
diff --git a/v1/img/databases/create_mysql_db.png b/docs/img/databases/create_mysql_db.png
similarity index 100%
rename from v1/img/databases/create_mysql_db.png
rename to docs/img/databases/create_mysql_db.png
diff --git a/v1/img/databases/create_postgresql_db.png b/docs/img/databases/create_postgresql_db.png
similarity index 100%
rename from v1/img/databases/create_postgresql_db.png
rename to docs/img/databases/create_postgresql_db.png
diff --git a/v1/img/databases/mysql_conf.png b/docs/img/databases/mysql_conf.png
similarity index 100%
rename from v1/img/databases/mysql_conf.png
rename to docs/img/databases/mysql_conf.png
diff --git a/v1/img/databases/mysql_connect.png b/docs/img/databases/mysql_connect.png
similarity index 100%
rename from v1/img/databases/mysql_connect.png
rename to docs/img/databases/mysql_connect.png
diff --git a/v1/img/databases/mysql_log.png b/docs/img/databases/mysql_log.png
similarity index 100%
rename from v1/img/databases/mysql_log.png
rename to docs/img/databases/mysql_log.png
diff --git a/v1/img/databases/mysql_remote.png b/docs/img/databases/mysql_remote.png
similarity index 100%
rename from v1/img/databases/mysql_remote.png
rename to docs/img/databases/mysql_remote.png
diff --git a/v1/img/databases/mysql_remote_add.png b/docs/img/databases/mysql_remote_add.png
similarity index 100%
rename from v1/img/databases/mysql_remote_add.png
rename to docs/img/databases/mysql_remote_add.png
diff --git a/v1/img/databases/mysql_select.png b/docs/img/databases/mysql_select.png
similarity index 100%
rename from v1/img/databases/mysql_select.png
rename to docs/img/databases/mysql_select.png
diff --git a/v1/img/databases/mysql_status.png b/docs/img/databases/mysql_status.png
similarity index 100%
rename from v1/img/databases/mysql_status.png
rename to docs/img/databases/mysql_status.png
diff --git a/v1/img/databases/mysql_variables.png b/docs/img/databases/mysql_variables.png
similarity index 100%
rename from v1/img/databases/mysql_variables.png
rename to docs/img/databases/mysql_variables.png
diff --git a/v1/img/databases/mysql_web.png b/docs/img/databases/mysql_web.png
similarity index 100%
rename from v1/img/databases/mysql_web.png
rename to docs/img/databases/mysql_web.png
diff --git a/v1/img/databases/postgresql_conf.png b/docs/img/databases/postgresql_conf.png
similarity index 100%
rename from v1/img/databases/postgresql_conf.png
rename to docs/img/databases/postgresql_conf.png
diff --git a/v1/img/databases/postgresql_connect.png b/docs/img/databases/postgresql_connect.png
similarity index 100%
rename from v1/img/databases/postgresql_connect.png
rename to docs/img/databases/postgresql_connect.png
diff --git a/v1/img/databases/postgresql_log.png b/docs/img/databases/postgresql_log.png
similarity index 100%
rename from v1/img/databases/postgresql_log.png
rename to docs/img/databases/postgresql_log.png
diff --git a/v1/img/databases/postgresql_remote.png b/docs/img/databases/postgresql_remote.png
similarity index 100%
rename from v1/img/databases/postgresql_remote.png
rename to docs/img/databases/postgresql_remote.png
diff --git a/v1/img/databases/postgresql_remote_add.png b/docs/img/databases/postgresql_remote_add.png
similarity index 100%
rename from v1/img/databases/postgresql_remote_add.png
rename to docs/img/databases/postgresql_remote_add.png
diff --git a/v1/img/databases/postgresql_select.png b/docs/img/databases/postgresql_select.png
similarity index 100%
rename from v1/img/databases/postgresql_select.png
rename to docs/img/databases/postgresql_select.png
diff --git a/v1/img/databases/recover_mysql_db.png b/docs/img/databases/recover_mysql_db.png
similarity index 100%
rename from v1/img/databases/recover_mysql_db.png
rename to docs/img/databases/recover_mysql_db.png
diff --git a/v1/img/databases/recover_postgresql_db.png b/docs/img/databases/recover_postgresql_db.png
similarity index 100%
rename from v1/img/databases/recover_postgresql_db.png
rename to docs/img/databases/recover_postgresql_db.png
diff --git a/v1/img/databases/redis_backup_aof.png b/docs/img/databases/redis_backup_aof.png
similarity index 100%
rename from v1/img/databases/redis_backup_aof.png
rename to docs/img/databases/redis_backup_aof.png
diff --git a/v1/img/databases/redis_backup_rdb.png b/docs/img/databases/redis_backup_rdb.png
similarity index 100%
rename from v1/img/databases/redis_backup_rdb.png
rename to docs/img/databases/redis_backup_rdb.png
diff --git a/v1/img/databases/redis_conf.png b/docs/img/databases/redis_conf.png
similarity index 100%
rename from v1/img/databases/redis_conf.png
rename to docs/img/databases/redis_conf.png
diff --git a/v1/img/databases/redis_status.png b/docs/img/databases/redis_status.png
similarity index 100%
rename from v1/img/databases/redis_status.png
rename to docs/img/databases/redis_status.png
diff --git a/v1/img/databases/redis_variables.png b/docs/img/databases/redis_variables.png
similarity index 100%
rename from v1/img/databases/redis_variables.png
rename to docs/img/databases/redis_variables.png
diff --git a/v1/img/databases/update_mysql_db_access.png b/docs/img/databases/update_mysql_db_access.png
similarity index 100%
rename from v1/img/databases/update_mysql_db_access.png
rename to docs/img/databases/update_mysql_db_access.png
diff --git a/docs/img/dev_manual/.DS_Store b/docs/img/dev_manual/.DS_Store
new file mode 100644
index 00000000..5008ddfc
Binary files /dev/null and b/docs/img/dev_manual/.DS_Store differ
diff --git a/v1/img/dev_manual/dataease-extensions.png b/docs/img/dev_manual/dataease-extensions.png
similarity index 100%
rename from v1/img/dev_manual/dataease-extensions.png
rename to docs/img/dev_manual/dataease-extensions.png
diff --git a/v1/img/dev_manual/import-pom1.png b/docs/img/dev_manual/import-pom1.png
similarity index 100%
rename from v1/img/dev_manual/import-pom1.png
rename to docs/img/dev_manual/import-pom1.png
diff --git a/v1/img/dev_manual/import-pom2.png b/docs/img/dev_manual/import-pom2.png
similarity index 100%
rename from v1/img/dev_manual/import-pom2.png
rename to docs/img/dev_manual/import-pom2.png
diff --git a/v1/img/dev_manual/install-frontend.png b/docs/img/dev_manual/install-frontend.png
similarity index 100%
rename from v1/img/dev_manual/install-frontend.png
rename to docs/img/dev_manual/install-frontend.png
diff --git a/v1/img/dev_manual/modify-demo-dataset.png b/docs/img/dev_manual/modify-demo-dataset.png
similarity index 100%
rename from v1/img/dev_manual/modify-demo-dataset.png
rename to docs/img/dev_manual/modify-demo-dataset.png
diff --git a/v1/img/dev_manual/modify-demo-dataset1.png b/docs/img/dev_manual/modify-demo-dataset1.png
similarity index 100%
rename from v1/img/dev_manual/modify-demo-dataset1.png
rename to docs/img/dev_manual/modify-demo-dataset1.png
diff --git a/v1/img/dev_manual/new-project.png b/docs/img/dev_manual/new-project.png
similarity index 100%
rename from v1/img/dev_manual/new-project.png
rename to docs/img/dev_manual/new-project.png
diff --git a/v1/img/dev_manual/run-backend.png b/docs/img/dev_manual/run-backend.png
similarity index 100%
rename from v1/img/dev_manual/run-backend.png
rename to docs/img/dev_manual/run-backend.png
diff --git a/v1/img/dev_manual/windows-idea-1.png b/docs/img/dev_manual/windows-idea-1.png
similarity index 100%
rename from v1/img/dev_manual/windows-idea-1.png
rename to docs/img/dev_manual/windows-idea-1.png
diff --git a/v1/img/dev_manual/windows-idea-2.png b/docs/img/dev_manual/windows-idea-2.png
similarity index 100%
rename from v1/img/dev_manual/windows-idea-2.png
rename to docs/img/dev_manual/windows-idea-2.png
diff --git a/v1/img/facio.ico b/docs/img/facio.ico
similarity index 100%
rename from v1/img/facio.ico
rename to docs/img/facio.ico
diff --git a/v1/img/faq/docker_error.png b/docs/img/faq/docker_error.png
similarity index 100%
rename from v1/img/faq/docker_error.png
rename to docs/img/faq/docker_error.png
diff --git a/v1/img/faq/wsl_error.jpg b/docs/img/faq/wsl_error.jpg
similarity index 100%
rename from v1/img/faq/wsl_error.jpg
rename to docs/img/faq/wsl_error.jpg
diff --git a/v1/img/hosts/firewall_ip_create.png b/docs/img/hosts/firewall_ip_create.png
similarity index 100%
rename from v1/img/hosts/firewall_ip_create.png
rename to docs/img/hosts/firewall_ip_create.png
diff --git a/v1/img/hosts/firewall_ip_list.png b/docs/img/hosts/firewall_ip_list.png
similarity index 100%
rename from v1/img/hosts/firewall_ip_list.png
rename to docs/img/hosts/firewall_ip_list.png
diff --git a/v1/img/hosts/firewall_ping.png b/docs/img/hosts/firewall_ping.png
similarity index 100%
rename from v1/img/hosts/firewall_ping.png
rename to docs/img/hosts/firewall_ping.png
diff --git a/v1/img/hosts/firewall_port_create.png b/docs/img/hosts/firewall_port_create.png
similarity index 100%
rename from v1/img/hosts/firewall_port_create.png
rename to docs/img/hosts/firewall_port_create.png
diff --git a/v1/img/hosts/firewall_port_forward.png b/docs/img/hosts/firewall_port_forward.png
similarity index 100%
rename from v1/img/hosts/firewall_port_forward.png
rename to docs/img/hosts/firewall_port_forward.png
diff --git a/v1/img/hosts/firewall_port_list.png b/docs/img/hosts/firewall_port_list.png
similarity index 100%
rename from v1/img/hosts/firewall_port_list.png
rename to docs/img/hosts/firewall_port_list.png
diff --git a/v1/img/hosts/firewall_switch.png b/docs/img/hosts/firewall_switch.png
similarity index 100%
rename from v1/img/hosts/firewall_switch.png
rename to docs/img/hosts/firewall_switch.png
diff --git a/v1/img/hosts/host.png b/docs/img/hosts/host.png
similarity index 100%
rename from v1/img/hosts/host.png
rename to docs/img/hosts/host.png
diff --git a/v1/img/hosts/monitor.png b/docs/img/hosts/monitor.png
similarity index 100%
rename from v1/img/hosts/monitor.png
rename to docs/img/hosts/monitor.png
diff --git a/v1/img/hosts/netstat.png b/docs/img/hosts/netstat.png
similarity index 100%
rename from v1/img/hosts/netstat.png
rename to docs/img/hosts/netstat.png
diff --git a/v1/img/hosts/processes.png b/docs/img/hosts/processes.png
similarity index 100%
rename from v1/img/hosts/processes.png
rename to docs/img/hosts/processes.png
diff --git a/v1/img/hosts/ssh_config.png b/docs/img/hosts/ssh_config.png
similarity index 100%
rename from v1/img/hosts/ssh_config.png
rename to docs/img/hosts/ssh_config.png
diff --git a/v1/img/hosts/ssh_log.png b/docs/img/hosts/ssh_log.png
similarity index 100%
rename from v1/img/hosts/ssh_log.png
rename to docs/img/hosts/ssh_log.png
diff --git a/v1/img/hosts/ssh_session.png b/docs/img/hosts/ssh_session.png
similarity index 100%
rename from v1/img/hosts/ssh_session.png
rename to docs/img/hosts/ssh_session.png
diff --git a/v1/img/hosts/supervisor_create.png b/docs/img/hosts/supervisor_create.png
similarity index 100%
rename from v1/img/hosts/supervisor_create.png
rename to docs/img/hosts/supervisor_create.png
diff --git a/v1/img/hosts/supervisor_init.png b/docs/img/hosts/supervisor_init.png
similarity index 100%
rename from v1/img/hosts/supervisor_init.png
rename to docs/img/hosts/supervisor_init.png
diff --git a/v1/img/hosts/supervisor_list.png b/docs/img/hosts/supervisor_list.png
similarity index 100%
rename from v1/img/hosts/supervisor_list.png
rename to docs/img/hosts/supervisor_list.png
diff --git a/v1/img/hosts/supervisor_operate.png b/docs/img/hosts/supervisor_operate.png
similarity index 100%
rename from v1/img/hosts/supervisor_operate.png
rename to docs/img/hosts/supervisor_operate.png
diff --git a/v1/img/hosts/supervisor_reinit.png b/docs/img/hosts/supervisor_reinit.png
similarity index 100%
rename from v1/img/hosts/supervisor_reinit.png
rename to docs/img/hosts/supervisor_reinit.png
diff --git a/v1/img/hosts/terminal.png b/docs/img/hosts/terminal.png
similarity index 100%
rename from v1/img/hosts/terminal.png
rename to docs/img/hosts/terminal.png
diff --git a/v1/img/installation/alibabacloud_computenest_deploy_1.jpg b/docs/img/installation/alibabacloud_computenest_deploy_1.jpg
similarity index 100%
rename from v1/img/installation/alibabacloud_computenest_deploy_1.jpg
rename to docs/img/installation/alibabacloud_computenest_deploy_1.jpg
diff --git a/v1/img/installation/alibabacloud_computenest_deploy_2.jpg b/docs/img/installation/alibabacloud_computenest_deploy_2.jpg
similarity index 100%
rename from v1/img/installation/alibabacloud_computenest_deploy_2.jpg
rename to docs/img/installation/alibabacloud_computenest_deploy_2.jpg
diff --git a/v1/img/installation/alibabacloud_computenest_deploy_3.jpg b/docs/img/installation/alibabacloud_computenest_deploy_3.jpg
similarity index 100%
rename from v1/img/installation/alibabacloud_computenest_deploy_3.jpg
rename to docs/img/installation/alibabacloud_computenest_deploy_3.jpg
diff --git "a/v1/img/installation/\346\243\200\346\237\245\346\233\264\346\226\260.png" "b/docs/img/installation/\346\243\200\346\237\245\346\233\264\346\226\260.png"
similarity index 100%
rename from "v1/img/installation/\346\243\200\346\237\245\346\233\264\346\226\260.png"
rename to "docs/img/installation/\346\243\200\346\237\245\346\233\264\346\226\260.png"
diff --git "a/v1/img/installation/\347\224\250\346\210\267\344\277\241\346\201\257.png" "b/docs/img/installation/\347\224\250\346\210\267\344\277\241\346\201\257.png"
similarity index 100%
rename from "v1/img/installation/\347\224\250\346\210\267\344\277\241\346\201\257.png"
rename to "docs/img/installation/\347\224\250\346\210\267\344\277\241\346\201\257.png"
diff --git "a/v1/img/installation/\350\205\276\350\256\257\344\272\221\344\272\221\345\272\224\347\224\250-\345\256\211\350\243\205\345\217\202\346\225\260.png" "b/docs/img/installation/\350\205\276\350\256\257\344\272\221\344\272\221\345\272\224\347\224\250-\345\256\211\350\243\205\345\217\202\346\225\260.png"
similarity index 100%
rename from "v1/img/installation/\350\205\276\350\256\257\344\272\221\344\272\221\345\272\224\347\224\250-\345\256\211\350\243\205\345\217\202\346\225\260.png"
rename to "docs/img/installation/\350\205\276\350\256\257\344\272\221\344\272\221\345\272\224\347\224\250-\345\256\211\350\243\205\345\217\202\346\225\260.png"
diff --git "a/v1/img/installation/\350\205\276\350\256\257\344\272\221\344\272\221\345\272\224\347\224\250-\345\272\224\347\224\250\344\277\241\346\201\257.png" "b/docs/img/installation/\350\205\276\350\256\257\344\272\221\344\272\221\345\272\224\347\224\250-\345\272\224\347\224\250\344\277\241\346\201\257.png"
similarity index 100%
rename from "v1/img/installation/\350\205\276\350\256\257\344\272\221\344\272\221\345\272\224\347\224\250-\345\272\224\347\224\250\344\277\241\346\201\257.png"
rename to "docs/img/installation/\350\205\276\350\256\257\344\272\221\344\272\221\345\272\224\347\224\250-\345\272\224\347\224\250\344\277\241\346\201\257.png"
diff --git "a/v1/img/installation/\350\205\276\350\256\257\344\272\221\344\272\221\345\272\224\347\224\250-\345\272\224\347\224\250\350\257\246\346\203\205.png" "b/docs/img/installation/\350\205\276\350\256\257\344\272\221\344\272\221\345\272\224\347\224\250-\345\272\224\347\224\250\350\257\246\346\203\205.png"
similarity index 100%
rename from "v1/img/installation/\350\205\276\350\256\257\344\272\221\344\272\221\345\272\224\347\224\250-\345\272\224\347\224\250\350\257\246\346\203\205.png"
rename to "docs/img/installation/\350\205\276\350\256\257\344\272\221\344\272\221\345\272\224\347\224\250-\345\272\224\347\224\250\350\257\246\346\203\205.png"
diff --git "a/v1/img/installation/\350\205\276\350\256\257\344\272\221\344\272\221\345\272\224\347\224\250-\350\256\242\345\215\225\347\241\256\350\256\244.png" "b/docs/img/installation/\350\205\276\350\256\257\344\272\221\344\272\221\345\272\224\347\224\250-\350\256\242\345\215\225\347\241\256\350\256\244.png"
similarity index 100%
rename from "v1/img/installation/\350\205\276\350\256\257\344\272\221\344\272\221\345\272\224\347\224\250-\350\256\242\345\215\225\347\241\256\350\256\244.png"
rename to "docs/img/installation/\350\205\276\350\256\257\344\272\221\344\272\221\345\272\224\347\224\250-\350\256\242\345\215\225\347\241\256\350\256\244.png"
diff --git "a/v1/img/installation/\350\275\273\351\207\217\345\272\224\347\224\250\346\234\215\345\212\241\345\231\250-\345\272\224\347\224\250\347\256\241\347\220\206.png" "b/docs/img/installation/\350\275\273\351\207\217\345\272\224\347\224\250\346\234\215\345\212\241\345\231\250-\345\272\224\347\224\250\347\256\241\347\220\206.png"
similarity index 100%
rename from "v1/img/installation/\350\275\273\351\207\217\345\272\224\347\224\250\346\234\215\345\212\241\345\231\250-\345\272\224\347\224\250\347\256\241\347\220\206.png"
rename to "docs/img/installation/\350\275\273\351\207\217\345\272\224\347\224\250\346\234\215\345\212\241\345\231\250-\345\272\224\347\224\250\347\256\241\347\220\206.png"
diff --git "a/v1/img/installation/\350\275\273\351\207\217\345\272\224\347\224\250\346\234\215\345\212\241\345\231\250-\346\237\245\347\234\213\347\231\273\345\275\225\344\277\241\346\201\257.png" "b/docs/img/installation/\350\275\273\351\207\217\345\272\224\347\224\250\346\234\215\345\212\241\345\231\250-\346\237\245\347\234\213\347\231\273\345\275\225\344\277\241\346\201\257.png"
similarity index 100%
rename from "v1/img/installation/\350\275\273\351\207\217\345\272\224\347\224\250\346\234\215\345\212\241\345\231\250-\346\237\245\347\234\213\347\231\273\345\275\225\344\277\241\346\201\257.png"
rename to "docs/img/installation/\350\275\273\351\207\217\345\272\224\347\224\250\346\234\215\345\212\241\345\231\250-\346\237\245\347\234\213\347\231\273\345\275\225\344\277\241\346\201\257.png"
diff --git "a/v1/img/installation/\350\275\273\351\207\217\345\272\224\347\224\250\346\234\215\345\212\241\345\231\250-\351\230\262\347\201\253\345\242\231.png" "b/docs/img/installation/\350\275\273\351\207\217\345\272\224\347\224\250\346\234\215\345\212\241\345\231\250-\351\230\262\347\201\253\345\242\231.png"
similarity index 100%
rename from "v1/img/installation/\350\275\273\351\207\217\345\272\224\347\224\250\346\234\215\345\212\241\345\231\250-\351\230\262\347\201\253\345\242\231.png"
rename to "docs/img/installation/\350\275\273\351\207\217\345\272\224\347\224\250\346\234\215\345\212\241\345\231\250-\351\230\262\347\201\253\345\242\231.png"
diff --git a/v1/img/logo-white.png b/docs/img/logo-white.png
similarity index 100%
rename from v1/img/logo-white.png
rename to docs/img/logo-white.png
diff --git "a/v1/img/logs/\347\231\273\345\275\225\346\227\245\345\277\227.png" "b/docs/img/logs/\347\231\273\345\275\225\346\227\245\345\277\227.png"
similarity index 100%
rename from "v1/img/logs/\347\231\273\345\275\225\346\227\245\345\277\227.png"
rename to "docs/img/logs/\347\231\273\345\275\225\346\227\245\345\277\227.png"
diff --git "a/v1/img/logs/\347\275\221\347\253\231\346\227\245\345\277\227-\350\277\220\350\241\214\346\227\245\345\277\227.png" "b/docs/img/logs/\347\275\221\347\253\231\346\227\245\345\277\227-\350\277\220\350\241\214\346\227\245\345\277\227.png"
similarity index 100%
rename from "v1/img/logs/\347\275\221\347\253\231\346\227\245\345\277\227-\350\277\220\350\241\214\346\227\245\345\277\227.png"
rename to "docs/img/logs/\347\275\221\347\253\231\346\227\245\345\277\227-\350\277\220\350\241\214\346\227\245\345\277\227.png"
diff --git "a/v1/img/logs/\347\275\221\347\253\231\346\227\245\345\277\227-\351\224\231\350\257\257\346\227\245\345\277\227.png" "b/docs/img/logs/\347\275\221\347\253\231\346\227\245\345\277\227-\351\224\231\350\257\257\346\227\245\345\277\227.png"
similarity index 100%
rename from "v1/img/logs/\347\275\221\347\253\231\346\227\245\345\277\227-\351\224\231\350\257\257\346\227\245\345\277\227.png"
rename to "docs/img/logs/\347\275\221\347\253\231\346\227\245\345\277\227-\351\224\231\350\257\257\346\227\245\345\277\227.png"
diff --git "a/v1/img/logs/\351\235\242\346\235\277\346\227\245\345\277\227-\346\223\215\344\275\234\346\227\245\345\277\227.png" "b/docs/img/logs/\351\235\242\346\235\277\346\227\245\345\277\227-\346\223\215\344\275\234\346\227\245\345\277\227.png"
similarity index 100%
rename from "v1/img/logs/\351\235\242\346\235\277\346\227\245\345\277\227-\346\223\215\344\275\234\346\227\245\345\277\227.png"
rename to "docs/img/logs/\351\235\242\346\235\277\346\227\245\345\277\227-\346\223\215\344\275\234\346\227\245\345\277\227.png"
diff --git "a/v1/img/logs/\351\235\242\346\235\277\346\227\245\345\277\227-\347\263\273\347\273\237\346\227\245\345\277\227.png" "b/docs/img/logs/\351\235\242\346\235\277\346\227\245\345\277\227-\347\263\273\347\273\237\346\227\245\345\277\227.png"
similarity index 100%
rename from "v1/img/logs/\351\235\242\346\235\277\346\227\245\345\277\227-\347\263\273\347\273\237\346\227\245\345\277\227.png"
rename to "docs/img/logs/\351\235\242\346\235\277\346\227\245\345\277\227-\347\263\273\347\273\237\346\227\245\345\277\227.png"
diff --git "a/v1/img/logs/\351\235\242\346\235\277\346\227\245\345\277\227-\350\256\277\351\227\256\346\227\245\345\277\227.png" "b/docs/img/logs/\351\235\242\346\235\277\346\227\245\345\277\227-\350\256\277\351\227\256\346\227\245\345\277\227.png"
similarity index 100%
rename from "v1/img/logs/\351\235\242\346\235\277\346\227\245\345\277\227-\350\256\277\351\227\256\346\227\245\345\277\227.png"
rename to "docs/img/logs/\351\235\242\346\235\277\346\227\245\345\277\227-\350\256\277\351\227\256\346\227\245\345\277\227.png"
diff --git a/v1/img/settings/about.png b/docs/img/settings/about.png
similarity index 100%
rename from v1/img/settings/about.png
rename to docs/img/settings/about.png
diff --git a/v1/img/settings/onedrive_custom1.png b/docs/img/settings/onedrive_custom1.png
similarity index 100%
rename from v1/img/settings/onedrive_custom1.png
rename to docs/img/settings/onedrive_custom1.png
diff --git a/v1/img/settings/onedrive_custom2.png b/docs/img/settings/onedrive_custom2.png
similarity index 100%
rename from v1/img/settings/onedrive_custom2.png
rename to docs/img/settings/onedrive_custom2.png
diff --git a/v1/img/settings/onedrive_custom3.png b/docs/img/settings/onedrive_custom3.png
similarity index 100%
rename from v1/img/settings/onedrive_custom3.png
rename to docs/img/settings/onedrive_custom3.png
diff --git a/v1/img/settings/onedrive_custom4.png b/docs/img/settings/onedrive_custom4.png
similarity index 100%
rename from v1/img/settings/onedrive_custom4.png
rename to docs/img/settings/onedrive_custom4.png
diff --git a/v1/img/settings/onedrive_step1.png b/docs/img/settings/onedrive_step1.png
similarity index 100%
rename from v1/img/settings/onedrive_step1.png
rename to docs/img/settings/onedrive_step1.png
diff --git a/v1/img/settings/onedrive_step2.png b/docs/img/settings/onedrive_step2.png
similarity index 100%
rename from v1/img/settings/onedrive_step2.png
rename to docs/img/settings/onedrive_step2.png
diff --git a/v1/img/settings/onedrive_step3.png b/docs/img/settings/onedrive_step3.png
similarity index 100%
rename from v1/img/settings/onedrive_step3.png
rename to docs/img/settings/onedrive_step3.png
diff --git a/v1/img/settings/onedrive_step4.png b/docs/img/settings/onedrive_step4.png
similarity index 100%
rename from v1/img/settings/onedrive_step4.png
rename to docs/img/settings/onedrive_step4.png
diff --git a/v1/img/settings/panel.png b/docs/img/settings/panel.png
similarity index 100%
rename from v1/img/settings/panel.png
rename to docs/img/settings/panel.png
diff --git a/v1/img/settings/security.png b/docs/img/settings/security.png
similarity index 100%
rename from v1/img/settings/security.png
rename to docs/img/settings/security.png
diff --git a/v1/img/settings/snapshot.png b/docs/img/settings/snapshot.png
similarity index 100%
rename from v1/img/settings/snapshot.png
rename to docs/img/settings/snapshot.png
diff --git a/v1/img/settings/webdav-01.png b/docs/img/settings/webdav-01.png
similarity index 100%
rename from v1/img/settings/webdav-01.png
rename to docs/img/settings/webdav-01.png
diff --git a/v1/img/settings/webdav-02.png b/docs/img/settings/webdav-02.png
similarity index 100%
rename from v1/img/settings/webdav-02.png
rename to docs/img/settings/webdav-02.png
diff --git a/v1/img/toolbox/clam_create_rule.png b/docs/img/toolbox/clam_create_rule.png
similarity index 100%
rename from v1/img/toolbox/clam_create_rule.png
rename to docs/img/toolbox/clam_create_rule.png
diff --git a/v1/img/toolbox/clean.png b/docs/img/toolbox/clean.png
similarity index 100%
rename from v1/img/toolbox/clean.png
rename to docs/img/toolbox/clean.png
diff --git a/v1/img/toolbox/quick_settings.png b/docs/img/toolbox/quick_settings.png
similarity index 100%
rename from v1/img/toolbox/quick_settings.png
rename to docs/img/toolbox/quick_settings.png
diff --git a/v1/img/waf/404.png b/docs/img/waf/404.png
similarity index 100%
rename from v1/img/waf/404.png
rename to docs/img/waf/404.png
diff --git a/v1/img/waf/acl.png b/docs/img/waf/acl.png
similarity index 100%
rename from v1/img/waf/acl.png
rename to docs/img/waf/acl.png
diff --git a/v1/img/waf/attack_cc.png b/docs/img/waf/attack_cc.png
similarity index 100%
rename from v1/img/waf/attack_cc.png
rename to docs/img/waf/attack_cc.png
diff --git a/v1/img/waf/block.png b/docs/img/waf/block.png
similarity index 100%
rename from v1/img/waf/block.png
rename to docs/img/waf/block.png
diff --git a/v1/img/waf/cc.png b/docs/img/waf/cc.png
similarity index 100%
rename from v1/img/waf/cc.png
rename to docs/img/waf/cc.png
diff --git a/v1/img/waf/cdn.png b/docs/img/waf/cdn.png
similarity index 100%
rename from v1/img/waf/cdn.png
rename to docs/img/waf/cdn.png
diff --git a/v1/img/waf/dashboard.png b/docs/img/waf/dashboard.png
similarity index 100%
rename from v1/img/waf/dashboard.png
rename to docs/img/waf/dashboard.png
diff --git a/v1/img/waf/ext.png b/docs/img/waf/ext.png
similarity index 100%
rename from v1/img/waf/ext.png
rename to docs/img/waf/ext.png
diff --git a/v1/img/waf/global.png b/docs/img/waf/global.png
similarity index 100%
rename from v1/img/waf/global.png
rename to docs/img/waf/global.png
diff --git a/v1/img/waf/html.png b/docs/img/waf/html.png
similarity index 100%
rename from v1/img/waf/html.png
rename to docs/img/waf/html.png
diff --git a/v1/img/waf/location.png b/docs/img/waf/location.png
similarity index 100%
rename from v1/img/waf/location.png
rename to docs/img/waf/location.png
diff --git a/v1/img/waf/log.png b/docs/img/waf/log.png
similarity index 100%
rename from v1/img/waf/log.png
rename to docs/img/waf/log.png
diff --git a/v1/img/waf/site.png b/docs/img/waf/site.png
similarity index 100%
rename from v1/img/waf/site.png
rename to docs/img/waf/site.png
diff --git a/v1/img/websites/auto_create.png b/docs/img/websites/auto_create.png
similarity index 100%
rename from v1/img/websites/auto_create.png
rename to docs/img/websites/auto_create.png
diff --git a/v1/img/websites/backup_list.png b/docs/img/websites/backup_list.png
similarity index 100%
rename from v1/img/websites/backup_list.png
rename to docs/img/websites/backup_list.png
diff --git a/v1/img/websites/basic_config_default.png b/docs/img/websites/basic_config_default.png
similarity index 100%
rename from v1/img/websites/basic_config_default.png
rename to docs/img/websites/basic_config_default.png
diff --git a/v1/img/websites/basic_config_https.png b/docs/img/websites/basic_config_https.png
similarity index 100%
rename from v1/img/websites/basic_config_https.png
rename to docs/img/websites/basic_config_https.png
diff --git a/v1/img/websites/basic_config_limit.png b/docs/img/websites/basic_config_limit.png
similarity index 100%
rename from v1/img/websites/basic_config_limit.png
rename to docs/img/websites/basic_config_limit.png
diff --git a/v1/img/websites/basic_config_other.png b/docs/img/websites/basic_config_other.png
similarity index 100%
rename from v1/img/websites/basic_config_other.png
rename to docs/img/websites/basic_config_other.png
diff --git a/v1/img/websites/basic_config_password.png b/docs/img/websites/basic_config_password.png
similarity index 100%
rename from v1/img/websites/basic_config_password.png
rename to docs/img/websites/basic_config_password.png
diff --git a/v1/img/websites/basic_config_protection.png b/docs/img/websites/basic_config_protection.png
similarity index 100%
rename from v1/img/websites/basic_config_protection.png
rename to docs/img/websites/basic_config_protection.png
diff --git a/v1/img/websites/basic_config_proxy.png b/docs/img/websites/basic_config_proxy.png
similarity index 100%
rename from v1/img/websites/basic_config_proxy.png
rename to docs/img/websites/basic_config_proxy.png
diff --git a/v1/img/websites/basic_config_redirect.png b/docs/img/websites/basic_config_redirect.png
similarity index 100%
rename from v1/img/websites/basic_config_redirect.png
rename to docs/img/websites/basic_config_redirect.png
diff --git a/v1/img/websites/basic_config_static.png b/docs/img/websites/basic_config_static.png
similarity index 100%
rename from v1/img/websites/basic_config_static.png
rename to docs/img/websites/basic_config_static.png
diff --git a/v1/img/websites/certificate_acme.png b/docs/img/websites/certificate_acme.png
similarity index 100%
rename from v1/img/websites/certificate_acme.png
rename to docs/img/websites/certificate_acme.png
diff --git a/v1/img/websites/certificate_create.png b/docs/img/websites/certificate_create.png
similarity index 100%
rename from v1/img/websites/certificate_create.png
rename to docs/img/websites/certificate_create.png
diff --git a/v1/img/websites/certificate_dns.png b/docs/img/websites/certificate_dns.png
similarity index 100%
rename from v1/img/websites/certificate_dns.png
rename to docs/img/websites/certificate_dns.png
diff --git a/v1/img/websites/certificate_dns_aliyun.png b/docs/img/websites/certificate_dns_aliyun.png
similarity index 100%
rename from v1/img/websites/certificate_dns_aliyun.png
rename to docs/img/websites/certificate_dns_aliyun.png
diff --git a/v1/img/websites/certificate_dns_cloudflare.png b/docs/img/websites/certificate_dns_cloudflare.png
similarity index 100%
rename from v1/img/websites/certificate_dns_cloudflare.png
rename to docs/img/websites/certificate_dns_cloudflare.png
diff --git a/v1/img/websites/certificate_dns_dnspod.png b/docs/img/websites/certificate_dns_dnspod.png
similarity index 100%
rename from v1/img/websites/certificate_dns_dnspod.png
rename to docs/img/websites/certificate_dns_dnspod.png
diff --git a/v1/img/websites/certificate_list.png b/docs/img/websites/certificate_list.png
similarity index 100%
rename from v1/img/websites/certificate_list.png
rename to docs/img/websites/certificate_list.png
diff --git a/v1/img/websites/certificate_renew.png b/docs/img/websites/certificate_renew.png
similarity index 100%
rename from v1/img/websites/certificate_renew.png
rename to docs/img/websites/certificate_renew.png
diff --git a/v1/img/websites/config_basic_domain.png b/docs/img/websites/config_basic_domain.png
similarity index 100%
rename from v1/img/websites/config_basic_domain.png
rename to docs/img/websites/config_basic_domain.png
diff --git a/v1/img/websites/config_basic_folder.png b/docs/img/websites/config_basic_folder.png
similarity index 100%
rename from v1/img/websites/config_basic_folder.png
rename to docs/img/websites/config_basic_folder.png
diff --git a/v1/img/websites/cookie_black.png b/docs/img/websites/cookie_black.png
similarity index 100%
rename from v1/img/websites/cookie_black.png
rename to docs/img/websites/cookie_black.png
diff --git a/v1/img/websites/default_group.png b/docs/img/websites/default_group.png
similarity index 100%
rename from v1/img/websites/default_group.png
rename to docs/img/websites/default_group.png
diff --git a/v1/img/websites/edit_group.png b/docs/img/websites/edit_group.png
similarity index 100%
rename from v1/img/websites/edit_group.png
rename to docs/img/websites/edit_group.png
diff --git a/v1/img/websites/ext_block.png b/docs/img/websites/ext_block.png
similarity index 100%
rename from v1/img/websites/ext_block.png
rename to docs/img/websites/ext_block.png
diff --git a/v1/img/websites/get_check.png b/docs/img/websites/get_check.png
similarity index 100%
rename from v1/img/websites/get_check.png
rename to docs/img/websites/get_check.png
diff --git a/v1/img/websites/ip_black.png b/docs/img/websites/ip_black.png
similarity index 100%
rename from v1/img/websites/ip_black.png
rename to docs/img/websites/ip_black.png
diff --git a/v1/img/websites/ip_white.png b/docs/img/websites/ip_white.png
similarity index 100%
rename from v1/img/websites/ip_white.png
rename to docs/img/websites/ip_white.png
diff --git a/v1/img/websites/log.png b/docs/img/websites/log.png
similarity index 100%
rename from v1/img/websites/log.png
rename to docs/img/websites/log.png
diff --git a/v1/img/websites/openresty_clear_cache.png b/docs/img/websites/openresty_clear_cache.png
similarity index 100%
rename from v1/img/websites/openresty_clear_cache.png
rename to docs/img/websites/openresty_clear_cache.png
diff --git a/v1/img/websites/openresty_conf.png b/docs/img/websites/openresty_conf.png
similarity index 100%
rename from v1/img/websites/openresty_conf.png
rename to docs/img/websites/openresty_conf.png
diff --git a/v1/img/websites/openresty_log.png b/docs/img/websites/openresty_log.png
similarity index 100%
rename from v1/img/websites/openresty_log.png
rename to docs/img/websites/openresty_log.png
diff --git a/v1/img/websites/openresty_performance.png b/docs/img/websites/openresty_performance.png
similarity index 100%
rename from v1/img/websites/openresty_performance.png
rename to docs/img/websites/openresty_performance.png
diff --git a/v1/img/websites/openresty_reload.png b/docs/img/websites/openresty_reload.png
similarity index 100%
rename from v1/img/websites/openresty_reload.png
rename to docs/img/websites/openresty_reload.png
diff --git a/v1/img/websites/openresty_setting.png b/docs/img/websites/openresty_setting.png
similarity index 100%
rename from v1/img/websites/openresty_setting.png
rename to docs/img/websites/openresty_setting.png
diff --git a/v1/img/websites/openresty_status.png b/docs/img/websites/openresty_status.png
similarity index 100%
rename from v1/img/websites/openresty_status.png
rename to docs/img/websites/openresty_status.png
diff --git a/v1/img/websites/post_check.png b/docs/img/websites/post_check.png
similarity index 100%
rename from v1/img/websites/post_check.png
rename to docs/img/websites/post_check.png
diff --git a/v1/img/websites/proxy_create.png b/docs/img/websites/proxy_create.png
similarity index 100%
rename from v1/img/websites/proxy_create.png
rename to docs/img/websites/proxy_create.png
diff --git a/v1/img/websites/runtime_create.png b/docs/img/websites/runtime_create.png
similarity index 100%
rename from v1/img/websites/runtime_create.png
rename to docs/img/websites/runtime_create.png
diff --git a/v1/img/websites/runtime_dotnet_create.png b/docs/img/websites/runtime_dotnet_create.png
similarity index 100%
rename from v1/img/websites/runtime_dotnet_create.png
rename to docs/img/websites/runtime_dotnet_create.png
diff --git a/v1/img/websites/runtime_dotnet_list.png b/docs/img/websites/runtime_dotnet_list.png
similarity index 100%
rename from v1/img/websites/runtime_dotnet_list.png
rename to docs/img/websites/runtime_dotnet_list.png
diff --git a/v1/img/websites/runtime_golang_create.png b/docs/img/websites/runtime_golang_create.png
similarity index 100%
rename from v1/img/websites/runtime_golang_create.png
rename to docs/img/websites/runtime_golang_create.png
diff --git a/v1/img/websites/runtime_golang_list.png b/docs/img/websites/runtime_golang_list.png
similarity index 100%
rename from v1/img/websites/runtime_golang_list.png
rename to docs/img/websites/runtime_golang_list.png
diff --git a/v1/img/websites/runtime_java_create.png b/docs/img/websites/runtime_java_create.png
similarity index 100%
rename from v1/img/websites/runtime_java_create.png
rename to docs/img/websites/runtime_java_create.png
diff --git a/v1/img/websites/runtime_java_list.png b/docs/img/websites/runtime_java_list.png
similarity index 100%
rename from v1/img/websites/runtime_java_list.png
rename to docs/img/websites/runtime_java_list.png
diff --git a/v1/img/websites/runtime_java_log.png b/docs/img/websites/runtime_java_log.png
similarity index 100%
rename from v1/img/websites/runtime_java_log.png
rename to docs/img/websites/runtime_java_log.png
diff --git a/v1/img/websites/runtime_list.png b/docs/img/websites/runtime_list.png
similarity index 100%
rename from v1/img/websites/runtime_list.png
rename to docs/img/websites/runtime_list.png
diff --git a/v1/img/websites/runtime_node_create.png b/docs/img/websites/runtime_node_create.png
similarity index 100%
rename from v1/img/websites/runtime_node_create.png
rename to docs/img/websites/runtime_node_create.png
diff --git a/v1/img/websites/runtime_node_list.png b/docs/img/websites/runtime_node_list.png
similarity index 100%
rename from v1/img/websites/runtime_node_list.png
rename to docs/img/websites/runtime_node_list.png
diff --git a/v1/img/websites/runtime_node_log.png b/docs/img/websites/runtime_node_log.png
similarity index 100%
rename from v1/img/websites/runtime_node_log.png
rename to docs/img/websites/runtime_node_log.png
diff --git a/v1/img/websites/runtime_node_module.png b/docs/img/websites/runtime_node_module.png
similarity index 100%
rename from v1/img/websites/runtime_node_module.png
rename to docs/img/websites/runtime_node_module.png
diff --git a/v1/img/websites/runtime_python_create.png b/docs/img/websites/runtime_python_create.png
similarity index 100%
rename from v1/img/websites/runtime_python_create.png
rename to docs/img/websites/runtime_python_create.png
diff --git a/v1/img/websites/runtime_python_list.png b/docs/img/websites/runtime_python_list.png
similarity index 100%
rename from v1/img/websites/runtime_python_list.png
rename to docs/img/websites/runtime_python_list.png
diff --git a/v1/img/websites/static_create.png b/docs/img/websites/static_create.png
similarity index 100%
rename from v1/img/websites/static_create.png
rename to docs/img/websites/static_create.png
diff --git a/v1/img/websites/url_black.png b/docs/img/websites/url_black.png
similarity index 100%
rename from v1/img/websites/url_black.png
rename to docs/img/websites/url_black.png
diff --git a/v1/img/websites/url_white.png b/docs/img/websites/url_white.png
similarity index 100%
rename from v1/img/websites/url_white.png
rename to docs/img/websites/url_white.png
diff --git a/v1/img/websites/waf_cc.png b/docs/img/websites/waf_cc.png
similarity index 100%
rename from v1/img/websites/waf_cc.png
rename to docs/img/websites/waf_cc.png
diff --git a/v1/img/websites/web_expire.png b/docs/img/websites/web_expire.png
similarity index 100%
rename from v1/img/websites/web_expire.png
rename to docs/img/websites/web_expire.png
diff --git a/v1/img/websites/web_openresty.png b/docs/img/websites/web_openresty.png
similarity index 100%
rename from v1/img/websites/web_openresty.png
rename to docs/img/websites/web_openresty.png
diff --git a/v1/img/websites/web_php.png b/docs/img/websites/web_php.png
similarity index 100%
rename from v1/img/websites/web_php.png
rename to docs/img/websites/web_php.png
diff --git a/v1/img/websites/website.png b/docs/img/websites/website.png
similarity index 100%
rename from v1/img/websites/website.png
rename to docs/img/websites/website.png
diff --git a/v1/img/websites/website_bak_download.png b/docs/img/websites/website_bak_download.png
similarity index 100%
rename from v1/img/websites/website_bak_download.png
rename to docs/img/websites/website_bak_download.png
diff --git a/v1/img/websites/website_bak_import.png b/docs/img/websites/website_bak_import.png
similarity index 100%
rename from v1/img/websites/website_bak_import.png
rename to docs/img/websites/website_bak_import.png
diff --git a/v1/img/websites/website_default.png b/docs/img/websites/website_default.png
similarity index 100%
rename from v1/img/websites/website_default.png
rename to docs/img/websites/website_default.png
diff --git a/v1/img/websites/website_del.png b/docs/img/websites/website_del.png
similarity index 100%
rename from v1/img/websites/website_del.png
rename to docs/img/websites/website_del.png
diff --git a/v1/img/websites/website_group.png b/docs/img/websites/website_group.png
similarity index 100%
rename from v1/img/websites/website_group.png
rename to docs/img/websites/website_group.png
diff --git a/v1/img/websites/website_restore.png b/docs/img/websites/website_restore.png
similarity index 100%
rename from v1/img/websites/website_restore.png
rename to docs/img/websites/website_restore.png
diff --git a/v1/img/websites/website_runtime_create.png b/docs/img/websites/website_runtime_create.png
similarity index 100%
rename from v1/img/websites/website_runtime_create.png
rename to docs/img/websites/website_runtime_create.png
diff --git a/v1/img/websites/website_start.png b/docs/img/websites/website_start.png
similarity index 100%
rename from v1/img/websites/website_start.png
rename to docs/img/websites/website_start.png
diff --git a/v1/img/wechat-group.png b/docs/img/wechat-group.png
similarity index 100%
rename from v1/img/wechat-group.png
rename to docs/img/wechat-group.png
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 00000000..2aadf05d
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,21 @@
+
+!!! note ""
+ 1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。
+
+
+
+## 1 产品优势
+
+!!! note ""
+
+ - **高效管理**:用户可以通过 Web 图形界面轻松管理 Linux 服务器,实现主机监控、文件管理、数据库管理、容器管理等功能;
+ - **快速建站**:深度集成开源建站软件 WordPress 和 [Halo](https://github.com/halo-dev/halo/),域名绑定、SSL 证书配置等操作一键搞定;
+ - **应用商店**:精选上架各类高质量的开源工具和应用软件,协助用户轻松安装并升级;
+ - **安全可靠**:基于容器管理并部署应用,实现最小的漏洞暴露面,同时提供防火墙和日志审计等功能;
+ - **一键备份**:支持一键备份和恢复,用户可以将数据备份到各类云端存储介质,永不丢失。
+
+## 2 教学视频
+
+!!! note ""
+
+ 您可以在哔哩哔哩(B 站)上搜索相关教学视频。[点击这里](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760)
\ No newline at end of file
diff --git a/docs/installation/.DS_Store b/docs/installation/.DS_Store
new file mode 100644
index 00000000..5008ddfc
Binary files /dev/null and b/docs/installation/.DS_Store differ
diff --git a/docs/installation/ali_cloud.md b/docs/installation/ali_cloud.md
new file mode 100644
index 00000000..06652c78
--- /dev/null
+++ b/docs/installation/ali_cloud.md
@@ -0,0 +1,41 @@
+# 云市场部署指南
+
+!!! note ""
+ 本指南将介绍如何通过阿里云云市场购买、部署和使用 **1Panel** 镜像,并提供购买服务器的优惠链接。
+
+## 1 购买镜像
+
+!!! note ""
+ - 1Panel 已经上架到阿里云云市场,您可以通过 [阿里云市场 · 1Panel 社区版镜像](https://market.aliyun.com/products/53690006/cmjj00062740.html?userCode=kmemb8jp) 直接购买。
+ - 您也可以自行购买阿里云服务器,并在选择镜像时搜索 **1Panel**,即可快速选择镜像进行部署。
+
+!!! note "服务器优惠"
+ 如果您还没有服务器,可以通过以下优惠链接购买阿里云服务器:
+
+ - [1Panel 专属阿里云特价链接 5.5 折优惠!](https://market.aliyun.com/common/dashi/1panel?userCode=kmemb8jp)
+
+## 2 开放端口
+
+!!! note ""
+ - 为了确保外部能够正常访问 1Panel 服务,您需要在阿里云服务器的安全组规则中开放 `8080` 端口。
+ - 具体的开放步骤可以参考阿里云的 [端口放行教程](https://help.aliyun.com/document_detail/25471.html)。
+
+## 3. 使用步骤
+
+### 3.1 获取面板用户信息
+
+!!! note ""
+ - 执行命令 `1pctl user-info` 来获取默认的用户信息。
+ - 输入命令并按回车,即可查看面板的用户名和密码。
+
+### 3.2 访问面板
+
+!!! note ""
+ - 通过以下格式的 URL 访问面板管理页面:`http://服务器外网IP:8090/安全入口`。例如:`http://172.16.10.1:8090/mm4h9iucdn`
+ - 在登录页面中输入获取的默认帐号和密码。
+
+### 3.3 面板设置
+
+!!! note ""
+ - 建议首次登录后立即修改默认的帐号和密码,以确保系统安全。
+ - 完成设置后,您可以开始使用面板进行管理和操作。
diff --git a/docs/installation/alibaba-cloud-computenest.md b/docs/installation/alibaba-cloud-computenest.md
new file mode 100644
index 00000000..80294dc2
--- /dev/null
+++ b/docs/installation/alibaba-cloud-computenest.md
@@ -0,0 +1,24 @@
+# 计算巢部署指南
+
+!!! note ""
+ 阿里云计算巢提供了软件与资源的一体化交付的完善基础能力,助力服务商、开发者的提升服务能力和降低运营成本。计算巢已经支持快速部署 1Panel 社区版。
+
+## 部署流程
+
+!!! note ""
+ 单击[部署链接](https://computenest.console.aliyun.com/service/instance/create/default?type=user&ServiceName=1panel%E8%BF%90%E7%BB%B4%E9%9D%A2%E6%9D%BF%E7%A4%BE%E5%8C%BA%E7%89%88),进入服务实例部署界面。
+
+!!! note ""
+ 选择新建ECS实例并根据界面提示配置参数,配置完成后点击下一步:确认订单。
+
+
+
+!!! note ""
+ 点击立即创建,等待服务实例创建完成。
+
+
+
+!!! note ""
+ 服务实例创建成功后,进入服务实例详情页。在概览页可获取1Panel面板登录信息,点击外网面板地址,登录1Panel面板。
+
+
diff --git a/docs/installation/cli.md b/docs/installation/cli.md
new file mode 100644
index 00000000..6233d699
--- /dev/null
+++ b/docs/installation/cli.md
@@ -0,0 +1,93 @@
+
+## 1 1pctl
+
+!!! note ""
+ 1Panel 默认内置了命令行运维工具 **1pctl**,通过执行 1pctl help,可以查看相关的命令说明。
+
+ ```
+ Usage:
+ 1pctl [COMMAND] [ARGS...]
+ 1pctl --help
+
+ Commands:
+ status 查看 1Panel 服务运行状态
+ start 启动 1Panel 服务
+ stop 停止 1Panel 服务
+ restart 重启 1Panel 服务
+ uninstall 卸载 1Panel 服务
+ user-info 获取 1Panel 用户信息
+ listen-ip 切换 1Panel 监听 IP
+ version 查看 1Panel 版本信息
+ update 修改 1Panel 系统信息
+ reset 重置 1Panel 系统信息
+ restore 恢复 1Panel 服务及数据
+ ```
+
+## 2 1pctl reset
+
+!!! note ""
+ **重置 1Panel 系统信息,包括取消安全入口登录,取消两步验证等**
+
+ ```
+ Usage:
+ 1pctl reset [COMMAND] [ARGS...]
+ 1pctl reset --help
+
+ Commands:
+ domain 取消 1Panel 访问域名绑定
+ entrance 取消 1Panel 安全入口
+ https 取消 1Panel https 方式登录
+ ips 取消 1Panel 授权 IP 限制
+ mfa 取消 1Panel 两步验证
+ ```
+
+## 3 1pctl listen-ip
+
+!!! note ""
+ **修改 1Panel 监听 IP**
+
+ ```
+ Usage:
+ 1pctl listen-ip [COMMAND] [ARGS...]
+ 1pctl listen-ip --help
+
+ Commands:
+ ipv4 监听 IPv4
+ ipv6 监听 IPv6
+ ```
+
+## 4 1pctl update
+
+!!! note ""
+ **修改 1Panel 系统信息**
+
+ ```
+ Usage:
+ 1pctl update [COMMAND] [ARGS...]
+ 1pctl update --help
+
+ Commands:
+ username 修改面板用户
+ password 修改面板密码
+ port 修改面板端口
+ ```
+
+## 5 1panel app
+
+!!! note ""
+ **应用商店相关命令,包括初始化应用等**
+
+ ```
+ Usage:
+ 1panel app [COMMAND] [ARGS...]
+ 1panel app --help
+
+ Commands:
+ init 初始化应用
+ ```
+
+> 创建应用名为 `app_name`,版本为 `v1.0.0` 的应用,命令如下:
+
+```bash
+1panel app init -k app_name -v v1.0.0
+```
diff --git a/docs/installation/online_installation.md b/docs/installation/online_installation.md
new file mode 100644
index 00000000..47fb8221
--- /dev/null
+++ b/docs/installation/online_installation.md
@@ -0,0 +1,75 @@
+## 1 环境要求
+
+!!! note ""
+ **安装前请确保您的系统符合安装条件:**
+
+ - 操作系统:支持主流 Linux 发行版本(基于 Debian / RedHat,包括国产操作系统);
+ - 服务器架构:x86_64、aarch64、armv7l、ppc64le、s390x;
+ - 内存要求:建议可用内存在 1GB 以上;
+ - 浏览器要求:请使用 Chrome、FireFox、IE10+、Edge等现代浏览器;
+ - **可访问互联网**。
+
+!!! note "服务器优惠"
+ 如果你还没有服务器,欢迎通过以下优惠链接选购。
+
+ - 阿里云:[专属阿里云特价链接 5.5 折优惠](https://market.aliyun.com/common/dashi/1panel?userCode=kmemb8jp);
+ - 腾讯云:[【腾讯云】2核2G3M云服务器7.92元/月起,2000元代金券免费领](https://curl.qcloud.com/dK2muFbM),更多云产品优惠请点击[此链接](https://curl.qcloud.com/9Ogon25Y);
+
+## 2 安装部署
+
+!!! note ""
+ GitHub release 链接: https://github.com/1Panel-dev/1Panel/releases
+
+=== "RedHat / CentOS"
+ !!! note ""
+ ```properties
+ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sh quick_start.sh
+ ```
+
+=== "Ubuntu"
+ !!! note ""
+ ```properties
+ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh
+ ```
+
+=== "Debian"
+ !!! note ""
+ ```properties
+ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && bash quick_start.sh
+ ```
+
+=== "openEuler / 其他"
+ !!! note ""
+ 第一步:安装 docker
+
+ ```properties
+ bash <(curl -sSL https://linuxmirrors.cn/docker.sh)
+ ```
+
+ 第二步:安装 1Panel
+
+ ```properties
+ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sh quick_start.sh
+ ```
+
+!!! note ""
+ 如果遇到 Docker 安装失败等问题,可以尝试运行以下脚本:
+
+ ```bash
+ bash <(curl -sSL https://linuxmirrors.cn/docker.sh)
+ ```
+
+ 了解更多信息,请访问官方网站:https://linuxmirrors.cn
+
+!!! note ""
+ 安装成功后,控制台会打印面板访问信息,可通过浏览器访问 1Panel:
+
+ ```
+ http://目标服务器 IP 地址:目标端口/安全入口
+ ```
+
+ - **如果使用的是云服务器,请至安全组开放目标端口。**
+ - **ssh 登录 1Panel 服务器后,执行 1pctl user-info 命令可获取安全入口(entrance)**
+
+!!! note ""
+ 安装成功后,可使用 [1pctl](cli.md) 命令行工具来维护 1Panel
diff --git a/docs/installation/online_upgrade.md b/docs/installation/online_upgrade.md
new file mode 100644
index 00000000..008c9928
--- /dev/null
+++ b/docs/installation/online_upgrade.md
@@ -0,0 +1,4 @@
+!!! note ""
+ 登录 1Panel Web 控制台,在页面右下角点击 **【检查更新】** 进行在线升级。
+
+{ width="900px" }
diff --git a/docs/installation/package_installation.md b/docs/installation/package_installation.md
new file mode 100644
index 00000000..f4534a07
--- /dev/null
+++ b/docs/installation/package_installation.md
@@ -0,0 +1,54 @@
+## 1 环境要求
+
+!!! note ""
+ **安装前请确保您的系统符合安装条件:**
+
+ - 操作系统:支持主流 Linux 发行版本(基于 Debian / RedHat,包括国产操作系统);
+ - 服务器架构:x86_64;
+ - 内存要求:建议可用内存在 1GB 以上;
+ - 浏览器要求:请使用 Chrome、FireFox、IE10+、Edge等现代浏览器。
+
+## 2 下载离线包
+
+!!! note ""
+ 请自行下载 1Panel 最新版本的离线包,并复制到目标机器的 /tmp 目录下。
+ 离线包下载链接: https://community.fit2cloud.com/#/products/1panel/downloads
+
+## 3 安装部署
+
+### 3.1 解压离线包
+
+!!! note ""
+ 以 root 用户 ssh 登录到目标机器, 并执行如下命令:
+
+ ```
+ cd /tmp
+ # 解压离线包(1panel-v1.10.0-lts-linux-amd64.tar.gz 为示例离线包名称,操作时可根据实际离线包名称替换)
+ tar zxvf 1panel-v1.10.0-lts-linux-amd64.tar.gz
+ ```
+
+### 3.2 执行安装脚本
+
+!!! note ""
+ ```
+ # 进入离线包目录(1panel-v1.10.0-lts-linux-amd64 为示例离线包目录名称,操作时可根据实际离线包名称替换)
+ cd 1panel-v1.10.0-lts-linux-amd64
+
+ # 运行安装脚本
+ /bin/bash install.sh
+ ```
+
+## 4 登录访问
+
+!!! note ""
+ 安装成功后,控制台会打印面板访问信息,可通过浏览器访问 1Panel:
+
+ ```
+ http://目标服务器 IP 地址:目标端口/安全入口
+ ```
+
+ - **如果使用的是云服务器,请至安全组开放目标端口。**
+ - **ssh 登录 1Panel 服务器后,执行 1pctl user-info 命令可获取安全入口(entrance)**
+
+!!! note ""
+ 安装成功后,可使用 [1pctl](cli.md) 命令行工具来维护 1Panel
diff --git a/docs/installation/tencent_cloud.md b/docs/installation/tencent_cloud.md
new file mode 100644
index 00000000..9c5e26fa
--- /dev/null
+++ b/docs/installation/tencent_cloud.md
@@ -0,0 +1,39 @@
+!!! note ""
+ 腾讯云目前已经在轻量应用服务器的应用模板中添加了 1Panel 的模板镜像,选择应用模板购买服务器即可直接使用 1Panel。
+
+## 1 购买轻量应用服务器
+
+!!! note ""
+ 购买地址:[轻量应用服务器](https://buy.cloud.tencent.com/lighthouse?blueprintType=APP_OS&blueprintOfficialId=lhbp-pjoqcja2®ionId=8&zone=ap-beijing-3&bundleId=bundle_starter_mc_med2_01&loginSet=AUTO&from=lh-console)
+
+ 在应用模板中选择 `1Panel Linux 面板`,然后选择所需地域、可用区、套餐等,点击立即购买即可。
+
+## 2 查看应用信息
+
+!!! note ""
+ 服务器初始化完成之后,进入服务器详情中的 `应用管理` 页面,即可看到 1Panel 的相关信息。
+
+
+
+## 3 开放防火墙端口
+
+!!! note ""
+ 登录 1Panel 面板前需要先在轻量应用服务器防火墙中开放 1Panel 服务端口,进入防火墙页面添加默认端口 8090 即可。
+
+ 如果后续修改了 1Panel 的服务端口,同样需要在这里添加规则。
+
+
+
+## 4 查看登录信息
+
+!!! note ""
+ 点击服务器详情页面的登录按钮,可以通过腾讯云的在线终端,在浏览器中直接进入服务器命令行,在命令行中复制并执行 `sudo /opt/1panel/get-1panel-info.sh` 命令,获取 1Panel 的登录地址和初始用户名密码。
+
+
+
+## 5 登录 1Panel 面板
+
+!!! note ""
+
+ - 通过上一步获取到的 http://服务器外网IP:8090/安全入口 地址,访问面板管理页面,如:http://172.16.10.1:8090/mm4h9iucdn
+ - 输入帐号密码
diff --git a/docs/installation/tencent_cloudapp.md b/docs/installation/tencent_cloudapp.md
new file mode 100644
index 00000000..0af04359
--- /dev/null
+++ b/docs/installation/tencent_cloudapp.md
@@ -0,0 +1,34 @@
+## 1 安装 1Panel 云应用
+
+!!! note ""
+ 1Panel 社区版已上架腾讯云云应用,可直接在腾讯云服务器中快速部署。通过云应用的部署方式,用户可以直接购买创建云服务器并自动完成 1Panel 的安装配置。
+
+ 第一步:关联我们的腾讯云合作伙伴账户,享受更多优惠福利:[点击链接进行关联](https://partner.cloud.tencent.com/invitation/10002820907763620ace838b1?inviteType=2)
+
+ 第二步:打开 [1Panel 社区版云应用](https://app.cloud.tencent.com/detail/SPU_BHDJDDBEBA6600),进入云应用页面。
+
+ 勾选同意用户协议后,点击安装应用即可进入 1Panel 社区版云应用安装页面。
+
+
+
+!!! note ""
+ 根据页面提示,选择 VPC类型、地域、计费类型及云服务器类型等参数后,点击 `下一步:确定资源` 进入订单确认页面。
+
+
+
+!!! note ""
+ 信息确认无误后,点击 `下一步:安装应用`,腾讯云将自动完成云服务器、安全组、公网 IP 等相关资源的创建及 1Panel 的安装配置。等待 1Panel 云应用部署完成后,页面将自动跳转到新部署的 1Panel 云应用详情页面。
+
+
+
+## 2 查看应用信息
+
+!!! note ""
+ 点击应用详情页面上方的 `应用信息`,即可查看到 1Panel 面板的登录地址,随机生成的用户名密码等信息。
+
+
+
+## 3 登录 1Panel 面板
+
+!!! note ""
+ 直接点击应用信息页面中的 1Panel 面板登录地址,或点击右上角的打开应用进入到 1Panel 面板登录页面,使用应用信息中的 `1Panel 面板用户名` 和 `1Panel 面板密码` 即可登录 1Panel 面板。
diff --git a/v1/js/custom.js b/docs/js/custom.js
similarity index 100%
rename from v1/js/custom.js
rename to docs/js/custom.js
diff --git a/v1/js/termynal.js b/docs/js/termynal.js
similarity index 100%
rename from v1/js/termynal.js
rename to docs/js/termynal.js
diff --git a/v1/stylesheets/extra.css b/docs/stylesheets/extra.css
similarity index 100%
rename from v1/stylesheets/extra.css
rename to docs/stylesheets/extra.css
diff --git a/docs/user_manual/.DS_Store b/docs/user_manual/.DS_Store
new file mode 100644
index 00000000..7b8f2af2
Binary files /dev/null and b/docs/user_manual/.DS_Store differ
diff --git a/docs/user_manual/ai/gpu.md b/docs/user_manual/ai/gpu.md
new file mode 100644
index 00000000..173b4cd5
--- /dev/null
+++ b/docs/user_manual/ai/gpu.md
@@ -0,0 +1,30 @@
+## 1 安装驱动
+
+!!! note ""
+ 针对 NVIDIA 显卡,用户可以在 https://www.nvidia.com/en-us/drivers/ 网站查找对应显卡型号支持的驱动版本,并进行下载安装。
+
+ 例如下载到的文件为 `NVIDIA-Linux-x86_64-570.86.15.run`,将文件上传到 1Panel 服务器后,可以在命令行执行以下命令进行安装:
+
+ ```bash
+ chmod +x NVIDIA-Linux-x86_64-570.86.15.run
+ ./NVIDIA-Linux-x86_64-570.86.15.run
+ ```
+
+ > 执行命令后根据弹出的提示框信息进行安装即可。
+ `nvidia-smi` 命令会随 NVIDIA 驱动一同安装,1Panel 将使用 `nvidia-smi` 命令获取显卡相关信息。
+
+## 2 查看显卡信息
+
+!!! note ""
+ 在 GPU 监控页面,可以查看到驱动版本,显卡型号以及显卡的使用率、温度、功耗等基础指标,还可以查看到目前正在使用显卡的进程信息。
+
+
+
+## 3 配置应用商店应用(容器)使用 GPU
+
+!!! note ""
+ 显卡驱动安装完成后,还需要根据 [NVIDIA 官网指引](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html)安装容器支持工具,才可以在应用商店应用或其他容器中使用 GPU 能力。
+
+> 在应用商店安装应用时,勾选高级设置中的 `GPU 加速` 即可让该应用获得 GPU 支持。
+
+
diff --git a/docs/user_manual/ai/mcp.md b/docs/user_manual/ai/mcp.md
new file mode 100644
index 00000000..2696491f
--- /dev/null
+++ b/docs/user_manual/ai/mcp.md
@@ -0,0 +1,53 @@
+## 1 MCP Server 管理
+
+!!! note ""
+ MCP(Model Context Protocol,模型上下文协议) 是由人工智能企业 Anthropic 推出的开放标准,旨在为大语言模型和 AI 助手提供统一、标准化的接口,让AI可以轻松操作外部工具,完成更加复杂的任务,从而发挥真正的“工具调用”能力。
+
+ 然而在实际操作过程中,搭建 MCP Server 需要手动配置大量依赖,部署门槛较高,许多用户难以上手。为了解决这个问题,1Panel v1.10.29 LTS 版本推出了原生的 MCP Server 管理功能,该功能通过容器化方式实现一键部署 MCP Server,能够极大简化搭建流程。
+
+
+
+## 2 创建 MCP Server
+
+!!! note ""
+ 当前已支持两种方式运行的 MCP Server 的 stdio 模式发布为 SSE 模式,供 MCP 客户端调用:
+
+ - 支持通过 npx 命令启动 MCP Server
+ - 支持以二进制方式运行 MCP Server(需将二进制文件挂载至容器中)
+
+### 2.1 npx 命令启动
+
+
+
+### 2.2 二进制方式运行
+
+
+
+## 3 获取配置信息
+
+!!! note ""
+ MCP Server部署成功后,1Panel会为每个MCP Server实例自动生成客户端配置信息,包括端口、地址、SSE路径等。点击“配置”按钮,即可快速获取该MCP Server的客户端配置信息。
+ 用户只需要复制客户端配置信息并粘贴至MCP客户端,即可开始使用拥有MCP加成的AI助手。这种方式无需手动查找或配置环境变量,实现了从部署到使用的无缝衔接。
+
+
+
+## 4 统一域名与SSE路径
+
+!!! note ""
+ 1Panel 支持将多个 MCP Server 实例统一绑定至同一个网站域名,每个实例仅需设置不同的SSE路径进行区分。这意味着用户无需为每个 MCP Server 单独开放端口,所有服务都可以通过同一个端口对外提供服务。
+
+ 这种方式不仅简化了公网访问的配置逻辑,也让运维操作更加集中统一。尤其是在大规模部署和企业内部网络的场景下,统一绑定网站域名能够避免暴露过多端口,减少安全风险,进一步提升部署的灵活性、安全性和可维护性。
+
+
+
+## 5 白名单访问限制
+
+!!! note ""
+ 1Panel 支持为每个 MCP Server 网站配置IP访问白名单,以此有效保障 MCP Server 的数据安全。用户可以根据实际需求将 IP 地址或 IP 段添加至白名单,从而保证只有白名单中的 IP 能够访问 MCP Server 网站。与此同时,系统将自动拒绝所有不在白名单中的 IP 的访问请求。
+
+ 通过为 MCP Server 网站配置 IP 访问白名单,可以有效隔离外部非授权访问,在网络入口层面建立起第一道安全防线。同时配合 1Panel 的防火墙策略和容器隔离机制,可以显著提升整体系统的安全性与稳定性。
+
+## 6 HTTPS数据加密
+
+!!! note ""
+ 1Panel 还支持为 MCP Server 网站启用HTTPS协议,用户只需要上传证书即可开启加密访问,全面保障上下文交互数据的安全性。
diff --git a/docs/user_manual/ai/model.md b/docs/user_manual/ai/model.md
new file mode 100644
index 00000000..e5f7429a
--- /dev/null
+++ b/docs/user_manual/ai/model.md
@@ -0,0 +1,52 @@
+## 1 管理 Ollama 应用
+
+1.1 应用商店安装 Ollama
+
+!!! note ""
+ 要使用模型管理功能,需要先在应用商店中安装 Ollama 应用。Ollama 安装完成后可以在该页面查看 Ollama 应用状态,并进行启动、停止及重启等操作。
+
+
+
+## 2 添加模型
+
+!!! note ""
+ 点击添加模型,输入模型名称点击添加按钮即可从 [Ollama 官方仓库](https://ollama.com/search)拉取对应模型。
+
+
+
+## 3 运行模型
+
+!!! note ""
+ 点击某个模型所在行的【运行】操作,即可在当前页面打开在线终端与该模型进行对话。
+
+
+
+## 4 AI 代理增强
+
+!!! note ""
+ 通过该功能可以为 Ollama 应用配置反向代理,从而支持域名、HTTPS、IP 白名单等配置,增强使用大模型时的安全性。
+
+
+
+## 5 查看连接信息
+
+!!! note ""
+ 点击列表上方的【连接信息】按钮,即可查看 Ollama 应用的连接信息。
+
+
+
+> 应用商店部署的 Ollama 采用容器化方式运行,不同的场景需要根据页面提示选择对应的连接信息。
+
+## 6 从服务器同步
+
+!!! note ""
+ 当使用了其他工具或应用程序添加了模型,模型列表信息与实际不一致时,可以点击列表上方的【从服务器同步】按钮,主动从 Ollama 查询当前模型列表。
+
+## 7 WEB 管理工具
+
+!!! note ""
+ 如果需要使用 WEB 图形化界面管理并使用 Ollama 时,可以列表上方的【OpenWebUI】按钮,跳转到对应工具页面。
+
+ 目前支持的管理工具有:
+
+ - [OpenWebUI](https://github.com/open-webui/open-webui)
diff --git a/docs/user_manual/appstore/appstore.md b/docs/user_manual/appstore/appstore.md
new file mode 100644
index 00000000..063f8e47
--- /dev/null
+++ b/docs/user_manual/appstore/appstore.md
@@ -0,0 +1,12 @@
+## 1 功能概述
+
+!!! note "功能概述"
+
+ - 应用商店旨在为用户提供便捷、高效的应用部署和管理体验。通过应用商店,用户可以一键安装多种常见的建站工具、服务和开发环境,如 WordPress、Halo、PHP、Node.js、MySQL 等,不再需要复杂的手动配置。
+ - 此外,1Panel 应用商店还提供应用的备份恢复、升级等功能,确保用户的数据安全和应用的持续可用性,为日常运维和站点管理提供了极大便利。
+
+!!! note "本地应用"
+
+ 添加自己想要的应用,1Panel 应用商店还支持本地应用。制作教程可参考:[提交自定义应用教程](https://github.com/1Panel-dev/appstore/wiki/%E5%A6%82%E4%BD%95%E6%8F%90%E4%BA%A4%E8%87%AA%E5%B7%B1%E6%83%B3%E8%A6%81%E7%9A%84%E5%BA%94%E7%94%A8),也可以参考论坛文章:[论坛文章链接](https://bbs.fit2cloud.com/t/topic/640/)。
+
+{ width="900px" }
diff --git a/docs/user_manual/appstore/install.md b/docs/user_manual/appstore/install.md
new file mode 100644
index 00000000..fa937c4b
--- /dev/null
+++ b/docs/user_manual/appstore/install.md
@@ -0,0 +1,25 @@
+!!! note ""
+
+ 在应用商店列表中找到并安装目标应用,您可以通过应用分类浏览,或者直接在右上角的搜索框中输入关键字快速查找。
+ > 本文将以安装 Halo 为例进行演示。
+
+## 安装步骤
+
+!!! note ""
+
+ 1、点击【安装】按钮进入应用详情页面。
+
+
+
+!!! note ""
+
+ 2、填写数据库、端口等参数。
+
+
+
+
+!!! note ""
+
+ 3、还支持高级设置选项,例如是否暴露外部端口、资源限制以及编辑 compose 文件等。最后,点击【确认】按钮,等待应用安装完成。
+
+
diff --git a/docs/user_manual/appstore/installed.md b/docs/user_manual/appstore/installed.md
new file mode 100644
index 00000000..103c13e9
--- /dev/null
+++ b/docs/user_manual/appstore/installed.md
@@ -0,0 +1,78 @@
+!!! note ""
+
+ 进入已安装列表,用户可以对应用进行同步、升级、重启、启动、停止、删除、备份和恢复等操作。
+
+{ width="900px" }
+
+## 1 同步
+
+!!! note ""
+
+ 点击【同步】按钮,可自动更新应用状态,确保与当前系统状态保持一致。
+
+
+
+## 2 重建
+
+!!! note ""
+
+ 点击【重建】按钮,系统会删除现有的应用实例,并基于当前的设置和配置重新安装和启动应用。
+
+
+
+## 3 启动 / 停止 / 重启
+
+
+
+## 4 卸载
+
+!!! note ""
+
+ 点击【卸载】按钮,系统将自动执行卸载过程,删除应用的所有相关资源,包括容器、配置文件等。
+
+ - 强制删除:会忽略删除过程中产生的错误并最终删除元数据。
+ - 删除备份:删除备份列表中的备份文件。
+
+
+
+## 5 应用详情
+
+!!! note ""
+
+ 点击【参数】按钮,可以查看应用的相关参数。
+
+
+
+!!! note ""
+
+ 点击参数页面右上角的【编辑】按钮,可以对部分应用参数及应用高级设置进行修改,具体支持修改的参数与应用定义有关。
+
+
+
+## 6 备份 / 恢复
+
+!!! note ""
+
+ 点击【备份】按钮,进入备份列表。
+
+
+
+!!! note ""
+
+ 点击【备份】按钮可立即备份当前应用。若需恢复应用,点击备份列表中的【恢复】按钮,将根据选定的备份恢复应用到相应状态。
+
+
+
+## 7 升级
+
+!!! note ""
+
+ 进入【可升级】页面,可查看当前支持升级的应用。
+
+
+
+!!! note ""
+
+ 点击【升级】按钮后,选择目标版本。可选择在升级前备份应用、自动拉取最新镜像、以及自定义修改 compose.yml 文件等。最后点击【确认】按钮,等待升级完成。
+
+
diff --git a/docs/user_manual/containers/compose.md b/docs/user_manual/containers/compose.md
new file mode 100644
index 00000000..94470813
--- /dev/null
+++ b/docs/user_manual/containers/compose.md
@@ -0,0 +1,30 @@
+## 1 创建编排
+
+!!! note ""
+ 提供三种方法可以从 1Panel 部署新 Compose
+
+ - 编辑: 使用 Web 编辑器定义服务。
+ - 路径选择: 选择 1Panel 服务中已存在的 docker-compose.yml。
+ - 编排模版: 选择已存在的编排模版。
+
+ [我想了解更多容器编排相关的知识](https://docs.docker.com/compose)
+
+
+
+## 2 编辑编排
+
+!!! note ""
+ Compose 按照来源可以区分为三种:
+
+ - Apps: 来源于应用商店应用部署;
+ - 1Panel: 来源于系统编排创建;
+ - Local: 服务器直接创建。
+
+ **编辑仅适用于 1Panel 部署的 Compose**
+
+## 3 编排详情
+
+!!! note ""
+ 点击编排列表名称,进入编排详情界面,详情界面实现该 Compose 对应的容器列表,仅当该 Compose 为 1Panel 创建时,支持对 Compose 进行启停操作。
+
+
diff --git a/docs/user_manual/containers/compose_template.md b/docs/user_manual/containers/compose_template.md
new file mode 100644
index 00000000..f5b1be50
--- /dev/null
+++ b/docs/user_manual/containers/compose_template.md
@@ -0,0 +1,6 @@
+## 1 添加模版
+
+!!! note ""
+ 供创建编排时使用
+
+
\ No newline at end of file
diff --git a/docs/user_manual/containers/container.md b/docs/user_manual/containers/container.md
new file mode 100644
index 00000000..a1a1a814
--- /dev/null
+++ b/docs/user_manual/containers/container.md
@@ -0,0 +1,51 @@
+## 1 添加容器
+
+!!! note ""
+
+ - 从菜单中选择 **容器**,然后单击 **创建容器**。
+ - **根据需要配置容器设置**。
+ - 镜像需要从镜像镜像菜单手动拉取。
+
+
+
+
+## 2 检查容器
+
+!!! note ""
+ 点击目标容器名称,有关容器的所有信息都将显示在右侧抽屉中。
+
+
+
+## 3 查看容器日志
+
+!!! note ""
+
+ - 支持查看最近一天,最近 4 小时,最近 1 小时,最近 10 分钟的容器日志。
+ - **追踪:** 实时刷新容器日志
+ - **下载:** 下载容器日志
+
+
+
+## 4 访问容器的控制台
+
+!!! note ""
+
+ - 选择要授予访问权限的命令和用户,然后单击 **连接**。
+ - **注意:** 对于 Alpine Linux 容器,选择 /bin/ash 命令。
+ - 如果需要定义除提供的命令之外的命令,请将 **自定义** 选项切换为打开。
+
+
+
+## 5 查看容器统计信息
+
+!!! note ""
+ 支持查看的信息包括:
+
+ - 内存使用率
+ - CPU 使用率
+ - 磁盘 IO 使用情况
+ - 网络使用情况
+
+ ***可以随时更改刷新间隔***。
+
+
\ No newline at end of file
diff --git a/docs/user_manual/containers/image.md b/docs/user_manual/containers/image.md
new file mode 100644
index 00000000..bea329d4
--- /dev/null
+++ b/docs/user_manual/containers/image.md
@@ -0,0 +1,45 @@
+## 1 拉取镜像
+
+!!! note ""
+
+ - 支持从已添加的镜像仓库中拉取,等价于 docker pull 操作。
+ - 拉取镜像将耗费一段时间,如果关闭抽屉后还想查看拉取日志,则可以去【主机 - 文件】中,下载或查看 [安装目录]/1panel/tmp/docker_logs/image_pull_[时间戳].log。
+
+## 2 导入镜像
+
+!!! note ""
+
+ - 选择 1Panel 服务器上已导出的镜像文件,等价于 docker load 操作。
+
+## 3 构建镜像
+
+!!! note ""
+
+ - 直接构建镜像,等价于 docker build 操作。
+ - 构建镜像将耗费一段时间,如果关闭抽屉后还想查看构建日志,则可以去【主机 - 文件】中,下载或查看 [安装目录]/1panel/tmp/docker_logs/image_build_[时间戳].log。
+
+
+
+!!! note ""
+
+ - 编辑: 使用 Web 编辑器编辑 Dockerfile。
+ - 路径选择: 选择 1Panel 服务中已存在的 Dockerfile。
+
+## 4 Tag 镜像
+
+!!! note ""
+
+ - Tag 镜像,等价于 docker tag 操作。
+
+## 5 推送镜像
+
+!!! note ""
+
+ - 将镜像推送到镜像仓库,推送过程中,后台将自动修改对应的镜像 Tag,等价于 docker tag + docker push 操作。
+
+## 6 导出镜像
+
+!!! note ""
+
+ - 将镜像导出为 .tar 文件,等价于 docker save,当需要进行复制或者移动镜像时,可直接在系统执行导入导出操作。
+
diff --git a/docs/user_manual/containers/network.md b/docs/user_manual/containers/network.md
new file mode 100644
index 00000000..5bf69dac
--- /dev/null
+++ b/docs/user_manual/containers/network.md
@@ -0,0 +1,17 @@
+## 1 添加网络
+
+!!! note ""
+ 1Panel 允许在环境中添加、删除网络,其中 none、host、bridge、1panel-network 四个网络为系统自带网络,无法删除。
+
+ [我想了解更多容器网络相关的知识](https://docs.docker.com/network)
+
+
+
+!!! note ""
+
+ **模式:Docker中的网络驱动(network driver)是可插拔的,1Panel 提供几种网络驱动以提供核心的网络功能,包括:**
+
+ - bridge: docker 默认的 network driver。如果不显示指定driver类型,docker默认会使用 bridge 模式的 network。通常,当应用程序运行在独立的容器中,并且要相互通信,可以使用 bridge 模式。Bridge 模式下容器与 docker host 的网络是相互隔离的。
+ - ipvlan: IPvlan 驱动程序让用户完全控制 IPv4 和 IPv6 寻址。VLAN 驱动程序建立在此基础上,为操作员提供对二层 VLAN 标记的完全控制,甚至对底层网络集成感兴趣的用户提供 IPvlan L3 路由。
+ - macvlan:macvlan network 能够给容器分配一个 MAC 地址,使的此容器就像一个此网络上的物理设备。Docker Daemon可以通过MAC地址给容器路由消息。对于一些遗留的应用需要直接连接到物理网络而不是通过 docker host 的网络栈转发时, macvlan 驱动是最好的选择。
+ - overlay: Overlay network能够连通不同的 docker daemon,能够使 swarm service 之间能够相互通信. Overlay network 也能够使 swarm service 与独立的容器连通, 能够使位于不同 Docker daemon 上的独立的容器连通。Overlay 模式省去了容器之间操作系统层级的路由工作。
diff --git a/docs/user_manual/containers/repo.md b/docs/user_manual/containers/repo.md
new file mode 100644
index 00000000..a0b1354c
--- /dev/null
+++ b/docs/user_manual/containers/repo.md
@@ -0,0 +1,8 @@
+## 1 添加仓库
+
+!!! note ""
+
+ - 仓库存在认证信息时,后端会自动执行 docker login 操作。
+ - 添加 http 协议仓库后,会自动在配置文件中添加该仓库的授信信息,需要重启 Docker 服务。
+
+
\ No newline at end of file
diff --git a/docs/user_manual/containers/setting.md b/docs/user_manual/containers/setting.md
new file mode 100644
index 00000000..78d7a8e1
--- /dev/null
+++ b/docs/user_manual/containers/setting.md
@@ -0,0 +1,48 @@
+## 1 配置
+
+!!! note ""
+
+ - 支持查看 Docker 运行状态,并执行重启服务等操作。
+ - 配置文件默认为:/etc/docker/daemon.json。
+
+
+
+!!! note ""
+
+ - 镜像加速:应用安装失败,镜像拉取超时,此时可以配置镜像加速器进行优化。
+ - 配置加速地址:
+ ```properties
+ https://docker.1panel.live
+ ```
+ > 配置了上述加速地址后,如果拉取应用镜像仍然失败,[可以在论坛中进一步讨论](https://bbs.fit2cloud.com/t/topic/5886)
+ - 私有仓库:搭建的私有镜像仓库,如 harber、nexus、docker-registry 等。
+ - iptables:该设置将关闭 Docker 对 iptables 规则的自动配置,这可能会导致容器无法与外部网络通信。
+ - live-restore:停止 Docker 服务时,是否停止所有容器。
+ - cgroup-driver:默认情况下使用的 Cgroup Driver 为 cgroupfs。
+
+## 2 使用 IPv6
+
+!!! note ""
+
+ - 确保自己的设备被分配了一个 IPv6。通过 ip addr show 查看当前设备的 IPv6。其输出的物理网卡存在包含 inet6 和 scope global 的行时,表示该网卡支持 IPv6。
+ ```properties
+ eth0: mtu 1500 qdisc mq state UP group default qlen 1000
+ link/ether 00:16:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
+ inet 172.31.168.107/20 brd 172.31.175.255 scope global dynamic eth0
+ valid_lft 314955046sec preferred_lft 314955046sec
+ inet6 2xxx:xxxx:xxxxx:xxxx:xxxx:xxxx:xxxx:xxxx/64 scope global dynamic
+ valid_lft 113120sec preferred_lft 69920sec
+ inet6 fe80::xxxx:xxxx:xxxx:xxxx/64 scope link
+ valid_lft forever preferred_lft forever
+ ```
+
+ - 面板设置中开启 IPv6,其中 fixed-cidr-v6 是上一步获取到的 IPv6 网段的子网(配置默认网络,前缀长度最大为 /80)。
+ 
+
+ - 通过【网络】-【详情】检查是否生效。若生效,则 EnableIPv6 值为 true,IPAM.Config[1].Subnet 是上一步配置的 fixed-cidr-v6。
+ 
+
+ - 创建 IPv6 网络。
+ 
+
+ - 使用创建的 IPv6 网络创建容器。
\ No newline at end of file
diff --git a/docs/user_manual/containers/volume.md b/docs/user_manual/containers/volume.md
new file mode 100644
index 00000000..e9b75fad
--- /dev/null
+++ b/docs/user_manual/containers/volume.md
@@ -0,0 +1,8 @@
+## 1 添加存储
+
+!!! note ""
+ Volume 是一个数据存储区域,可以挂载到容器中以提供持久存储。
+
+ [我想了解更多容器存储相关的知识](https://docs.docker.com/storage/volumes)
+
+
diff --git a/docs/user_manual/cronjobs.md b/docs/user_manual/cronjobs.md
new file mode 100644
index 00000000..dd013369
--- /dev/null
+++ b/docs/user_manual/cronjobs.md
@@ -0,0 +1,153 @@
+## 功能说明
+
+!!! note ""
+ 主要用于管理需要定时执行的任务,如定期执行某shell脚本、定期备份、定期访问url等,同时支持手动执行。
+
+
+
+## 任务类型
+
+### 1 Shell 脚本
+
+!!! note "配置说明"
+
+ - 执行周期:选择当前计划任务的执行时间,可以同时配置多个执行周期;
+ - 在容器中执行:勾选后可以选择某个容器,在容器中执行指定的脚本;
+ - 脚本内容:具体需要执行的脚本内容;
+ - 是否告警(✨专业版):定时任务执行失败时可以触发告警通知;
+ - 保留份数:执行记录及执行日志的保留份数,默认保存为7份;
+
+### 2 备份应用
+
+!!! note "配置说明"
+
+ - 执行周期:选择当前计划任务的执行时间,可以同时配置多个执行周期;
+ - 备份应用:选择需要备份的应用,可以选择指定的应用备份,也可以备份所有应用;
+ - 备份账号:备份数据的存放位置,可以保存在当前服务器磁盘,或面板设置中配置的对象存储、FTP 等外部存储服务中;
+ - 压缩密码:备份数据压缩包的保护密码;
+ - 默认下载地址:当选择了多个备份账号,用于下载备份文件时默认使用的备份账号;
+ - 是否告警(✨专业版):定时任务执行失败时可以触发告警通知;
+ - 保留份数:默认保存为7份,保留就近备份文件的数量,可以减少备份所使用的空间;
+ - 排除规则:备份数据压缩包中需要排除的文件,例如日志文件、临时目录等,支持配置多个排除规则;
+
+### 3 备份网站
+
+!!! note "配置说明"
+
+ - 执行周期:选择当前计划任务的执行时间,可以同时配置多个执行周期;
+ - 备份网站:选择需要备份的网站,可以选择指定的网站备份,也可以备份所有网站;
+ - 备份账号:备份数据的存放位置,可以保存在当前服务器磁盘,或面板设置中配置的对象存储、FTP 等外部存储服务中;
+ - 压缩密码:备份数据压缩包的保护密码;
+ - 默认下载地址:当选择了多个备份账号,用于下载备份文件时默认使用的备份账号;
+ - 是否告警(✨专业版):定时任务执行失败时可以触发告警通知;
+ - 保留份数:默认保存为7份,保留就近备份文件的数量,可以减少备份所使用的空间;
+ - 排除规则:备份数据压缩包中需要排除的文件,例如日志文件、临时目录等,支持配置多个排除规则;
+
+### 4 备份数据库
+
+!!! note "配置说明"
+
+ - 执行周期:选择当前计划任务的执行时间,可以同时配置多个执行周期;
+ - 备份数据库:选择需要备份的数据库,可以选择指定的数据库备份,也可以备份所有数据库;
+ - 备份账号:备份数据的存放位置,可以保存在当前服务器磁盘,或面板设置中配置的对象存储、FTP 等外部存储服务中;
+ - 压缩密码:备份数据压缩包的保护密码;
+ - 默认下载地址:当选择了多个备份账号,用于下载备份文件时默认使用的备份账号;
+ - 是否告警(✨专业版):定时任务执行失败时可以触发告警通知;
+ - 保留份数:默认保存为7份,保留就近备份文件的数量,可以减少备份所使用的空间;
+ - 排除规则:备份数据压缩包中需要排除的文件,例如日志文件、临时目录等,支持配置多个排除规则;
+
+## 5 备份目录
+
+!!! note "配置说明"
+
+ - 执行周期:选择当前计划任务的执行时间,可以同时配置多个执行周期;
+ - 备份目录:选择需要备份的目录;
+ - 备份账号:备份数据的存放位置,可以保存在当前服务器磁盘,或面板设置中配置的对象存储、FTP 等外部存储服务中;
+ - 压缩密码:备份数据压缩包的保护密码;
+ - 默认下载地址:当选择了多个备份账号,用于下载备份文件时默认使用的备份账号;
+ - 是否告警(✨专业版):定时任务执行失败时可以触发告警通知;
+ - 保留份数:默认保存为7份,保留就近备份文件的数量,可以减少备份所使用的空间;
+ - 排除规则:备份数据压缩包中需要排除的文件,例如日志文件、临时目录等,支持配置多个排除规则;
+
+## 6 备份日志
+
+!!! note ""
+ 备份以下日志内容:
+
+ - 1Panel 系统日志
+ - 服务器的 SSH 登录日志
+ - 所有网站日志
+
+!!! note "配置说明"
+
+ - 执行周期:选择当前计划任务的执行时间,可以同时配置多个执行周期;
+ - 备份账号:备份数据的存放位置,可以保存在当前服务器磁盘,或面板设置中配置的对象存储、FTP 等外部存储服务中;
+ - 压缩密码:备份数据压缩包的保护密码;
+ - 默认下载地址:当选择了多个备份账号,用于下载备份文件时默认使用的备份账号;
+ - 是否告警(✨专业版):定时任务执行失败时可以触发告警通知;
+ - 保留份数:默认保存为7份,保留就近备份文件的数量,可以减少备份所使用的空间;
+
+## 7 访问 URL
+
+!!! note "配置说明"
+
+ - 执行周期:选择当前计划任务的执行时间,可以同时配置多个执行周期;
+ - 是否告警(✨专业版):定时任务执行失败时可以触发告警通知;
+ - 保留份数:执行记录及执行日志的保留份数,默认保存为7份;
+ - URL 地址:需要定时访问的 URL 地址;
+
+## 8 切割网站日志
+
+!!! note ""
+ 计划任务执行时会将指定网站的日志进行切割,将之前产生的日志保存在备份目录下。
+
+!!! note "配置说明"
+
+ - 执行周期:选择当前计划任务的执行时间,可以同时配置多个执行周期;
+ - 网站:选择需要进行日志切割的网站,可以选择指定的网站,也可以选择所有网站;
+ - 是否告警(✨专业版):定时任务执行失败时可以触发告警通知;
+ - 保留份数:默认保存为7份,保留就近切割后日志文件的数量;
+
+## 9 缓存清理
+
+!!! note ""
+ 定时执行面板 `工具箱` 菜单中的 `缓存清理` 任务。
+
+!!! note "配置说明"
+
+ - 执行周期:选择当前计划任务的执行时间,可以同时配置多个执行周期;
+ - 是否告警(✨专业版):定时任务执行失败时可以触发告警通知;
+ - 保留份数:执行记录及执行日志的保留份数,默认保存为7份;
+
+## 10 系统快照
+
+!!! note ""
+ 定时执行面板 `面本设置`-`快照` 菜单中的 `创建快照` 任务。
+
+!!! note "配置说明"
+
+ - 执行周期:选择当前计划任务的执行时间,可以同时配置多个执行周期;
+ - 备份账号:备份数据的存放位置,可以保存在当前服务器磁盘,或面板设置中配置的对象存储、FTP 等外部存储服务中;
+ - 压缩密码:备份数据压缩包的保护密码;
+ - 默认下载地址:当选择了多个备份账号,用于下载备份文件时默认使用的备份账号;
+ - 是否告警(✨专业版):定时任务执行失败时可以触发告警通知;
+ - 保留份数:默认保存为7份,保留就近备份文件的数量,可以减少备份所使用的空间;
+ - 排除规则:备份数据压缩包中需要排除的文件,例如日志文件、临时目录等,支持配置多个排除规则;
+
+## 11 同步服务器时间
+
+!!! note ""
+ 定时从 `工具箱`-`快速设置` 页面配置的 NTP 服务器进行时间同步。
+
+!!! note "配置说明"
+
+ - 执行周期:选择当前计划任务的执行时间,可以同时配置多个执行周期;
+ - 是否告警(✨专业版):定时任务执行失败时可以触发告警通知;
+ - 保留份数:执行记录及执行日志的保留份数,默认保存为7份;
+
+## 执行报告
+
+!!! note ""
+ 显示该任务产生的所有报告详情,支持时间、状态筛选,如果计划任务为备份,则可通过报告详情的下载按钮直接下载。
+
+
diff --git a/docs/user_manual/databases/mysql.md b/docs/user_manual/databases/mysql.md
new file mode 100644
index 00000000..270053ea
--- /dev/null
+++ b/docs/user_manual/databases/mysql.md
@@ -0,0 +1,142 @@
+## 1 管理数据库实例
+
+1.1 应用商店安装数据库
+
+!!! note ""
+ 通过应用商店安装的 MySQL、MariaDB 数据库应用,会自动出现在数据库实例列表中。
+
+1.2 远程服务器
+
+!!! note ""
+ 除应用商店安装的本地数据库以外,还可以添加已存在的数据库服务地址。点击列表上方的【远程服务器】按钮,即可进入远程服务器管理页面。
+
+
+
+
+
+1.3 切换数据库实例
+
+!!! note ""
+ 点击数据库列表上方的下拉菜单,即可在不同的数据库实例间进行切换,管理不同数据库实例下的数据库及设置等。
+
+
+
+## 2 创建数据库
+
+!!! note ""
+ 创建一个新的数据库,首先输入数据库名称,选择编码格式,输入密码,设置访问权限,即可成功创建一个数据库。
+
+
+
+!!! note ""
+ - 数据库名:新建数据库的名称,选择编码格式,默认为 UTF-8 格式。
+ - 用户名:访问该数据库的用户名。
+ - 密码:默认为随机密码,需要可以自行修改。
+ - 访问权限:默认权限本地服务器权限,选项有:本地服务器,所有人,指定 IP。
+
+## 3 查看连接信息
+
+!!! note ""
+ 点击列表上方的【连接信息】按钮,即可查看数据库的地址、端口及 root 密码等连接信息,同时可以在这里修改数据库 root 密码。
+
+
+
+!!! note "注意"
+ 应用商店部署的数据库采用容器化方式运行,不同的场景需要根据页面提示选择对应的连接信息。
+
+## 4 从服务器同步
+
+!!! note ""
+ 当使用了其他数据库工具或应用程序操作了数据库,数据库列表信息与实际不一致时,可以点击列表上方的【从服务器同步】按钮,主动从数据库查询当前数据库列表。
+
+## 5 WEB 管理工具
+
+!!! note ""
+ 如果需要使用 WEB 图形化界面管理 MySQL 数据库,可以列表上方的【管理】按钮,跳转到对应工具页面。
+
+ 目前支持的管理工具有:
+
+ - [phpMyAdmin](https://www.wpdaxue.com/series/phpmyadmin)
+ - Adminer
+
+## 6 备份
+
+!!! note ""
+ 点击备份列表按钮,选择备份,即可备份当前数据库文件。
+
+
+
+!!! note ""
+ - 默认数据库路径为 /opt/1panel/backup/database/mysql。
+ - 备份使用 mysqldump 方式。
+
+## 7 恢复
+
+!!! note ""
+ 点击导入备份按钮,可以选择本地上传,或选择已备份的文件还原。
+
+
+
+!!! note ""
+
+ - 如从上传文件恢复,则需要保证上传文件压缩包内存在 test.sql 文件,否则无法正确导入。
+ - 导入的 sql 文件格式必须符合标准,若你使用 phpmyadmin 导出的 sql 文件,可能会缺少版本 编码等信息,导致无法通过 mysqldump 正确导入。
+ - 若无法正常导入,可以尝试使用 phpmyadmin 导入。
+
+## 8 权限设置
+
+!!! note ""
+ 点击操作列的【权限】按钮,可以修改指定数据库的访问权限,目前支持配置为所有人可访问或指定 IP 可访问。
+
+
+
+!!! note ""
+ - 所有人:任何人都可以远程连接至数据库。
+ - IP 地址:仅限指定的 IP 访问,多个 IP 使用英文逗号分隔。
+ - 若需要开启外网访问,仍需要在防火墙中放行 MySQL 端口(默认3306)。
+
+## 9 修改密码
+
+!!! note ""
+ - 修改当前的数据库账号的密码。
+ - **注意事项:** 当前修改的密码为非 root 密码。
+
+## 10 数据库配置
+
+!!! note ""
+ 点击状态栏设置按钮,即可进入数据库具体设置界面,具体包括配置修改、当前状态、性能调整、端口、日志、慢日志。
+ 其中配置界面可对数据库配置进行手动调整。
+
+
+
+!!! note ""
+ - 系统 MySQL 使用 Docker 安装,配置文件默认挂载在 /opt/1panel/apps/mysql/[数据库名称]/conf/my.cnf。
+ - **注意事项:** 错误的数据库配置将导致 MySQL 服务不可用,请谨慎修改。
+ - 如数据库配置不正确导致服务无法正常启动,可尝试恢复默认配置后保存。
+
+## 11 当前状态
+
+!!! note ""
+ 当数据库查询缓慢时,可在数据库设置界面,点击当前状态按钮,查看当前数据库包括缓存命中数、索引命中数等各个常用指标的状态,通过这些状态对数据库进行性能优化。
+
+
+
+## 12 性能调整
+
+!!! note ""
+ 系统支持表单方式直接调整数据库性能相关参数名,如索引缓冲区、连接数等,并且预设常用的优化方案,用户可根据系统环境,直接选择优化方案。
+
+
+
+## 13 端口
+
+!!! note ""
+ 除了在用户安装 MySQL 应用时可自由选择端口外,设置界面也可以直接进行端口的修改操作。
+
+## 14 日志
+
+!!! note ""
+ - 系统 MySQL 使用 Docker 安装,本处产生日志为对应 MySQL 容器产生的日志。支持时间段筛选、追踪及下载操作。
+ - 设置界面还支持查看 MySQL 产生的慢日志。
+
+
diff --git a/docs/user_manual/databases/postgresql.md b/docs/user_manual/databases/postgresql.md
new file mode 100644
index 00000000..7fad88ad
--- /dev/null
+++ b/docs/user_manual/databases/postgresql.md
@@ -0,0 +1,112 @@
+## 1 管理数据库实例
+
+1.1 应用商店安装数据库
+
+!!! note ""
+ 通过应用商店安装的 PostgreSQL 数据库应用,会自动出现在数据库实例列表中。
+
+1.2 远程服务器
+
+!!! note ""
+ 除应用商店安装的本地数据库以外,还可以添加已存在的数据库服务地址。点击列表上方的【远程服务器】按钮,即可进入远程服务器管理页面。
+
+
+
+
+
+1.3 切换数据库实例
+
+!!! note ""
+ 点击数据库列表上方的下拉菜单,即可在不同的数据库实例间进行切换,管理不同数据库实例下的数据库及设置等。
+
+
+
+## 2 创建数据库
+
+!!! note ""
+ 创建一个新的数据库,输入数据库名称、用户名、密码,设置访问权限,即可成功创建一个数据库。
+
+
+
+!!! note ""
+ - 数据库名:新建数据库的名称。
+ - 用户名:访问该数据库的用户名。
+ - 密码:默认为随机密码,需要可以自行修改。
+ - 访问权限:默认权限本地服务器权限,选项有:本地服务器,所有人,指定 IP。
+
+## 3 查看连接信息
+
+!!! note ""
+ 点击列表上方的【连接信息】按钮,即可查看数据库的地址、端口及管理员用户名和密码等连接信息,同时可以在这里修改管理员用户密码。
+
+
+
+!!! note "注意"
+ 应用商店部署的数据库采用容器化方式运行,不同的场景需要根据页面提示选择对应的连接信息。
+
+## 4 从服务器同步
+
+!!! note ""
+ 当使用了其他数据库工具或应用程序操作了数据库,数据库列表信息与实际不一致时,可以点击列表上方的【从服务器同步】按钮,主动从数据库查询当前数据库列表。
+
+## 5 WEB 管理工具
+
+!!! note ""
+ 如果需要使用 WEB 图形化界面管理 PostgreSQL 数据库,可以列表上方的【PGAdmin4】按钮,跳转到对应工具页面。
+
+## 6 备份
+
+!!! note ""
+ 点击备份列表按钮,选择备份,即可备份当前数据库文件。
+
+
+
+!!! note ""
+ - 默认数据库路径为 /opt/1panel/backup/database/postgresql。
+ - 备份使用 pg_dump 方式。
+
+## 7 恢复
+
+!!! note ""
+ 点击导入备份按钮,可以选择本地上传,或选择已备份的文件还原。
+
+
+
+!!! note ""
+
+ - 如从上传文件恢复,则需要保证上传文件压缩包内存在 test.sql 文件,否则无法正确导入。
+
+## 8 权限设置
+
+!!! note ""
+ 点击操作列的【权限】按钮,可以修改当前数据库绑定的用户是否为超级用户。
+
+## 9 修改密码
+
+!!! note ""
+ - 修改当前的数据库绑定用户的密码。
+ - **注意事项:** 当前修改的密码为非默认管理员密码。
+
+## 10 数据库配置
+
+!!! note ""
+ 点击状态栏设置按钮,即可进入数据库具体设置界面,具体包括配置修改、端口、日志查看。
+ 其中配置界面可对数据库配置进行手动调整。
+
+
+
+!!! note ""
+ - 系统 PostgreSQL 使用 Docker 安装,配置文件默认挂载在 /opt/1panel/apps/postgresql/[数据库名称]/data/postgresql.cnf。
+ - **注意事项:** 错误的数据库配置将导致 PostgreSQL 服务不可用,请谨慎修改。
+
+## 11 端口
+
+!!! note ""
+ 除了在用户安装 PostgreSQL 应用时可自由选择端口外,设置界面也可以直接进行端口的修改操作。
+
+## 12 日志
+
+!!! note ""
+ - 系统 PostgreSQL 使用 Docker 安装,本处产生日志为对应 PostgreSQL 容器产生的日志。支持时间段筛选、追踪及下载操作。
+
+
diff --git a/docs/user_manual/databases/redis.md b/docs/user_manual/databases/redis.md
new file mode 100644
index 00000000..91b2b8d6
--- /dev/null
+++ b/docs/user_manual/databases/redis.md
@@ -0,0 +1,71 @@
+## 1 修改密码
+
+!!! note ""
+ 默认为随机密码,root 为最高权限账号密码,请谨慎操作。
+
+## 2 Redis Commander
+
+!!! note ""
+ WEB 图形化界面管理 redis 数据库的管理工具,此处不会详细讲解工具使用方法,[点击查看工具教程](http://joeferner.github.io/redis-commander/)
+
+## 3 数据库配置
+
+!!! note ""
+ 点击状态栏设置按钮,即可进入 Redis 具体设置界面,具体包括配置修改、当前状态、性能调整、端口、持久化。
+ 其中配置界面可对 Redis 配置进行手动调整。
+
+
+
+!!! note ""
+ - 系统 Redis 使用 Docker 安装,配置文件默认挂载在 /opt/1panel/apps/redis/[数据库名称]/conf/redis.conf。
+ - **注意事项:** 错误的数据库配置将导致 Redis 服务不可用,请谨慎修改。
+ - 如数据库配置不正确导致服务无法正常启动,可尝试恢复默认配置后保存。
+
+## 4 当前状态
+
+!!! note ""
+ 当 Redis 查询缓慢时,可在设置界面,点击当前状态按钮,查看当前数据库包括内存分配、查询命中率等各个常用指标的状态,通过这些状态对 Redis 进行性能优化。
+
+
+
+## 5 性能调整
+
+!!! note ""
+ 系统支持表单方式直接调整 Redis 相关参数,具体包括:超时时间、最大连接数、最大内存数。
+
+
+
+## 6 端口
+
+!!! note ""
+ 除了在用户安装 Redis 应用时可自由选择端口外,设置界面也可以直接进行端口的修改操作。
+
+## 7 持久化
+
+!!! note ""
+ Redis 持久化分为两种:AOF 及 RDB,其中:
+
+ - RBD:
+ - 实现: 父进程在保存 RDB 文件时,先 fork 出来一个子进程,然后子进程处理接下来的保存工作,父进程无需执行任何磁盘 I/O 操作。
+ - 优点: 将 Redis 在某个时间点上的数据集保存在一个文件中,适用于灾难恢复,可以最大化 Redis 性能,速度更快,并且在恢复大数据集时速度更快。
+ - 缺点: 有丢失数据的风险,需要设置备份频率,一旦发生故障停机时,可能会丢失数据,而且当数据集比较大时,fork 子进程将会非常耗时造成服务停止。
+ - AOF:
+ - 实现: 定时或者在每次写入命令时追加操作到日志文件中,日志文件只进行追加操作,当 AOF 文件变的过大时,自动对 AOF 进行重写,重写仅保留恢复当前数据集所需的最小命令集合。
+ - 优点: 有序保存了对数据库执行的所有写入操作,数据不容易丢失,即使发生故障停机,也只会丢失上一次写入日志文件操作之后的数据,更可靠且更容易对文件进行分析。
+ - 缺点: 一般相同的数据集来说,AOF 体积要更大,而且速度可能会慢于 RDB。
+
+
+
+!!! note ""
+
+ - appendonly: 是否开启 AOF 备份
+ - appendfsync: 同步频率
+ - always: 每次写入时;
+ - everysec: 每秒;
+ - no: 不同步。
+
+
+
+!!! note ""
+
+ - 设置持久化策略,当 Redis 满足其中任意一个条件时,将触发 RDB 持久化。
\ No newline at end of file
diff --git a/docs/user_manual/hosts/file.md b/docs/user_manual/hosts/file.md
new file mode 100644
index 00000000..5066731e
--- /dev/null
+++ b/docs/user_manual/hosts/file.md
@@ -0,0 +1,40 @@
+## 1 文件操作
+
+!!! note ""
+ 文件管理实现了很多实用的文件操作,除了基本的剪切、复制、粘贴、删除操作,还支持上传和下载文件、解压和解压、加密和解密、批量操作。
+
+## 2 修改权限
+
+!!! note ""
+ 点击文件列表“权限”列中的值(类似 0755、0644),可对文件的权限进行修改。
+
+!!! note ""
+ Linux 中文件权限可按照以下三个不用角色分别进行设置:
+
+ - 文件所有者
+ - 所属用户组
+ - 其它用户
+
+ 在修改权限的窗口中,可直接勾选不同角色所具备的权限,下方的权限代码会随之自动变化。
+
+ 如果你要修改的是目录的权限,勾选“同时修改子目录权限”后,目录中的所有文件和目录的权限也都会发生变化。
+
+## 3 上传文件
+
+!!! note ""
+ 点击工具栏中的“上传”按钮,可将本地电脑的文件上传到服务器上:
+
+## 4 在线下载文件
+
+!!! note ""
+ 如果想从其它服务器上下载文件到当前服务器上,可点击工具栏上的“在线下载”按钮进行操作:
+
+## 5 下载文件
+
+!!! note ""
+ 如果需要将服务器上的文件下载到本地,点击文件右侧下拉菜单中的“下载”即可:
+
+## 6 压缩和解压
+
+!!! note ""
+ 文件管理支持多种格式的压缩和解压,默认压缩格式为 .tar.gz,为 Linux 下最为常见的打包压缩格式,建议使用:
diff --git a/docs/user_manual/hosts/firewall.md b/docs/user_manual/hosts/firewall.md
new file mode 100644
index 00000000..d9dfe120
--- /dev/null
+++ b/docs/user_manual/hosts/firewall.md
@@ -0,0 +1,148 @@
+
+!!! note ""
+ **1Panel 集成了两种广泛使用的 Linux 防火墙软件:Firewalld 和 UFW。**
+
+ - RedHat/CentOS 使用的是 Firewall 防火墙。
+ - Debian/Ubuntu使用的是 UFW 防火墙。
+
+## 1 安装
+
+=== "RedHat / CentOS"
+ !!! note ""
+ **1、更新软件包**
+
+ ```bash
+ sudo yum update
+ ```
+
+ **2、安装 firewalld**
+
+ ```bash
+ sudo yum install firewalld
+ ```
+
+ **3、启动 firewalld**
+
+ ```bash
+ sudo systemctl start firewalld
+ ```
+
+ **4、如果你在远程位置连接你的服务器,在启用 firewalld 防火墙之前,你必须显式允许进来的 SSH 连接。否则,你将永远都无法连接到机器上。**
+
+ ```bash
+ sudo firewall-cmd --zone=public --add-port=22/tcp --permanent
+ ```
+
+ > 如果 SSH 运行在非标准端口,你需要将上述命令中的 22 端口替换为对应的 SSH 端口。
+
+ **5、放开 1Panel 系统端口。**
+
+ ```bash
+ sudo firewall-cmd --zone=public --add-port=8090/tcp --permanent
+ ```
+
+ > 上述命令中的 8090 端口需要替换为安装 1Panel 系统时自定义的端口。
+
+ **6、重新加载防火墙规则,使更改生效**
+
+ ```bash
+ sudo firewall-cmd --reload
+ ```
+
+ **7、设置开机启动 firewalld**
+
+ ```bash
+ sudo systemctl enable firewalld
+ ```
+
+=== "Ubuntu / Debian"
+ !!! note ""
+ **1、更新软件包**
+
+ ```bash
+ sudo apt update
+ ```
+
+ **2、安装 UFW**
+
+ ```bash
+ sudo apt install ufw
+ ```
+
+ **3、如果你在远程位置连接你的服务器,在启用 UFW 防火墙之前,你必须显式允许进来的 SSH 连接。否则,你将永远都无法连接到机器上。**
+
+ ```bash
+ sudo ufw allow 22/tcp
+ ```
+
+ > 如果 SSH 运行在非标准端口,你需要将上述命令中的 22 端口替换为对应的 SSH 端口。
+
+ **4、放开 1Panel 系统端口。**
+
+ ```bash
+ sudo ufw allow 8090/tcp
+ ```
+
+ > 上述命令中的 8090 端口需要替换为安装 1Panel 系统时自定义的端口。
+
+ **5、启动 UFW**
+
+ ```bash
+ sudo ufw enable
+ ```
+
+## 2 防火墙状态
+
+!!! note ""
+ **点击防火墙开关按钮,即可开启或关闭防火墙。**
+
+
+
+!!! note ""
+ **点击禁 ping 按钮,即可开启或关闭 PING 命令。**
+
+ - 禁用 PING 命令的主要功能是:为了防止用户频繁 PING 服务器而导致服务器性能下降。
+
+
+
+## 3 端口规则
+
+!!! note ""
+ **点击创建端口规则按钮,即可设置端口规则。**
+
+ - 协议:默认为 TCP 协议,有 TCP、UDP、TCP/UDP 协议,根据你的实际情况选择。
+ - 端口:输入你要设置规则的端口,自定义,端口范围是:0-65535。
+ - 来源:默认为所有 IP,选择有:所有 IP、指定 IP。
+ - 策略:默认为允许,有允许、拒绝。
+
+
+!!! note ""
+ **端口放行成功后,可以查看防火墙列表查看当前端口的运行情况。**
+
+
+
+
+
+## 4 端口转发
+
+!!! note ""
+ **点击创建端口转发按钮,即可设置端口转发规则。**
+
+ - 协议:默认为 TCP 协议,有 TCP、UDP、TCP/UDP 协议,根据你的实际情况选择。
+ - 源端口:发送至源端口的报文,将被转发至 `目标 IP:目标端口`,端口范围是:0-65535。
+ - 目标 IP:如果是本机端口转发,目标IP为:127.0.0.1;如果目标IP不填写,则默认为本机端口转发。
+ - 目标端口:接收转发报文的目标端口。
+
+
+
+## 5 IP 规则
+
+!!! note ""
+ **点击创建 IP 规则按钮,即可设置IP规则**
+
+ - 指定 IP
+ - 策略:默认为放行,有放行、屏蔽。
+
+
+
+
diff --git a/docs/user_manual/hosts/monitor.md b/docs/user_manual/hosts/monitor.md
new file mode 100644
index 00000000..07abf5ca
--- /dev/null
+++ b/docs/user_manual/hosts/monitor.md
@@ -0,0 +1,13 @@
+## 1 查看监控
+
+!!! note ""
+ 点击【主机 - 监控】菜单,进入监控报表,直观的了解服务器的运行状态,包含【平均负载】、【CPU性能监控】、【内存使用监控】、【磁盘IO监控】、【网络IO监控】。
+
+ 通过时间监控指标上方的时间选择组件,可以调整监控数据的时间范围。
+
+
+
+## 2 修改设置
+
+!!! note ""
+ 在监控设置页面,可以开启/关闭监控功能,修改监控数据的保存时长,修改监控数据的采集间隔,或者手动清空监控记录。
\ No newline at end of file
diff --git a/docs/user_manual/hosts/process.md b/docs/user_manual/hosts/process.md
new file mode 100644
index 00000000..53088c30
--- /dev/null
+++ b/docs/user_manual/hosts/process.md
@@ -0,0 +1,23 @@
+## 1 查看进程
+
+!!! note ""
+ 点击【主机 - 进程管理】菜单,进入进程管理页面。
+
+ - 在列表中可以查看系统中的所有进程信息
+ - 列表上方筛选组件可以根据进程 ID、进程名称、用户等信息对进程进行筛选
+ - 列表中可以根据 PID、父进程 ID、CPU 使用率、内存使用率进行排序,根据进程状态进行筛选
+ - 点击操作列的 `详情`,可以查看进程的更多信息,包括基本信息、内存信息、打开的文件、环境变量及网络连接信息等
+ - 点击操作列的 `结束`,可以结束掉指定进程
+
+
+
+## 2 查看网络连接信息
+
+!!! note ""
+ 点击当前页面上方的 `网络` 选项,可以进入网络连接列表。
+
+ - 在列表中可以查看系统中的所有网络连接及端口使用信息
+ - 列表上方筛选组件可以更具进程 ID、进程名称、端口号进行筛选
+ - 列表中可以根据 PID 进行排序,根据连接状态进行筛选
+
+
diff --git a/docs/user_manual/hosts/ssh.md b/docs/user_manual/hosts/ssh.md
new file mode 100644
index 00000000..e1b51571
--- /dev/null
+++ b/docs/user_manual/hosts/ssh.md
@@ -0,0 +1,23 @@
+## 1 配置 SSH 服务
+
+!!! note ""
+ 在 SSH 管理配置页面,可以开启/关闭/重启 SSH 服务,设置 SSH 服务开机自启动,同时支持可视化调整监听端口、监听地址等常用配置,或者通过配置文件方式修改其他配置。
+
+
+
+## 2 管理 SSH 会话
+
+!!! note ""
+ 点击当前页面上方的 `会话` 选项,可以进入 SSH 会话列表。
+
+ - 在列表中可以查看系统中的所有活跃的 SSH 会话信息
+ - 点击操作列的 `断开`,可以断开指定的 SSH 会话
+
+
+
+## 2 查看 SSH 登录日志
+
+!!! note ""
+ 点击当前页面上方的 `登录日志` 选项,可以进入 SSH 登录日志列表。
+
+
diff --git a/docs/user_manual/hosts/terminal.md b/docs/user_manual/hosts/terminal.md
new file mode 100644
index 00000000..93bdd128
--- /dev/null
+++ b/docs/user_manual/hosts/terminal.md
@@ -0,0 +1,20 @@
+## 1 终端管理
+
+!!! note ""
+ 点击【主机 - 终端】菜单,进入终端页面,终端默认连接本地服务器,如未填写本地服务器登录信息,则连接失败。
+
+ - 支持直接选择已有主机连接(【终端 - 主机】菜单中维护)和连接新主机;
+ - 支持重新连接;
+ - 支持打开多个本地服务器;
+ - 支持全屏操作;
+ - 支持快速快速命令(需要在【终端 - 快速命令】菜单中维护),用户可预定于常用快速命令;
+ - 支持当前所有连接批量输入。
+
+
+
+## 2 主机管理
+
+!!! note ""
+ 维护主机信息,支持主机分组。
+
+
\ No newline at end of file
diff --git a/docs/user_manual/logs.md b/docs/user_manual/logs.md
new file mode 100644
index 00000000..43821b97
--- /dev/null
+++ b/docs/user_manual/logs.md
@@ -0,0 +1,39 @@
+## 1 面板日志
+
+### 操作日志
+
+用于记录用户在 1Panel 上进行的操作。
+
+
+
+### 访问日志
+
+用于记录 1Panel 控制台的访问日志。
+
+
+
+### 系统日志
+
+用于记录 1Panel 服务的运行日志,可用于开发人员等快速定位问题。
+
+
+
+## 2 登录日志
+
+主要记录服务器的 ssh 登录记录,可用于查询是否有人恶意登录和操作。
+
+!!! note "提示"
+
+ 日志内容从操作系统 SSH 登录日志文件中读取而来,文件位置一般为 `/var/log/secure` 或者 `/var/log/auth.log`。
+
+ 当需要清理登录日志时,可以手动删除上述文件中的历史内容。
+
+
+
+## 3 网站日志
+
+用于查看在 1Panel 上创建的各个网站的日志,分为运行日志和错误日志,可以用于排查网站的访问问题。
+
+
+
+
\ No newline at end of file
diff --git a/docs/user_manual/mcp/mcp_server.md b/docs/user_manual/mcp/mcp_server.md
new file mode 100644
index 00000000..fb87e411
--- /dev/null
+++ b/docs/user_manual/mcp/mcp_server.md
@@ -0,0 +1,138 @@
+# 1Panel MCP Server
+
+1Panel MCP 服务器是一个用于 1Panel 的模型上下文协议(Model Context Protocol,MCP)服务器实现。
+
+## 安装
+
+### 前提条件
+
+- Go 1.23.0 或更高版本 (二进制使用方式)
+- Docker (Docker 使用方式)
+- 已安装 1Panel
+
+### 从源代码构建 (二进制)
+
+1. 克隆代码仓库:
+
+```bash
+git clone https://github.com/1Panel-dev/mcp-1panel.git
+cd mcp-1panel
+```
+
+2. 构建项目:
+
+```bash
+make build
+```
+
+将 `./build/mcp-1panel` 移动到系统环境变量 PATH 所包含的目录中。
+
+### 使用 `go install` 安装
+
+```bash
+go install github.com/1Panel-dev/mcp-1panel@latest
+```
+
+## 使用方式
+
+你可以将 1Panel MCP Server 与 Cursor 和 Windsurf 等工具配合使用。
+
+### stdio 模式
+
+#### 二进制方式
+
+确保已安装 Go 并已构建或安装该二进制文件:
+
+```json
+{
+ "mcpServers": {
+ "mcp-1panel": {
+ "command": "mcp-1panel",
+ "env": {
+ "PANEL_ACCESS_TOKEN": "",
+ "PANEL_HOST": "such as http://localhost:8080"
+ }
+ }
+ }
+}
+```
+
+#### Docker 方式
+
+确保已安装 Docker:
+
+```json
+{
+ "mcpServers": {
+ "mcp-1panel": {
+ "command": "docker",
+ "args": [
+ "run",
+ "-i",
+ "--rm",
+ "-e",
+ "PANEL_HOST",
+ "-e",
+ "PANEL_ACCESS_TOKEN",
+ "1panel/1panel-mcp-server"
+ ],
+ "env": {
+ "PANEL_HOST": "such as http://localhost:8080",
+ "PANEL_ACCESS_TOKEN": ""
+ }
+ }
+ }
+}
+```
+
+### SSE 模式
+
+使用 SSE 启动 MCP server:
+
+```bash
+mcp-1panel -host -token -transport sse -addr "http://localhost:8000/"
+```
+
+Cursor/Windsurf 配置示例:
+
+```json
+{
+ "mcpServers": {
+ "mcp-1panel": {
+ "url": "http://localhost:8000/sse"
+ }
+ }
+}
+```
+
+### 命令行选项
+
+- `-token`:1Panel 访问令牌
+- `-host`:1Panel 访问地址
+- `-transport`:传输类型(stdio 或 sse,默认:stdio)
+- `-sse-port`:启动 SSE 服务器端口(默认:8000)
+
+### 环境变量
+
+您也可以使用环境变量配置服务器:
+
+- `PANEL_HOST`:1Panel 访问地址
+- `PANEL_ACCESS_TOKEN`:1Panel 访问令牌
+
+## 可用工具
+
+服务器提供了各种与 1Panel 交互的工具:
+
+| 工具 | 类别 | 描述 |
+|-----------------------------|------|------------------|
+| **get_dashboard_info** | 系统 | 列出概览页状态 |
+| **get_system_info** | 系统 | 获取系统信息 |
+| **list_websites** | 网站 | 列出所有网站 |
+| **create_website** | 网站 | 创建网站 |
+| **list_ssls** | 证书 | 列出所有证书 |
+| **create_ssl** | 证书 | 创建证书 |
+| **list_installed_apps** | 应用 | 列出所有已安装应用 |
+| **install_openresty** | 应用 | 安装 OpenResty |
+| **install_mysql** | 应用 | 安装 MySQL |
+| **list_databases** | 数据库 | 列出所有数据库 |
+| **create_database** | 数据库 | 创建数据库 |
diff --git a/docs/user_manual/settings.md b/docs/user_manual/settings.md
new file mode 100644
index 00000000..f130a93c
--- /dev/null
+++ b/docs/user_manual/settings.md
@@ -0,0 +1,212 @@
+## 1 面板
+
+!!! note ""
+ 支持面板的一些基础设置,具体包括:
+
+ - 面板用户:1Panel 系统仅支持单主机单用户,此处是用于登录 1Panel 面板的验证信息,在初次登陆时由用户初始化。
+ - 面板密码:用于登录 1Panel 面板的密码。
+ - 主题颜色: 系统支持亮色(light)和 暗色(dark),可根据用户使用习惯手动切换,也可以选择跟随系统,根据浏览器及操作系统使用的主题模式自动切换。
+ - 菜单标签页:开启后,将在页面最上方通过多标签页的方式,列出最近访问过的菜单。
+ - 面板别名: 用户可自定义面板名称。
+ - 系统语言: 系统当前支持中文和英文。
+ - 超时时间: 此处为系统用户登陆后,多长时间未操作系统自动退出,最小超时时间为 300 秒。
+ - 服务器地址:设置当前服务器的地址,配置后可以点击应用商店已安装应用的服务端口,快速打开指定应用服务页面。
+ - 代理服务器(✨专业版):配置代理服务器后,1Panel 中的部分网络请求将通过指定的代理服务器进行转发,适合用在内网环境服务器无法直接访问互联网的场景中。
+ - 预览体验计划:开启后可以获取到 1Panel 的预览版本,以分享有关新功能和更新的反馈。
+ - 高级功能菜单隐藏:控制是否在左侧菜单中显示高级功能菜单项。
+
+
+
+## 2 安全
+
+!!! note "配置说明"
+ 针对一些系统要求等级比较高的用户,我们增加了一些安全设置,具体包括:
+
+ - 面板端口:修改 1Panel 服务使用的端口,但是需要谨慎操作,防止与应用端口冲突导致服务无法启动,建议修改端口前先执行 netstat -tunlp | grep [端口] 查看端口是否正在使用。
+ - 监听地址:修改 1Panel 服务监听的 IP 地址,需谨慎操作,防止监听地址后当前客户端无法访问到面板。
+ - 安全入口:开启安全入口后只能通过指定安全入口登录面板,同时支持配置是否开启相关提示。
+ - 未认证设置:配置未使用安全入口访问面板时的返回内容。
+ - 授权 IP:设置授权 IP 后,仅有设置中的 IP 可以访问 1Panel 服务,支持配置多个 IP 地址。
+ - 域名绑定:设置域名绑定后,仅能通过设置中域名访问 1Panel 服务。
+ - 面板 SSL:为面板设置 HTTPS 协议访问,提升面板访问安全性,开启后仅能通过 HTTPS 协议访问 1Panel 服务。
+ - 密码过期时间: 系统支持设置密码过期天数,默认未设置,当密码超过过期时间时,系统将跳转到改密界面,需要修改账户密码,且新密码不能与老密码相同。
+ - 密码复杂度校验: 开启后,账户密码必须长度大于 8 位,且包含数字、字母及特殊字符,如 Password@2023。
+ - 两步校验: 开启 MFA 登录验证,登录时输入用户名密码后,需要手机或者浏览器扫描二维码完成登录,提升系统安全等级。
+
+
+
+!!! warning "注意"
+ 以上设置修改后会影响访问 1Panel 服务的方式,可能导致不能正常打开、登录 1Panel 面板的情况。
+
+ 此时可以 SSH 登录到服务器后,使用 `1pctl reset` 和 `1pctl update` 命令重置或更新特定配置。
+
+ ```text
+ root@hostname:/# 1pctl reset --help
+ 重置系统信息
+
+ Usage:
+ 1panel reset [command]
+
+ Available Commands:
+ domain 取消 1Panel 访问域名绑定
+ entrance 取消 1Panel 安全入口
+ https 取消 1Panel https 方式登录
+ ips 取消 1Panel 授权 IP 限制
+ mfa 取消 1Panel 两步验证
+
+ Flags:
+ -h, --help help for reset
+
+ Use "1panel reset [command] --help" for more information about a command.
+ ```
+
+ ```text
+ root@hostname:/# 1pctl update
+ 修改面板信息
+
+ Usage:
+ 1panel update [command]
+
+ Available Commands:
+ password 修改面板密码
+ port 修改面板端口
+ username 修改面板用户
+
+ Flags:
+ -h, --help help for update
+
+ Use "1panel update [command] --help" for more information about a command.
+ ```
+
+## 3 备份账号
+
+### 3.1 已支持的备份账号
+
+!!! note ""
+ **支持添加本地服务器磁盘和第三方账号:**
+
+ - 亚马逊 S3 云存储
+ - 阿里云 OSS
+ - 腾讯云 COS
+ - 微软 OneDrive
+ - 七牛云 Kodo
+ - 又拍云 对象存储
+ - MINIO
+ - SFTP
+ - WebDAV
+
+### 3.2 OneDrive 自定义配置
+
+!!! note ""
+ **在调用 Onedrive API 时需要使用到 4 个参数:**
+
+ - client_id: 客户端ID
+ - client_secret: 客户端密码
+ - redirect_uri: 重定向地址
+ - scope: API权限
+
+1. 访问并登录 MicroSoft Azure:https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade
+
+2. 点击新注册,并填写注册信息,其中的重定向 URI 作为 重定向 Url 参数
+
+
+
+3. 主页上的 应用程序(客户端) ID 作为 客户端 ID
+
+
+
+4. 在 证书和密码 页面新建客户端密码,填写相关信息,生成的值作为 客户端密钥
+
+
+
+5. 在 API 权限页面选择需要的权限,添加权限,Microsoft Graph,委托的权限,勾选 Files.ReadWrite.All、offline_access、User.Read,这将作为 scope 传递
+
+
+
+### 3.3 OneDrive 账号绑定
+
+1. 点击 OneDrive 授权码获取按钮
+
+
+
+2. 输入 Onedrive 账号信息
+
+
+
+3. 信任 1panel 服务
+
+
+
+4. 复制授权码到 1Panel 授权码输入框 (注意不要包含 &session_state=xxx 部分)
+
+
+
+### 3.4 WebDAV 连接 AList
+
+1. 从应用商店安装好 AList 后(记得打开端口外部访问),在容器日志中查看初始化密码,跳转到 AList 管理界面。
+
+2. 存储 菜单中添加对应的存储,记住该路径。
+
+
+
+3. 1Panel 备份账号中,WebDAV 添加该备份账号,这里的路径应该是 /dav/${2步骤中的路径}/xxx,如此处的 /dav/tmp/sftp/1panel,完成绑定。
+
+
+
+### 3.5 部分对象存储服务商与亚马逊 S3 云存储的兼容性
+
+|服务商|文档|兼容访问风格|兼容性|
+| ----- | ---- | ----- | ----- |
+|阿里云|https://help.aliyun.com/document_detail/410748.html|Virtual Hosted Style|✅|
+|腾讯云|[https://cloud.tencent.com/document/product/436/41284](https://cloud.tencent.com/document/product/436/41284)|Virtual Hosted Style /
Path Style|✅|
+|七牛云|https://developer.qiniu.com/kodo/4088/s3-access-domainname|Virtual Hosted Style /
Path Style|✅|
+|百度云|https://cloud.baidu.com/doc/BOS/s/Fjwvyq9xo|Virtual Hosted Style /
Path Style|✅|
+|京东云| https://docs.jdcloud.com/cn/object-storage-service/api/regions-and-endpoints |Virtual Hosted Style|✅|
+|金山云|https://docs.ksyun.com/documents/6761|Virtual Hosted Style|✅|
+|青云|https://docsv3.qingcloud.com/storage/object-storage/s3/intro/|Virtual Hosted Style /
Path Style|✅|
+|网易数帆|[https://sf.163.com/help/documents/89796157866430464](https://sf.163.com/help/documents/89796157866430464)|Virtual Hosted Style|✅|
+|Cloudflare|Cloudflare S3 兼容性API
[https://developers.cloudflare.com/r2/data-access/s3-api/](https://developers.cloudflare.com/r2/data-access/s3-api/)|Virtual Hosted Style /
Path Style|✅|
+| Oracle Cloud |[https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm](https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm)|Virtual Hosted Style /
Path Style|✅|
+|自建minio|\-|Path Style|✅|
+|又拍云|[https://help.upyun.com/knowledge-base/aws-s3%E5%85%BC%E5%AE%B9/](https://help.upyun.com/knowledge-base/aws-s3%E5%85%BC%E5%AE%B9/)|Virtual Hosted Style /
Path Style|✅|
+|华为云|文档未说明是否兼容,工单反馈不保证兼容性,实际测试可以使用|Virtual Hosted Style|❓|
+|Ucloud|只支持 8MB 大小的分片,本插件暂不支持
[https://docs.ucloud.cn/ufile/s3/s3\_introduction](https://docs.ucloud.cn/ufile/s3/s3_introduction)|\-|❌|
+
+## 4 快照
+
+!!! note ""
+ 快照用于全量备份 1Panel 所产生的数据,具体包括:
+
+ - Docker 配置文件,路径为 /etc/docker/daemon.json;
+ - 应用商店应用,可在【应用商店 - 已安装】中查看;
+ - 本地备份数据,可在【面板设置 - 备份账号】中查看;
+ - 1Panel 产生的数据,将压缩整个 [安装目录]/1panel 目录,包括数据库文件;
+ - 1panel 二进制文件,路径为 /usr/local/bin/1panel;
+ - 1pctl 命令行工具,路径为 /usr/local/bin/1pctl;
+ - 1panel.service 路径为 /etc/systemd/system/1panel.service;
+
+
+
+!!! note ""
+
+ - 创建和同步快照只支持选择第三方账号。
+ - 快照恢复过程中,将对恢复前数据进行备份,默认的备份路径为 [安装目录]/original_[快照名]。
+ - 快照恢复失败后,可选择根据【面板日志 - 系统日志】排查失败原因后,重试恢复,或者直接回滚到恢复之前的版本。
+ - 如果上述操作都不能使服务正常运行,则需要手动拿到恢复前的备份文件,手动替换当前系统数据,然后重启系统。
+ - 如机器迁移等,需要将快照放到备份账号对应的指定目录下,如服务器磁盘:/opt/1panel/backup/system_snapshot/ 。
+
+## 5 许可证
+
+!!! note ""
+ 用于查看当前许可证状态,导入专业版许可证并成功激活后,可以使用专业版相关功能。
+
+ [探索专业版带来的更多可能](https://www.lxware.cn/1panel)
+
+## 6 关于
+
+!!! note ""
+
+ - 支持检查 1Panel 服务是否存在新版本,更新将替换 1panel 二进制文件、1pctl 命令行工具以及 1panel.service 文件。
+ - 更新失败时,将回滚所有更新内容到更新前的状态,如更新后发现版本信息没有发生变化,则更新失败,可在【面板日志 - 系统日志】中查看失败原因,解决后重新完成更新操作。
+
+
diff --git a/docs/user_manual/toolbox/clam.md b/docs/user_manual/toolbox/clam.md
new file mode 100644
index 00000000..fc5d7ddc
--- /dev/null
+++ b/docs/user_manual/toolbox/clam.md
@@ -0,0 +1,158 @@
+
+## 1 介绍
+
+!!! note ""
+ ClamAV 是一个开源(GPLv2许可)的反病毒工具包,专为邮件网关上的电子邮件扫描而设计。它提供了多种实用工具,包括灵活且可扩展的多线程守护进程、命令行扫描器以及用于自动更新数据库的高级工具。该工具包的核心是一个作为共享库形式提供的反病毒引擎。
+
+## 2 环境要求
+
+!!! note ""
+ **ClamAV 的最低建议配置为:**
+
+ * CPU 要求:1 CPU,2.0 Ghz+;
+ * 内存要求:3 GiB+;
+ * 服务器架构:至少 5GiB 可用磁盘空间。
+
+## 3 安装
+
+=== "RedHat / CentOS"
+ !!! note ""
+ **1、安装 epel 源**
+
+ ```bash
+ yum install -y epel-release
+ ```
+
+ **2、安装 ClamAV**
+
+ ```bash
+ yum install clamav clamd clamav-update -y
+ ```
+
+ **3、修改 ClamAV 配置文件**
+
+ ```bash
+ /etc/clamd.d/scan.conf 取消下面行注释
+ LogFile /var/log/clamd.scan
+ LogFileMaxSize 2M
+ PidFile /run/clamd.scan/clamd.pid
+ DatabaseDirectory /var/lib/clamav
+ LocalSocket /run/clamd.scan/clamd.sock
+ ```
+
+ **4、修改病毒库刷新配置文件**
+
+ ```bash
+ /etc/freshclam.conf 取消下面行注释
+ DatabaseDirectory /var/lib/clamav
+ UpdateLogFile /var/log/freshclam.log
+ PidFile /var/run/freshclam.pid
+ DatabaseMirror database.clamav.net
+ Checks 12
+ ```
+
+ **5、启动 ClamAV 服务**
+
+ ```bash
+ freshclam
+ systemctl start clamd@scan.service
+ systemctl start clamav-freshclam.service
+ ```
+
+ **6、开机自启动**
+
+ ```bash
+ systemctl enable clamd@scan.service
+ systemctl enable clamav-freshclam.service
+ ```
+
+ **7、查看 ClamAV 服务状态。**
+
+ ```bash
+ systemctl status clamd@scan.service
+ systemctl status clamav-freshclam.service
+ ```
+
+=== "Ubuntu / Debian"
+ !!! note ""
+ **1、安装 ClamAV**
+
+ ```bash
+ sudo apt install clamav clamav-daemon -y
+ ```
+
+ **2、启动 ClamAV 服务**
+
+ ```bash
+ freshclam
+ sudo systemctl start clamav-daemon
+ sudo systemctl start clamav-freshclam.service
+ ```
+
+ **4、开机自启动**
+
+ ```bash
+ sudo systemctl enable clamav-daemon
+ sudo systemctl enable clamav-freshclam.service
+ ```
+
+ **5、查看 ClamAV 服务状态。**
+
+ ```bash
+ sudo systemctl status clamav-daemon
+ sudo systemctl status clamav-freshclam.service
+ ```
+
+## 4 扫描规则
+
+!!! note "配置说明"
+
+ - 扫描目录:病毒扫描任务扫描的目标目录
+ - 感染文件策略:发现感染文件后,需要执行的操作方式,支持不操作、删除文件、移动文件到隔离目录、复制文件到隔离目录
+ - 定时扫描(✨专业版):配置定时任务,定时执行扫描任务
+ - 是否告警(✨专业版):扫描到感染文件后,发送短信告警
+
+!!! note ""
+
+ 点击操作列的 `执行` 可以手动执行该条扫描规则,点击 `报告` 即可查看该条扫描规则的执行记录和扫描结果。
+
+
+
+## 5 病毒类型说明
+
+|类型|说明|
+| ----- | ---- |
+|Adware|广告软件,通常在用户不知情的情况下显示广告。|
+|Backdoor|后门,允许攻击者远程访问和控制受感染系统的程序或功能。|
+|Coinminer|加密货币挖矿程序,用于非法挖掘加密货币的恶意软件。|
+|Countermeasure|反对抗措施,指示该签名用于识别防御性安全工具。|
+|Downloader|下载器,用于下载和执行其他恶意软件或组件的程序。|
+|Dropper|放置器,用于将其他恶意软件注入到受感染系统中的程序。|
+|Exploit|漏洞利用程序,利用系统或应用程序中的漏洞进行攻击的恶意软件。|
+|File|文件类型,用于描述独立文件的签名。|
+|Filetype|文件类型,描述恶意文件的类型。|
+|Infostealer|信息窃取程序,用于窃取用户敏感信息的恶意软件。|
+|Ircbot|IRC 机器人,用于连接到 IRC(Internet Relay Chat)网络的恶意软件。|
+|Joke|恶作剧,不良影响系统但通常不造成实际损害的恶意软件。|
+|Keylogger|键盘记录器,用于记录用户输入的恶意软件。|
+|Loader|装载器,用于加载和执行其他恶意软件的程序。|
+|Macro|宏病毒,针对文档或电子表格中的宏命令进行攻击的恶意软件。|
+|Malware|恶意软件,一般术语,指任何有害的计算机程序。|
+|Packed/Packer|打包/打包工具,用于压缩和加密恶意软件以逃避检测的程序。|
+|Phishing|钓鱼,用于欺骗用户输入个人信息的恶意软件。|
+|Proxy|代理,用于通过受感染系统进行网络通信的恶意软件。|
+|Ransomware|勒索软件,加密用户文件并勒索解密费用的恶意软件。|
+|Revoked|已撤销的,指示签名或证书已被官方撤销的恶意软件。|
+|Rootkit|根套件,用于隐藏恶意软件活动和存在的程序。|
+|Spyware|间谍软件,用于监视用户活动并发送给攻击者的恶意软件。|
+
+## 6 故障排除
+
+!!! note ""
+
+ - 如果 clamav 服务无法启动,请检查配置信息以及日志;
+ - 检查病毒库数据是否正常,在配置文件中会指定 DatabaseDirectory ,即病毒库存放位置,检查是否存在,不存在的话,手动执行一下 freshclam 命令。
+ - 如果手动执行 freshclam 也无法正常下载的话,可以从以下地址下载后传到该目录下。
+ + https://database.clamav.net/daily.cvd
+ + https://database.clamav.net/bytecode.cvd
+ + https://database.clamav.net/main.cvd
diff --git a/docs/user_manual/toolbox/clean.md b/docs/user_manual/toolbox/clean.md
new file mode 100644
index 00000000..846ae05a
--- /dev/null
+++ b/docs/user_manual/toolbox/clean.md
@@ -0,0 +1,33 @@
+!!! note ""
+
+ 在 `缓存清理` 页面,可以扫描并清理 1Panel 运行期间积累的垃圾文件,包括:
+
+ - 系统垃圾
+ - 系统快照恢复前备份文件
+ - 系统升级备份文件
+ - 系统快照临时文件
+ - 恢复前备份文件
+ - 系统缓存文件
+ - 系统废弃目录
+ - 容器垃圾
+ - 所有违背任何容器使用的镜像
+ - 所有处于停止状态的容器
+ - 存储卷
+ - 构建缓存
+ - 临时上传文件
+ - 临时长传文件
+ - 应用
+ - 网站
+ - 数据库
+ - 文件夹
+ - 临时下载文件
+ - 应用
+ - 网站
+ - 数据库
+ - 文件夹
+ - 系统日志文件
+ - 系统日志文件
+ - 容器操作日志文件
+ - 计划任务执行日志文件
+
+
diff --git a/docs/user_manual/toolbox/fail2ban.md b/docs/user_manual/toolbox/fail2ban.md
new file mode 100644
index 00000000..b2694a11
--- /dev/null
+++ b/docs/user_manual/toolbox/fail2ban.md
@@ -0,0 +1,108 @@
+
+## 1 安装
+
+=== "RedHat / CentOS"
+ !!! note ""
+ **1、安装 epel 源**
+
+ ```bash
+ yum install -y epel-release
+ ```
+
+ **2、安装 Fail2ban**
+
+ ```bash
+ yum install -y fail2ban
+ ```
+
+ **3、启动 Fail2ban 服务**
+
+ ```bash
+ systemctl start fail2ban
+ ```
+
+ **4、开机自启动**
+
+ ```bash
+ systemctl enable fail2ban
+ ```
+
+ **5、查看 Fail2ban 服务状态。**
+
+ ```bash
+ systemctl status fail2ban
+ ```
+
+=== "Ubuntu / Debian"
+ !!! note ""
+ **1、安装 Fail2ban**
+
+ ```bash
+ sudo apt-get install fail2ban
+ ```
+
+ **2、Debian 12 及以上的版本需要手动安装 rsyslog**
+
+ ```bash
+ sudo apt-get install rsyslog
+ ```
+
+ **3、启动 Fail2ban 服务**
+
+ ```bash
+ sudo systemctl start fail2ban
+ ```
+
+ **4、开机自启动**
+
+ ```bash
+ sudo systemctl enable fail2ban
+ ```
+
+ **5、查看 Fail2ban 服务状态。**
+
+ ```bash
+ sudo systemctl status fail2ban
+ ```
+
+## 2 默认配置
+
+!!! note ""
+
+ 1Panel 会默认使用以下配置:
+ ```properties
+ #DEFAULT-START
+ [DEFAULT]
+ bantime = 600
+ findtime = 300
+ maxretry = 5
+ banaction = firewallcmd-ipset
+ action = %(action_mwl)s
+ #DEFAULT-END
+
+ [sshd]
+ ignoreip = 127.0.0.1/8 # 白名单
+ enabled = true
+ filter = sshd
+ port = 22 # 端口
+ maxretry = 2 # 最大尝试次数
+ findtime = 300 # 发现周期 单位s
+ bantime = 600 # 封禁时间,单位s。-1为永久封禁
+ action = %(action_mwl)s
+ banaction = iptables-multiport # 禁用方式
+ logpath = /var/log/secure # SSH 登陆日志位置
+ ```
+
+## 3 故障排除
+
+!!! note ""
+
+ - 如之前已经手动安装过 Fail2ban,需要将 [sshd] 部分的配置信息写入到 jail.local 中,重启 fail2ban 服务,否则可能出现获取黑名单报错的问题;
+ - 如果选择的禁用方式为 -muliport,则在封禁时,只会禁用配置中的端口,如默认配置中的 22;
+ - 如果需要修改禁用方式,需要先判读对应服务是否正常可用;
+ - RedHat/CentOS 使用的是 Firewall 防火墙。
+ - Debian/Ubuntu使用的是 UFW 防火墙。
+ - 日志路径需要根据操作系统修改。
+ - RedHat/CentOS 日志为 /var/log/secure。
+ - Debian/Ubuntu 日志为 /var/log/auth.log
+ - Debian 从 12 开始弃用了 rsyslog,使用时需要先自行安装;
diff --git a/docs/user_manual/toolbox/ftp.md b/docs/user_manual/toolbox/ftp.md
new file mode 100644
index 00000000..c16d0d70
--- /dev/null
+++ b/docs/user_manual/toolbox/ftp.md
@@ -0,0 +1,96 @@
+
+## 1 安装
+
+=== "RedHat / CentOS"
+ !!! note ""
+ **1、安装 epel 源**
+
+ ```bash
+ yum install -y epel-release
+ ```
+
+ **2、安装 Pure-FTPd**
+
+ ```bash
+ yum -y install pure-ftpd
+ ```
+
+ **3、修改默认配置**
+
+ ```bash
+ # 默认配置位于 /etc/pure-ftpd/pure-ftpd.conf,在配置文件中找到下面几个参数进行修改:
+
+ # 指定路径,PureDB用户数据库文件
+ PureDB /etc/pure-ftpd/pureftpd.pdb
+ # 开启日志
+ VerboseLog yes
+ # 拒绝匿名登录
+ NoAnonymous yes
+ # 开启被动端口范围 (这里需要根据实际需求调整端口范围)
+ PassivePortRange 39000 40000
+ ```
+
+ **4、启动 Pure-FTPd 服务**
+
+ ```bash
+ systemctl start pure-ftpd.service
+ ```
+
+ **5、查看 Pure-FTPd 服务状态。**
+
+ ```bash
+ systemctl status pure-ftpd.service
+ ```
+
+=== "Ubuntu / Debian"
+ !!! note ""
+ **1、安装 Pure-FTPd**
+
+ ```bash
+ sudo apt-get install pure-ftpd
+ ```
+
+ **2、修改默认配置**
+
+ ```bash
+ # 与 centos 不同,这里需要在 /etc/pure-ftpd/conf 文件夹下执行下列命令,增加对应配置文件:
+
+ # 创建 /etc/pure-ftpd/conf/PureDB 文件,内容指定路径 /etc/pure-ftpd/pureftpd.pdb
+ echo '/etc/pure-ftpd/pureftpd.pdb' > /etc/pure-ftpd/conf/PureDB
+ # 创建 /etc/pure-ftpd/conf/VerboseLog 文件,开启日志
+ echo yes > /etc/pure-ftpd/conf/VerboseLog
+ # 创建 /etc/pure-ftpd/conf/NoAnonymous 文件,拒绝匿名登录
+ echo yes > /etc/pure-ftpd/conf/NoAnonymous
+ # 创建 /etc/pure-ftpd/conf/PassivePortRange 文件,开启被动端口范围 (这里需要根据实际需求调整端口范围)
+ echo '39000 40000' > /etc/pure-ftpd/conf/PassivePortRange
+ ```
+
+ **3、建立数据库软链**
+
+ ```bash
+ ln -s /etc/pure-ftpd/conf/PureDB /etc/pure-ftpd/auth/50puredb
+ ```
+
+ **4、启动 Pure-FTPd 服务**
+
+ ```bash
+ sudo systemctl start pure-ftpd.service
+ ```
+
+
+ **5、查看 Pure-FTPd 服务状态。**
+
+ ```bash
+ sudo systemctl status pure-ftpd.service
+ ```
+
+## 2 故障排除
+
+!!! note ""
+
+ - 如果之前已经安装过 Pure-FTPd,可以直接通过界面同步按钮同步到 1panel 上,但是同步过程中无法同步密码,需要在界面上手动编辑;
+ - 如果无法正常连接,可以从以下方向检查:
+ - 防火墙是否开启,是否放行 Pure-FTPd 端口 ( 默认 21,可以通过 netstat -tunlp |grep pure-ftpd 或者 cat /etc/pure-ftpd/pure-ftpd.conf | grep Bind 查询)
+ - 是否放行 Pure-FTPd 被动端口 ( 可以通过 cat /etc/pure-ftpd/pure-ftpd.conf | grep PassivePortRange 或者 cat /etc/pure-ftpd/conf/PassivePortRange 文件查询 )
+ - 是否开启 selinux
+
diff --git a/docs/user_manual/toolbox/quick_settings.md b/docs/user_manual/toolbox/quick_settings.md
new file mode 100644
index 00000000..01f72441
--- /dev/null
+++ b/docs/user_manual/toolbox/quick_settings.md
@@ -0,0 +1,14 @@
+!!! note ""
+
+ 在 `工具箱`-`快速设置` 页面,可以对常用的系统设置进行修改,包括:
+
+ - DNS
+ - Hosts
+ - Swap
+ - 主机名
+ - 操作系统用户密码
+ - NTP 服务器
+ - 系统时区
+ - 服务器时间
+
+
diff --git a/docs/user_manual/toolbox/supervisor.md b/docs/user_manual/toolbox/supervisor.md
new file mode 100644
index 00000000..5721536b
--- /dev/null
+++ b/docs/user_manual/toolbox/supervisor.md
@@ -0,0 +1,86 @@
+
+## 1 安装
+
+=== "RedHat / CentOS"
+ !!! note ""
+ **1、安装 epel 源**
+
+ ```bash
+ yum install -y epel-release
+ ```
+
+ **2、安装 supervisor**
+
+ ```bash
+ yum install -y supervisor
+ ```
+
+ **3、启动 supervisord 服务**
+
+ ```bash
+ systemctl start supervisord
+ ```
+
+ **4、开机自启动**
+
+ ```bash
+ systemctl enable supervisord
+ ```
+
+ **5、查看 supervisord 服务状态。**
+
+ ```bash
+ systemctl status supervisord
+ ```
+
+=== "Ubuntu / Debian"
+ !!! note ""
+ **安装 supervisor**
+
+ ```bash
+ sudo apt-get install supervisor
+ ```
+
+ > 安装成功后,supervisor 会默认启动。
+
+## 2 初始化
+
+!!! note ""
+
+ 首次使用需要先初始化 supervisor,导入配置文件位置和服务名称
+
+{ width="900px" }
+
+!!! note ""
+
+ 后期服务名称和配置文件有变动,可以在设置页面进行重新初始化
+
+
+{ width="900px" }
+
+
+## 3 创建
+
+!!! note ""
+
+ 点击创建守护进程按钮,填写相应参数,点击确认
+
+{ width="900px" }
+
+
+## 4 守护进程管理
+
+!!! note ""
+
+ 列表页面可以操作守护进程,包括启动、停止、重启、查看日志、编辑、删除、修改源文等
+
+{ width="900px" }
+
+
+## 5 Supervisor 管理
+
+!!! note ""
+
+ Supervisor 状态栏可以重启 停止 Supervisor 服务,查看日志,修改配置文件等
+
+{ width="900px" }
diff --git a/docs/user_manual/websites/certificate.md b/docs/user_manual/websites/certificate.md
new file mode 100644
index 00000000..db9de83c
--- /dev/null
+++ b/docs/user_manual/websites/certificate.md
@@ -0,0 +1,6 @@
+
+!!! note ""
+
+ 管理证书相关,包括申请证书、续约证书、ACME 账户管理,DNS账户管理等。
+
+{ width="900px" }
diff --git a/docs/user_manual/websites/certificate_acme.md b/docs/user_manual/websites/certificate_acme.md
new file mode 100644
index 00000000..55138d50
--- /dev/null
+++ b/docs/user_manual/websites/certificate_acme.md
@@ -0,0 +1,8 @@
+## 1 Acme 账户管理
+
+!!! note ""
+
+ 点击证书列表上方的【Acme 账户】按钮,弹出 Acme 账户管理页面。在该页面中可以创建 Acme 账户或删除已有的 Acme 账户。
+ 目前支持的账户类型有 Let's Encrypt 、 ZeroSSL 、 Buypass、Google Cloud。
+
+
diff --git a/docs/user_manual/websites/certificate_create.md b/docs/user_manual/websites/certificate_create.md
new file mode 100644
index 00000000..21b18928
--- /dev/null
+++ b/docs/user_manual/websites/certificate_create.md
@@ -0,0 +1,35 @@
+
+### 1.1 前置条件
+
+!!! note ""
+
+ - 已经创建 Acme 账户
+ - 如果是 DNS 验证模式,需要提前准备DNS账号
+
+
+
+### 1.2 DNS 账号模式申请证书
+
+!!! note ""
+
+ 1. 选择 ACME 账号
+ 2. 选择 DNS 账号
+ 3. 选择是否自动续签
+ 4. 点击确认
+
+### 1.3 手动解析模式申请证书
+
+!!! note ""
+
+ 1. 选择 ACME 账号
+ 3. 点击确认
+ 4. 等待返回解析内容,然后在 DNS 供应商解析处添加解析内容
+ 5. 点击确认
+
+### 1.4 HTTP 模式申请证书
+
+!!! note ""
+
+ 1. 选择 ACME 账号
+ 2. 选择是否自动续签
+ 3. 点击确认
diff --git a/docs/user_manual/websites/certificate_dns.md b/docs/user_manual/websites/certificate_dns.md
new file mode 100644
index 00000000..2e81e735
--- /dev/null
+++ b/docs/user_manual/websites/certificate_dns.md
@@ -0,0 +1,25 @@
+## 1 DNS 账户管理
+
+!!! note ""
+
+ 点击证书列表上方的【DNS 账户】按钮,弹出 DNS 账户管理页面。在该页面中可以创建、编辑或删除 DNS 账户。DNS 账户用于调用对应 DNS 服务商 API,自动添加 DNS 解析记录验证域名所有权。
+
+ 目前支持的账户类型有:
+
+ - 阿里云
+ - 腾讯云
+ - 华为云
+ - 火山引擎
+ - DNSPod(即将废弃)
+ - Cloudflare
+ - CloudDNS
+ - NameSilo
+ - NameCheap
+ - Name.com
+ - GoDaddy
+
+
+
+!!! note "说明"
+
+ 关于不同类型 DNS 账户需要的认证信息如何获取,请查阅对应服务商的 API 文档获取支持。
diff --git a/docs/user_manual/websites/certificate_renew.md b/docs/user_manual/websites/certificate_renew.md
new file mode 100644
index 00000000..bfec8cbe
--- /dev/null
+++ b/docs/user_manual/websites/certificate_renew.md
@@ -0,0 +1,6 @@
+
+!!! note ""
+
+ 点击续签
+
+
diff --git a/docs/user_manual/websites/dotnet.md b/docs/user_manual/websites/dotnet.md
new file mode 100644
index 00000000..4cfb6ce5
--- /dev/null
+++ b/docs/user_manual/websites/dotnet.md
@@ -0,0 +1,19 @@
+## 创建 .NET 运行环境
+
+**点击创建运行环境按钮,选择 Golang 版本和运行目录等信息**
+
+!!! note ""
+
+ - 目前支持 .NET 9.0、8.0、6.0 版本,用户可以根据自己的需求选择合适的版本。
+ - 目前使用的是 mcr.microsoft.com/dotnet/aspnet 镜像,需要先把代码编译成 .dll 文件,然后放到运行目录中。
+
+
+
+## 操作 .NET 运行环境
+
+!!! note ""
+
+ - 在列表页面,可以对 .NET 运行环境进行停止、启动、重启、编辑、删除和查看日志等操作
+
+
+
diff --git a/docs/user_manual/websites/golang.md b/docs/user_manual/websites/golang.md
new file mode 100644
index 00000000..284511e4
--- /dev/null
+++ b/docs/user_manual/websites/golang.md
@@ -0,0 +1,18 @@
+## 创建 Golang 运行环境
+
+**点击创建运行环境按钮,选择 Golang 版本和运行目录等信息**
+
+!!! note ""
+
+ - 目前支持 Golang 1.21、1.22 版本,用户可以根据自己的需求选择合适的版本。
+
+
+
+## 操作 Golang 运行环境
+
+!!! note ""
+
+ - 在列表页面,可以对 Golang 运行环境进行停止、启动、重启、编辑、删除和查看日志等操作
+
+
+
diff --git a/docs/user_manual/websites/java.md b/docs/user_manual/websites/java.md
new file mode 100644
index 00000000..4df42cfb
--- /dev/null
+++ b/docs/user_manual/websites/java.md
@@ -0,0 +1,19 @@
+## 创建 Java 运行环境
+
+**点击创建运行环境按钮,选择 Java 版本和运行目录等信息**
+
+!!! note ""
+
+ - 目前支持 Java 1.8、11、17、18、21、22 大版本,用户可以根据自己的需求选择合适的版本。
+
+
+
+## 操作 Java 运行环境
+
+!!! note ""
+
+ - 在列表页面,可以对 Java 运行环境进行停止、启动、重启、编辑、删除和查看日志等操作
+
+
+
+
diff --git a/docs/user_manual/websites/node.md b/docs/user_manual/websites/node.md
new file mode 100644
index 00000000..2940c533
--- /dev/null
+++ b/docs/user_manual/websites/node.md
@@ -0,0 +1,34 @@
+## 创建 Node 运行环境
+
+**点击创建运行环境按钮,选择 Node 版本和源码目录**
+
+!!! note ""
+
+ - 目前支持 12.x、14.x 16.x 和 18.x 四个大版本,用户可以根据自己的需求选择合适的版本。
+
+
+
+
+## 操作 Node 运行环境
+
+!!! note ""
+
+ - 在列表页面,可以对 Node 运行环境进行停止、启动、重启、编辑、删除、模块管理和查看日志等操作
+
+
+
+## 日志查看
+
+!!! note ""
+
+ - 点击查看按钮,可以查看 Node 运行环境的运行日志
+
+
+
+## 模块管理
+
+!!! note ""
+
+ - 点击模块按钮,可以对 Node 运行环境的模块进行管理
+
+
\ No newline at end of file
diff --git a/docs/user_manual/websites/openresty.md b/docs/user_manual/websites/openresty.md
new file mode 100644
index 00000000..edf8f028
--- /dev/null
+++ b/docs/user_manual/websites/openresty.md
@@ -0,0 +1,63 @@
+
+!!! note ""
+
+ 网站列表上方的工具栏可用于查看和配置 OpenResty。
+
+## 1 停止 / 启动 / 重启
+
+!!! note ""
+
+ 可以通过按钮停止、启动或重启来管理 OpenResty 应用。
+
+
+
+## 2 重载
+
+!!! note ""
+
+ 允许用户在无需停机的情况下快速应用配置更改,确保网站服务的高可用性。
+
+
+
+## 3 设置
+
+### 3.1 当前状态
+
+!!! note ""
+
+ 查看当前网站状态,包括活动连接数、总连接数、总握手次数、总请求数、请求数、响应数及驻留进程等信息。
+
+
+
+### 3.2 配置修改
+
+!!! note ""
+
+ - 配置 OpenResty 的配置文件
+ - 点击【默认配置】按钮可将配置文件恢复到默认状态
+
+
+
+### 3.3 性能调整
+
+!!! note ""
+
+ 调整 OpenResty 的相关配置参数。
+
+
+
+### 3.4 日志
+
+!!! note ""
+
+ 查看 OpenResty 日志,支持实时追踪、下载、清空等操作,并可按指定时间段和行数筛选日志。
+
+
+
+## 4 清除反代缓存
+
+!!! note ""
+
+ 清除反向代理缓存的功能,以确保用户获取最新的内容和资源。
+
+
\ No newline at end of file
diff --git a/docs/user_manual/websites/php.md b/docs/user_manual/websites/php.md
new file mode 100644
index 00000000..b19bd42d
--- /dev/null
+++ b/docs/user_manual/websites/php.md
@@ -0,0 +1,160 @@
+
+## 创建 PHP 运行环境
+
+!!! note ""
+ **点击创建运行环境按钮,选择 PHP 版本和扩展**
+
+ - 1Panel 支持维护 5.x、7.x 和 8.x 三个大版本,用户可以根据自己的需求选择合适的版本。
+
+
+
+
+
+
+## PHP 扩展列表
+
+
+
+
+
+
+
+
+
+| Extension | PHP 5.5 | PHP 5.6 | PHP 7.0 | PHP 7.1 | PHP 7.2 | PHP 7.3 | PHP 7.4 | PHP 8.0 | PHP 8.1 | PHP 8.2 |
+|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
+| amqp | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| apcu | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| apcu_bc | | | ✓ | ✓ | ✓ | ✓ | ✓ | | | |
+| ast | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| bcmath | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| blackfire | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
+| bz2 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| calendar | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| cassandra | | | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| cmark | | | ✓ | ✓ | ✓ | ✓ | ✓ | | | |
+| csv | | | | | | ✓ | ✓ | ✓ | ✓ | ✓ |
+| dba | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| ddtrace | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| decimal | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| ds | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| enchant | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| ev | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| event | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| excimer | | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| exif | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| ffi | | | | | | | ✓ | ✓ | ✓ | ✓ |
+| gd | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| gearman | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | |
+| geoip | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | | |
+| geos | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | | |
+| geospatial | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| gettext | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| gmagick | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| gmp | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| gnupg | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| grpc | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| http | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| igbinary | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| imagick | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| imap | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| inotify | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| interbase | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | | | |
+| intl | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| ion | | | | | | | | | ✓ | ✓ |
+| ioncube_loader | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | ✓ | |
+| jsmin | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | | |
+| json_post | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| ldap | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| luasandbox | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| lz4 | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| lzf | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| mailparse | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| maxminddb | | | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| mcrypt | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| memcache | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| memcached | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| memprof | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| mongo | ✓ | ✓ | | | | | | | | |
+| mongodb | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| mosquitto | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | | |
+| msgpack | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| mssql | ✓ | ✓ | | | | | | | | |
+| mysql | ✓ | ✓ | | | | | | | | |
+| mysqli | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| oauth | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| oci8 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| odbc | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| opcache | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| opencensus | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| openswoole | | | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| opentelemetry | | | | | | | | ✓ | ✓ | ✓ |
+| parallel | | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| parle | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| pcntl | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| pcov | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| pdo_dblib | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| pdo_firebird | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| pdo_mysql | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| pdo_oci | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| pdo_odbc | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| pdo_pgsql | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| pdo_sqlsrv | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| pgsql | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| php_trie | | | | | | ✓ | ✓ | ✓ | ✓ | ✓ |
+| propro | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | | |
+| protobuf | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| pspell | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| pthreads | ✓ | ✓ | ✓ | | | | | | | |
+| raphf | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| rdkafka | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| recode | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | | | |
+| redis | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| relay | | | | | | | ✓ | ✓ | ✓ | ✓ |
+| seaslog | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| shmop | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| simdjson | | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| smbclient | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| snappy | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| snmp | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| snuffleupagus | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| soap | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| sockets | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| sodium | | ✓ | ✓ | ✓ | | | | | | |
+| solr | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| sourceguardian | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| spx | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| sqlsrv | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| ssh2 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| stomp | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | | ✓ |
+| swoole | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| sybase_ct | ✓ | ✓ | | | | | | | | |
+| sysvmsg | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| sysvsem | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| sysvshm | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| tensor | | | | | ✓ | ✓ | ✓ | ✓ | | |
+| tidy | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| timezonedb | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| uopz | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| uploadprogress | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| uuid | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| vips | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| wddx | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | | | |
+| xdebug | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| xdiff | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| xhprof | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| xlswriter | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| xmldiff | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| xmlrpc | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| xsl | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| yac | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| yaml | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| yar | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
+| zephir_parser | | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| zip | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| zmq | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| zookeeper | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| zstd | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+
+*Number of supported extensions: 132*
+
\ No newline at end of file
diff --git a/docs/user_manual/websites/python.md b/docs/user_manual/websites/python.md
new file mode 100644
index 00000000..b211e974
--- /dev/null
+++ b/docs/user_manual/websites/python.md
@@ -0,0 +1,17 @@
+## 创建 Python 运行环境
+
+**点击创建运行环境按钮,选择 Python 版本和运行目录等信息**
+
+!!! note ""
+
+ - 目前支持 Python 3.10、3.11、3.12、3.13 版本,用户可以根据自己的需求选择合适的版本。
+
+
+
+## 操作 Python 运行环境
+
+!!! note ""
+
+ - 在列表页面,可以对 Python 运行环境进行停止、启动、重启、编辑、删除和查看日志等操作
+
+
diff --git a/docs/user_manual/websites/website_backup.md b/docs/user_manual/websites/website_backup.md
new file mode 100644
index 00000000..b811c916
--- /dev/null
+++ b/docs/user_manual/websites/website_backup.md
@@ -0,0 +1,36 @@
+
+!!! note ""
+
+ **支持备份和恢复网站数据,以及导入现有备份,以确保网站内容的安全和易于管理。**
+
+## 1 创建备份
+
+!!! note ""
+
+ 点击【备份】按钮后,系统将在默认备份目录下生成网站的备份文件。
+
+
+
+## 2 网站恢复
+
+!!! note ""
+
+ 在备份列表中选择目标备份记录,然后点击【恢复】按钮以进行恢复操作。
+
+
+
+## 3 备份下载
+
+!!! note ""
+
+ 支持将网站备份记录下载到本地,下载后可在上传备份页面使用该文件。
+
+
+
+## 4 导入备份
+
+!!! note ""
+
+ 选择网站备份文件并进行上传。
+
+
diff --git a/docs/user_manual/websites/website_config_basic.md b/docs/user_manual/websites/website_config_basic.md
new file mode 100644
index 00000000..52a2ade6
--- /dev/null
+++ b/docs/user_manual/websites/website_config_basic.md
@@ -0,0 +1,101 @@
+!!! note ""
+
+ 网站设置页面包含多种功能,包括域名设置、网站目录、默认文档、流量限制、反向代理、密码保护、HTTPS 配置、伪静态、防盗链、重定向及其他设置。
+
+## 1 域名设置
+
+!!! note ""
+
+ 域名设置页面允许用户管理网站的域名和端口配置。
+
+
+
+## 2 网站目录
+
+!!! note ""
+
+ 网站目录页面支持查看网站的根目录,设置运行目录,以及配置运行用户和用户组等选项。
+
+
+
+## 3 默认文档
+
+!!! note ""
+
+ 配置默认文档,以便在用户访问网站根目录时自动加载指定的文件。
+
+
+
+## 4 流量限制
+
+!!! note ""
+
+ 允许用户配置流量限制,通过选择不同的限制方案,控制网站的带宽和访问流量。
+
+
+
+## 5 反向代理
+
+!!! note ""
+
+ 反向代理功能允许将网站请求转发到后端服务器,以实现负载均衡、安全控制和内容分发。
+
+
+
+## 6 密码访问
+
+!!! note ""
+
+ 密码访问功能允许用户为网站设置访问密码,以增强网站的安全性,限制未经授权的访问。
+
+
+
+## 7 HTTPS
+
+!!! note ""
+
+ 配置网站的 HTTPS 功能时,用户需要填写或选择以下信息:
+
+ - **HTTP 选项**:选择访问方式,包括:1. 自动将 HTTP 跳转到 HTTPS ;2. 允许直接访问 HTTP ;3. 禁止 HTTP 访问。
+ - **HSTS**:开启 HSTS,以提升网站安全性。
+ - **SSL 选项**:选择现有证书或导入新证书,现有证书需通过 1Panel 证书模块申请。
+ - **Acme 账户**:选择已存在的 Acme 账户。
+ - **证书**:选择已存在的证书。
+ - **支持的协议版本**:选择 SSL 协议版本。
+ - **加密算法**:指定 SSL 加密算法。
+
+ 通过以上配置,用户可以有效提升网站的安全性和访问性能。
+
+
+
+## 8 伪静态
+
+!!! note ""
+
+ 伪静态功能通过将动态 URL 转换为更友好的静态 URL,提高网站的可读性和搜索引擎优化效果。
+
+
+
+## 9 防盗链
+
+!!! note ""
+
+ 防盗链功能通过验证请求来源,阻止非授权用户直接链接和下载网站资源,以保护网站内容安全。
+
+
+
+## 10 重定向
+
+!!! note ""
+
+ 重定向功能允许将访问特定URL的请求自动转发到另一个URL,以实现链接管理和流量引导。
+
+
+
+## 11 其他
+
+!!! note ""
+
+ 支持更改主域名、切换分组以及更新备注信息等操作。
+
+
diff --git a/docs/user_manual/websites/website_config_other.md b/docs/user_manual/websites/website_config_other.md
new file mode 100644
index 00000000..b8798449
--- /dev/null
+++ b/docs/user_manual/websites/website_config_other.md
@@ -0,0 +1,65 @@
+
+## 1 日志
+
+!!! note ""
+
+ 1Panel 的网站日志查看功能支持以下操作:
+
+ - 查看正常日志和错误日志
+ - 开启/关闭日志记录
+ - 实时追踪日志内容
+ - 下载日志文件
+ - 清空日志内容
+
+
+
+## 2 配置文件
+
+!!! note ""
+
+ - 查看并修改目标网站的 OpenResty 配置文件设置。
+ - PHP 运行环境网站还支持修改 FPM 和 PHP 配置文件。
+
+
+
+## 3 PHP
+
+!!! note ""
+
+ PHP 运行环境网站支持配置修改,包括禁用函数、调整上传限制以及切换 PHP 版本等功能。
+
+
+
+## 4 默认站点
+
+!!! note ""
+
+ 设置默认站点功能允许用户在未匹配到任何域名时,将请求自动定向到指定的默认网站。
+
+
+
+## 5 开启 / 停止网站
+
+!!! note ""
+
+ 点击列表中的【已启动】或【已停止】按钮,可以切换网站的运行状态。
+
+
+
+## 6 设置过期时间
+
+!!! note ""
+
+ 设置网站过期时间后,系统将在到期时自动停止该站点,以确保资源的有效管理和使用。
+
+
+
+## 7 删除网站
+
+!!! note ""
+
+ - **强制删除**:跳过删除过程中的错误,直接执行删除操作。
+ - **删除应用**:可在删除网站时一并删除与之相关的 1Panel 应用。
+ - **删除备份**:在删除网站的同时,也会删除其备份。
+
+
diff --git a/docs/user_manual/websites/website_config_waf.md b/docs/user_manual/websites/website_config_waf.md
new file mode 100644
index 00000000..df30ad13
--- /dev/null
+++ b/docs/user_manual/websites/website_config_waf.md
@@ -0,0 +1,81 @@
+
+!!! note ""
+
+ 配置网站的 WAF。
+
+## 1 CC 防护
+
+!!! note ""
+
+ 配置 CC 防护,填写以下信息:
+
+ - 周期:CC 防护的检测周期;
+ - 频率:CC 防护的频率设置。
+
+ 例如周期 60 频率 100 代表 60 秒内累计请求同一URL超过 100 次,触发 CC 防御,封锁此 IP。
+
+
+
+## 2 IP 白名单
+
+!!! note ""
+
+ 设置访问网站的 IP 白名单。
+
+
+
+## 3 IP 黑名单
+
+!!! note ""
+
+ 设置禁止访问网站的 IP 黑名单。
+
+
+
+## 4 URL 白名单
+
+!!! note ""
+
+ 设置访问网站的 URL 白名单。
+
+
+
+## 5 URL 黑名单
+
+!!! note ""
+
+ 设置禁止访问网站的 URL 黑名单。
+
+
+
+## 6 Cookie 黑名单
+
+!!! note ""
+
+ 设置禁止 Cookie 中携带的数据黑名单。
+
+
+
+## 7 Get 参数校验
+
+!!! note ""
+
+ 设置禁止 Get 请求中携带的参数。
+
+
+
+## 8 POST 参数校验
+
+!!! note ""
+
+ 设置禁止 POST 请求中携带的参数。
+
+
+
+## 9 文件扩展名黑名单
+
+!!! note ""
+
+ 这是禁止上传的文件类型。
+
+
diff --git a/docs/user_manual/websites/website_create.md b/docs/user_manual/websites/website_create.md
new file mode 100644
index 00000000..58d1fc8e
--- /dev/null
+++ b/docs/user_manual/websites/website_create.md
@@ -0,0 +1,70 @@
+!!! note ""
+
+ **支持一键部署多种网站创建方式,包括运行环境(PHP、Java、Node.js、Go、Python)、反向代理和静态网站等,满足不同类型网站的快速搭建需求。**
+
+## 1 一键部署
+
+!!! note ""
+
+ **您可以通过应用商店中提供的应用,如 WordPress 和 Halo,轻松部署网站。**
+
+ - **分组**:选择网站所属的分组;
+ - **应用类型**:选择已安装的应用或新安装的应用;
+ - **应用参数**:如果选择新安装应用,请填写相关参数;
+ - **主域名**:输入需要绑定的主要域名及其端口;
+ - **其他域名**:输入需要绑定的其他域名及其端口;
+ - **监听 IPv6**:使服务器能够通过 IPv6 地址接收客户端请求;
+ - **代号**:设定网站目录的文件夹名称;
+ - **备注**:填写对该站点作用的描述;
+
+
+
+## 2 运行环境
+
+!!! note ""
+
+ **您可以利用已添加的运行环境来创建网站。**
+
+ - **分组**:选择网站所属的分组;
+ - **运行环境**:从运行环境菜单中选择已创建的运行环境(目前支持 PHP、Java、Node.js、Go、Python);
+ - **端口**:指定网站服务的端口;
+ - **主域名**:填写需要绑定的主要域名及其端口;
+ - **其他域名**:填写需要绑定的其他域名及其端口;
+ - **监听 IPv6**:使服务器能够通过 IPv6 地址接收客户端请求;
+ - **代号**:为网站目录指定一个代号,作为文件夹名称;
+ - **创建 FTP**:创建站点的同时,为站点创建一个对应 FTP 帐户,并且 FTP 目录指向站点所在目录;
+ - **备注**:提供该站点的功能描述。
+
+
+
+## 3 反向代理
+
+!!! note ""
+
+ **支持创建反向代理网站,允许用户将请求转发到其他服务。**
+
+ - **分组**:选择网站所属的分组;
+ - **主域名**:填写要绑定的主要域名及其端口;
+ - **其他域名**:填写需要绑定的其他域名及其端口;
+ - **监听 IPv6**:使服务器能够通过 IPv6 地址接收客户端请求;
+ - **代号**:设定网站目录的文件夹名称;
+ - **代理地址**:输入已有服务的地址;
+ - **备注**:描述该站点的功能或用途。
+
+
+
+## 4 静态网站
+
+!!! note ""
+
+ **支持快速创建静态网站,提供便捷的部署和管理功能,让用户轻松发布和维护静态内容。**
+
+ - **分组**:选择网站所属的分组;
+ - **主域名**:填写需要绑定的主要域名及其端口;
+ - **其他域名**:填写需要绑定的其他域名及其端口;
+ - **监听 IPv6**:使服务器能够通过 IPv6 地址接收客户端请求;
+ - **代号**:设置代号,作为网站目录的文件夹名称;
+ - **创建 FTP**:创建站点的同时,为站点创建一个对应 FTP 帐户,并且 FTP 目录指向站点所在目录;
+ - **备注**:简要描述该站点的功能或用途。
+
+
diff --git a/docs/user_manual/websites/website_group.md b/docs/user_manual/websites/website_group.md
new file mode 100644
index 00000000..80d917d8
--- /dev/null
+++ b/docs/user_manual/websites/website_group.md
@@ -0,0 +1,19 @@
+!!! note ""
+
+ **用户为网站设置分组,以便于更好地组织和管理多个网站。**
+
+## 1 创建分组
+
+
+
+## 2 默认分组
+
+!!! note ""
+
+ 设置网站默认分组后,创建新网站时会自动将其归入该分组。
+
+
+
+## 3 修改分组
+
+
diff --git a/docs/user_manual/websites/websites.md b/docs/user_manual/websites/websites.md
new file mode 100644
index 00000000..516ff6f5
--- /dev/null
+++ b/docs/user_manual/websites/websites.md
@@ -0,0 +1,9 @@
+
+!!! note ""
+
+ - 1Panel 的网站管理功能旨在为用户提供便捷、高效的网站创建与管理体验。
+ - 通过 1Panel,用户可以轻松搭建多种类型的网站,包括静态网站、反向代理站点,以及支持 PHP、Java、Node.js、Go、Python 等运行环境的网站。
+ - 面板提供了全面的管理选项,支持域名绑定、SSL 证书配置、HTTPS 启用、伪静态设置、重定向、防盗链等功能。
+ - 此外,用户还可以通过 1Panel 实现网站数据的自动备份与恢复,确保数据安全。通过这些功能,1Panel 帮助用户轻松管理服务器上的各类网站。
+
+{ width="900px" }
diff --git a/docs/user_manual/xpack/waf/block.md b/docs/user_manual/xpack/waf/block.md
new file mode 100644
index 00000000..aaba5271
--- /dev/null
+++ b/docs/user_manual/xpack/waf/block.md
@@ -0,0 +1,8 @@
+
+!!! note ""
+
+ 封锁记录 可以查看 WAF 临时拉黑的 IP
+ 可以拉黑或者解封 IP
+
+
+{ width="900px" }
diff --git a/docs/user_manual/xpack/waf/dashboard.md b/docs/user_manual/xpack/waf/dashboard.md
new file mode 100644
index 00000000..553e3622
--- /dev/null
+++ b/docs/user_manual/xpack/waf/dashboard.md
@@ -0,0 +1,6 @@
+
+!!! note ""
+
+ 概览页 可以查看今日状态、拦截地图、请求趋势、拦截趋势等
+
+{ width="900px" }
diff --git a/docs/user_manual/xpack/waf/global.md b/docs/user_manual/xpack/waf/global.md
new file mode 100644
index 00000000..c51f7f84
--- /dev/null
+++ b/docs/user_manual/xpack/waf/global.md
@@ -0,0 +1,199 @@
+
+!!! note ""
+
+ 全局设置 可以查看并配置 WAF。
+ 包括黑白名单 频率设置 默认规则 自定义规则 配置等功能
+ 注意:
+ 1.全局设置的开关可以控制所有网站的规则,比如关闭访问频率之后所有网站的访问频率限制都会失效
+ 2.全局设置中的小项,比如默认规则-参数规则的第一项,关闭了之后,只影响新建网站,不影响现存网站
+
+
+{ width="900px" }
+
+## 1 黑白名单
+
+!!! note ""
+
+ 包括 IP 黑白名单、 URL 黑白名单、User-Agent 黑白名单、IP 组
+ 黑名单:阻止携带黑名单特征的请求
+ 白名单:对携带白名单特征的请求,不做 WAF 校验
+
+### 1.1 IP 黑白名单
+
+!!! note ""
+
+ 可以根据 IP 地址阻止/放行请求
+
+### 1.2 URL 黑白名单
+
+!!! note ""
+
+ 黑名单:可以阻止用户访问某些 URL
+ 白名单:用户访问白名单中的 URL 不会触发 WAF 校验,适合某些请求中包含 SQL 注入和 XSS 特征的请求,比如 WordPress Halo 文章保存接口
+
+### 1.3 User-Agent 黑白名单
+
+!!! note ""
+
+ 可以根据 User-Agent 阻止/放行请求
+
+### 1.4 IP 组
+
+!!! note ""
+
+ 可以把多个 IP 包含在一个组中,用于 IP 黑白名单
+
+
+## 2 频率限制
+
+!!! note ""
+
+ 可以用来抵御 CC 攻击,包含访问频率限制、攻击频率限制、404 频率限制
+
+### 2.1 访问频率限制
+
+!!! note ""
+
+ 如果单位时间内请求超过阈值,就拉黑 IP 一段时间
+ 全局模式:单位时间请求任意 URL 次数之和超过阈值即触发
+ URL 模式:单位时间请求单个 URL 次数超过阈值即触发
+
+
+{ width="900px" }
+
+
+### 2.2 攻击频率限制
+
+!!! note ""
+
+ 如果某个 IP 一直触发 WAF 规则,则拉黑此 IP
+ 场景:某个 IP 一直攻击你的网站,触发了多次规则
+
+{ width="900px" }
+
+
+### 2.3 404频率限制
+
+!!! note ""
+
+ 如果某个 IP 的访问一直返回 404 ,则拉黑此 IP
+ 场景:扫描器或者恶意爬虫一直爬你的网站
+
+{ width="900px" }
+
+
+## 3 默认规则
+
+!!! note ""
+
+ WAF 的默认规则,按照一定的规则来阻止恶意请求
+
+
+### 3.1 参数规则
+
+!!! note ""
+
+ 过滤常见的恶意参数
+
+### 3.2 URL 规则
+
+!!! note ""
+
+ 过滤常见的恶意 URL
+
+### 3.3 HTTP 规则
+
+!!! note ""
+
+ 设置允许访问的方法类型,如果想限制某些类型访问,请关闭这个类型的按钮,例如:仅允许 GET 类型访问,那么需要关闭除了 GET 之外的其他类型按钮
+
+### 3.4 Cookie 规则
+
+!!! note ""
+
+ 过滤携带恶意 Cookie 的请求
+
+
+### 3.5 Header 规则
+
+!!! note ""
+
+ 过滤携带恶意 Header 的请求
+
+### 3.6 User-Agent 规则
+
+!!! note ""
+
+ 过滤携带恶意 User-Agent 的请求
+
+### 3.7 其他
+
+!!! note ""
+
+ SQL 注入防御 和 XSS 防御
+
+## 4 自定义规则
+
+!!! note ""
+
+ 根据自己的需求制定 WAF 规则
+ 包含自定义规则、文件上传限制、地区访问限制、CDN 配置
+
+## 4.1 自定义规则(✨专业版)
+
+!!! note ""
+
+ 根据自己的需求制定 WAF 规则
+ 可以匹配 URL IP Header Host 的参数,并选择相应的动作
+ 比如可以选择 URL 为 /login 的比如经过人机验证
+
+{ width="900px" }
+
+## 4.2 文件上传限制
+
+!!! note ""
+
+ 可以根据文件后缀限制上传文件的类型
+
+{ width="900px" }
+
+## 4.3 地区访问限制(✨专业版)
+
+!!! note ""
+
+ 可以限制或者仅允许某些地区的访问
+
+{ width="900px" }
+
+## 4.4 CDN
+
+!!! note ""
+
+ 如果网站开启了 CDN 并且影响日志获取用户的 IP,可以开启此项
+ 从 HTTP Header 中获取:从指定的请求 Header 中获取,需要确认 CDN 把真实 IP 放在哪个 Header,比如 CloudFlare 默认是放在 cf-connecting-ip 中
+ 从 Header 列表中获取: 从常用的 CDN 携带真实 IP 的 HTTP Header 中获取,取第一个能获取到的值
+ 获取 X-Forwarded-For 的上一级代理地址:例如:X-Forwarded-For: client,proxy1,proxy2,proxy3 上一级代理会取最后一个 IP proxy3
+
+{ width="900px" }
+
+
+## 5 配置
+
+!!! note ""
+
+ 包含拦截页面和恶意 IP 组
+
+### 5.1 拦截页面(✨专业版)
+
+!!! note ""
+
+ 可以自定义拦截页面
+
+{ width="900px" }
+
+
+### 5.2 恶意 IP 组
+
+!!! note ""
+
+ 拦截由 1Panel 提供的恶意 IP 组
diff --git a/docs/user_manual/xpack/waf/log.md b/docs/user_manual/xpack/waf/log.md
new file mode 100644
index 00000000..04a86058
--- /dev/null
+++ b/docs/user_manual/xpack/waf/log.md
@@ -0,0 +1,8 @@
+
+!!! note ""
+
+ 拦截记录 可以查看 WAF 拦截的请求
+ 可以拉黑 IP、给 URL 加白名单、查看详细信息等
+
+{ width="900px" }
+
diff --git a/docs/user_manual/xpack/waf/site.md b/docs/user_manual/xpack/waf/site.md
new file mode 100644
index 00000000..1d24787b
--- /dev/null
+++ b/docs/user_manual/xpack/waf/site.md
@@ -0,0 +1,122 @@
+
+!!! note ""
+
+ 网站设置,可以查看并配置某个网站的 WAF 规则。
+ 包括频率设置 默认规则 自定义规则 等
+
+
+{ width="900px" }
+
+## 1 频率限制
+
+!!! note ""
+
+ 可以用来抵御 CC 攻击,包含访问频率限制、攻击频率限制、404 频率限制
+
+### 1.1 访问频率限制
+
+!!! note ""
+
+ 如果单位时间内请求超过阈值,就拉黑 IP 一段时间
+ 全局模式:单位时间请求任意 URL 次数之和超过阈值即触发
+ URL 模式:单位时间请求单个 URL 次数超过阈值即触发
+
+
+{ width="900px" }
+
+
+
+## 2 默认规则
+
+!!! note ""
+
+ WAF 的默认规则,按照一定的规则来阻止恶意请求
+
+
+### 2.1 参数规则
+
+!!! note ""
+
+ 过滤常见的恶意参数
+
+### 2.2 URL 规则
+
+!!! note ""
+
+ 过滤常见的恶意 URL
+
+### 2.3 HTTP 规则
+
+!!! note ""
+
+ 设置允许访问的方法类型,如果想限制某些类型访问,请关闭这个类型的按钮,例如:仅允许 GET 类型访问,那么需要关闭除了 GET 之外的其他类型按钮
+
+### 2.4 Cookie 规则
+
+!!! note ""
+
+ 过滤携带恶意 Cookie 的请求
+
+
+### 2.5 Header 规则
+
+!!! note ""
+
+ 过滤携带恶意 Header 的请求
+
+### 2.6 User-Agent 规则
+
+!!! note ""
+
+ 过滤携带恶意 User-Agent 的请求
+
+### 2.7 其他
+
+!!! note ""
+
+ SQL 注入防御 和 XSS 防御
+
+## 3 自定义规则
+
+!!! note ""
+
+ 根据自己的需求制定 WAF 规则
+ 包含自定义规则、文件上传限制、地区访问限制、CDN 配置
+
+## 3.1 自定义规则(✨专业版)
+
+!!! note ""
+
+ 根据自己的需求制定 WAF 规则
+ 可以匹配 URL IP Header Host 的参数,并选择相应的动作
+ 比如可以选择 URL 为 /login 的比如经过人机验证
+
+{ width="900px" }
+
+## 3.2 文件上传限制
+
+!!! note ""
+
+ 可以根据文件后缀限制上传文件的类型
+
+{ width="900px" }
+
+## 3.3 地区访问限制(✨专业版)
+
+!!! note ""
+
+ 可以限制或者仅允许某些地区的访问
+
+{ width="900px" }
+
+## 3.4 CDN
+
+!!! note ""
+
+ 如果网站开启了 CDN 并且影响日志获取用户的 IP,可以开启此项
+ 从 HTTP Header 中获取:从指定的请求 Header 中获取,需要确认 CDN 把真实 IP 放在哪个 Header,比如 CloudFlare 默认是放在 cf-connecting-ip 中
+ 从 Header 列表中获取: 从常用的 CDN 携带真实 IP 的 HTTP Header 中获取,取第一个能获取到的值
+ 获取 X-Forwarded-For 的上一级代理地址:例如:X-Forwarded-For: client,proxy1,proxy2,proxy3 上一级代理会取最后一个 IP proxy3
+
+{ width="900px" }
+
diff --git a/docs/user_manual/xpack/waf/waf.md b/docs/user_manual/xpack/waf/waf.md
new file mode 100644
index 00000000..a296259e
--- /dev/null
+++ b/docs/user_manual/xpack/waf/waf.md
@@ -0,0 +1,7 @@
+
+!!! note ""
+
+ WAF 是 Web Application Firewall 的缩写,也被称为 Web 应用防火墙
+ 可以保护你的网站免受恶意攻击,如 SQL 注入、XSS 攻击等。
+
+{ width="900px" }
diff --git a/index.html b/index.html
deleted file mode 100644
index 5fb079b7..00000000
--- a/index.html
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
- Redirecting
-
-
-
-
- Redirecting to v2/...
-
-
diff --git a/mkdocs.yml b/mkdocs.yml
new file mode 100644
index 00000000..c9e40b3d
--- /dev/null
+++ b/mkdocs.yml
@@ -0,0 +1,217 @@
+site_name: '1Panel 文档'
+site_url: 'https://1panel.cn/'
+site_author: '1Panel'
+site_description: "1Panel 开源 Linux 服务器运维管理面板"
+
+repo_name: '1Panel-dev/1Panel'
+repo_url: 'https://github.com/1Panel-dev/1Panel'
+edit_uri: ''
+
+theme:
+ name: 'material'
+ logo: 'img/logo-white.png'
+ favicon: 'img/facio.ico'
+ language: 'zh'
+ palette:
+ - scheme: default
+ accent: red
+ toggle:
+ icon: material/weather-sunny
+ name: Switch to dark mode
+ - scheme: slate
+ accent: red
+ toggle:
+ icon: material/weather-night
+ name: Switch to light mode
+ features:
+ - navigation.tracking
+ - navigation.indexes
+ - navigation.top
+ - search.suggest
+ - search.highlight
+ - search.share
+ - header.autohide
+ font: false
+ custom_dir: 'theme'
+ icon:
+ repo: fontawesome/brands/github
+
+nav:
+ - 产品介绍: index.md
+ - 安装部署:
+ - 在线安装: installation/online_installation.md
+ - 离线包安装: installation/package_installation.md
+ - 云平台:
+ - 阿里云镜像部署: installation/ali_cloud.md
+ - 阿里云计算巢部署: installation/alibaba-cloud-computenest.md
+ - 腾讯云应用模板部署: installation/tencent_cloud.md
+ - 腾讯云云应用部署: installation/tencent_cloudapp.md
+ - 在线升级: installation/online_upgrade.md
+ - 命令行工具: installation/cli.md
+ - 功能手册:
+ - 应用商店:
+ - 概述: user_manual/appstore/appstore.md
+ - 安装部署: user_manual/appstore/install.md
+ - 应用操作: user_manual/appstore/installed.md
+ - 网站:
+ - 概述: user_manual/websites/websites.md
+ - 创建网站: user_manual/websites/website_create.md
+ - 基本设置: user_manual/websites/website_config_basic.md
+ - 其他设置: user_manual/websites/website_config_other.md
+ - 网站分组: user_manual/websites/website_group.md
+ - 网站备份: user_manual/websites/website_backup.md
+ - OpenResty 设置: user_manual/websites/openresty.md
+ - 证书:
+ - 证书概述: user_manual/websites/certificate.md
+ - 申请证书: user_manual/websites/certificate_create.md
+ - 续签证书: user_manual/websites/certificate_renew.md
+ - Acme 账户: user_manual/websites/certificate_acme.md
+ - DNS 账户: user_manual/websites/certificate_dns.md
+ - 运行环境:
+ - PHP: user_manual/websites/php.md
+ - Node.js: user_manual/websites/node.md
+ - Java: user_manual/websites/java.md
+ - Golang: user_manual/websites/golang.md
+ - Python: user_manual/websites/python.md
+ - .NET: user_manual/websites/dotnet.md
+ - AI:
+ - 模型: user_manual/ai/model.md
+ - MCP: user_manual/ai/mcp.md
+ - GPU 监控: user_manual/ai/gpu.md
+ - MCP Server: user_manual/mcp/mcp_server.md
+ - 数据库:
+ - MySQL: user_manual/databases/mysql.md
+ - PostgreSQL: user_manual/databases/postgresql.md
+ - Redis: user_manual/databases/redis.md
+ - 容器:
+ - 容器: user_manual/containers/container.md
+ - 编排: user_manual/containers/compose.md
+ - 镜像: user_manual/containers/image.md
+ - 网络: user_manual/containers/network.md
+ - 存储卷: user_manual/containers/volume.md
+ - 仓库: user_manual/containers/repo.md
+ - 编排模版: user_manual/containers/compose_template.md
+ - 配置: user_manual/containers/setting.md
+ - 计划任务: user_manual/cronjobs.md
+ - 主机:
+ - 文件: user_manual/hosts/file.md
+ - 监控: user_manual/hosts/monitor.md
+ - 终端: user_manual/hosts/terminal.md
+ - 防火墙: user_manual/hosts/firewall.md
+ - 进程管理: user_manual/hosts/process.md
+ - SSH 管理: user_manual/hosts/ssh.md
+ - 工具箱:
+ - 快速设置: user_manual/toolbox/quick_settings.md
+ - 缓存清理: user_manual/toolbox/clean.md
+ - 进程守护: user_manual/toolbox/supervisor.md
+ - 病毒扫描: user_manual/toolbox/clam.md
+ - FTP: user_manual/toolbox/ftp.md
+ - Fail2ban: user_manual/toolbox/fail2ban.md
+ - 日志审计: user_manual/logs.md
+ - 高级功能:
+ - WAF:
+ - 概述: user_manual/xpack/waf/waf.md
+ - 概览: user_manual/xpack/waf/dashboard.md
+ - 全局设置: user_manual/xpack/waf/global.md
+ - 网站设置: user_manual/xpack/waf/site.md
+ - 拦截记录: user_manual/xpack/waf/log.md
+ - 封锁记录: user_manual/xpack/waf/block.md
+ - 面板设置: user_manual/settings.md
+ - 常见问题:
+ - 产品 FAQ: faq/faq.md
+ - 操作系统相关: faq/operating_system.md
+ - 系统功能相关: faq/system_function.md
+ - 服务器架构相关: faq/server_architecture.md
+ - 开发文档:
+ - 开发环境搭建: dev_manual/dev_manual.md
+ - API 接口配置: dev_manual/api_manual.md
+ - 版本迭代: changelog.md
+ - 联系我们: contact.md
+
+markdown_extensions:
+ - admonition
+ - abbr
+ - attr_list
+ - def_list
+ - footnotes
+ - meta
+ - toc:
+ permalink: ⚓︎
+ - pymdownx.arithmatex:
+ generic: true
+ - pymdownx.betterem:
+ smart_enable: all
+ - pymdownx.caret
+ - pymdownx.critic
+ - pymdownx.details
+ - pymdownx.emoji:
+ emoji_index: !!python/name:material.extensions.emoji.twemoji
+ emoji_generator: !!python/name:material.extensions.emoji.to_svg
+ options:
+ custom_icons:
+ - theme/.icons
+ - pymdownx.inlinehilite
+ - pymdownx.keys
+ - pymdownx.superfences:
+ custom_fences:
+ - name: mermaid
+ class: mermaid
+ format: !!python/name:pymdownx.superfences.fence_code_format
+ - pymdownx.saneheaders
+ - pymdownx.magiclink:
+ repo_url_shortener: true
+ repo_url_shorthand: true
+ - pymdownx.mark
+ - pymdownx.smartsymbols
+ - pymdownx.snippets:
+ check_paths: true
+ - pymdownx.tabbed:
+ alternate_style: true
+ - pymdownx.tasklist:
+ custom_checkbox: true
+ - pymdownx.tilde
+
+extra:
+ 1Panel:
+ tag: v1.10.29
+ search:
+ separator: '[\s\-\.]+'
+ language: 'zh'
+ Content-Encoding: gzip
+ boost: 100
+ generator: false
+ # version:
+ # default: master
+ # provider: mike
+ analytics:
+ provider: google
+ property: G-P2ER2N0NSN
+ social:
+ - icon: Bilibili_Logo_Blue
+ link: https://space.bilibili.com/510493147/lists/1199760
+ - icon: fontawesome/brands/github
+ link: https://github.com/1Panel-dev
+ - icon: fontawesome/solid/envelope
+ link: mailto:wanghe@fit2cloud.com
+ - icon: fontawesome/brands/skype
+ link: tel://400-052-0755
+
+extra_css:
+ - css/extra.css
+ - css/termynal.css
+ - css/custom.css
+ - stylesheets/extra.css
+
+extra_javascript:
+ - js/termynal.js
+ - js/custom.js
+
+copyright: Copyright © 2014-2025 杭州飞致云信息科技有限公司, All Rights Reserved. 浙ICP备14038283号-5
+
+plugins:
+ - search:
+ lang:
+ - en
+ - ja
+ separator: '[\s\-\.]+'
+ - macros
\ No newline at end of file
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
new file mode 100644
index 00000000..e76b4e5a
--- /dev/null
+++ b/requirements/requirements.txt
@@ -0,0 +1,3 @@
+mkdocs-material>=8.4.0
+mkdocs-macros-plugin>=0.7.0
+mike>=1.1.2
diff --git a/theme/.icons/Bilibili_Logo_Blue.svg b/theme/.icons/Bilibili_Logo_Blue.svg
new file mode 100644
index 00000000..7d8c0d68
--- /dev/null
+++ b/theme/.icons/Bilibili_Logo_Blue.svg
@@ -0,0 +1,67 @@
+
+
+
diff --git a/v1/css/f2c-header.css b/theme/css/f2c-header.css
similarity index 100%
rename from v1/css/f2c-header.css
rename to theme/css/f2c-header.css
diff --git a/v1/css/lightgallery.min.css b/theme/css/lightgallery.min.css
similarity index 100%
rename from v1/css/lightgallery.min.css
rename to theme/css/lightgallery.min.css
diff --git a/theme/f2c-header.html b/theme/f2c-header.html
new file mode 100644
index 00000000..a75c5086
--- /dev/null
+++ b/theme/f2c-header.html
@@ -0,0 +1,51 @@
+
diff --git a/v1/fonts/lg.svg b/theme/fonts/lg.svg
similarity index 100%
rename from v1/fonts/lg.svg
rename to theme/fonts/lg.svg
diff --git a/v1/fonts/lg.ttf b/theme/fonts/lg.ttf
similarity index 100%
rename from v1/fonts/lg.ttf
rename to theme/fonts/lg.ttf
diff --git a/v1/fonts/lg.woff b/theme/fonts/lg.woff
similarity index 100%
rename from v1/fonts/lg.woff
rename to theme/fonts/lg.woff
diff --git a/v1/img/loading.gif b/theme/img/loading.gif
similarity index 100%
rename from v1/img/loading.gif
rename to theme/img/loading.gif
diff --git a/v1/img/logo/banner-nav-CloudExplorer.svg b/theme/img/logo/banner-nav-CloudExplorer.svg
similarity index 100%
rename from v1/img/logo/banner-nav-CloudExplorer.svg
rename to theme/img/logo/banner-nav-CloudExplorer.svg
diff --git a/v1/img/logo/banner-nav-DataEase.svg b/theme/img/logo/banner-nav-DataEase.svg
similarity index 100%
rename from v1/img/logo/banner-nav-DataEase.svg
rename to theme/img/logo/banner-nav-DataEase.svg
diff --git a/v1/img/logo/banner-nav-FIT2CLOUD.svg b/theme/img/logo/banner-nav-FIT2CLOUD.svg
similarity index 100%
rename from v1/img/logo/banner-nav-FIT2CLOUD.svg
rename to theme/img/logo/banner-nav-FIT2CLOUD.svg
diff --git a/v1/img/logo/banner-nav-JumpServer.svg b/theme/img/logo/banner-nav-JumpServer.svg
similarity index 100%
rename from v1/img/logo/banner-nav-JumpServer.svg
rename to theme/img/logo/banner-nav-JumpServer.svg
diff --git a/v1/img/logo/banner-nav-KubeOperator.svg b/theme/img/logo/banner-nav-KubeOperator.svg
similarity index 100%
rename from v1/img/logo/banner-nav-KubeOperator.svg
rename to theme/img/logo/banner-nav-KubeOperator.svg
diff --git a/v1/img/logo/banner-nav-MeterSphere.svg b/theme/img/logo/banner-nav-MeterSphere.svg
similarity index 100%
rename from v1/img/logo/banner-nav-MeterSphere.svg
rename to theme/img/logo/banner-nav-MeterSphere.svg
diff --git a/v1/img/logo/logo-dark-MeterSphere.svg b/theme/img/logo/logo-dark-MeterSphere.svg
similarity index 100%
rename from v1/img/logo/logo-dark-MeterSphere.svg
rename to theme/img/logo/logo-dark-MeterSphere.svg
diff --git a/v1/img/logo/logo-light-FIT2CLOUD.svg b/theme/img/logo/logo-light-FIT2CLOUD.svg
similarity index 100%
rename from v1/img/logo/logo-light-FIT2CLOUD.svg
rename to theme/img/logo/logo-light-FIT2CLOUD.svg
diff --git a/v1/img/logo/logo-light-MeterSphere.svg b/theme/img/logo/logo-light-MeterSphere.svg
similarity index 100%
rename from v1/img/logo/logo-light-MeterSphere.svg
rename to theme/img/logo/logo-light-MeterSphere.svg
diff --git a/v1/js/bootstrap.min.js b/theme/js/bootstrap.min.js
similarity index 100%
rename from v1/js/bootstrap.min.js
rename to theme/js/bootstrap.min.js
diff --git a/v1/js/jquery-3.5.1.min.js b/theme/js/jquery-3.5.1.min.js
similarity index 100%
rename from v1/js/jquery-3.5.1.min.js
rename to theme/js/jquery-3.5.1.min.js
diff --git a/v1/js/lightgallery.min.js b/theme/js/lightgallery.min.js
similarity index 100%
rename from v1/js/lightgallery.min.js
rename to theme/js/lightgallery.min.js
diff --git a/v1/js/mega.js b/theme/js/mega.js
similarity index 100%
rename from v1/js/mega.js
rename to theme/js/mega.js
diff --git a/theme/main.html b/theme/main.html
new file mode 100644
index 00000000..2cdac3d3
--- /dev/null
+++ b/theme/main.html
@@ -0,0 +1,59 @@
+{% extends "base.html" %}
+
+{% block header %}
+{% include "f2c-header.html" %}
+{{ super() }}
+{% endblock %}
+
+{% block announce %}
+
+{% endblock %}
+
+{% block styles %}
+
+
+ {{ super() }}
+{% endblock styles %}
+
+{% block footer %}
+
+
+{% endblock footer %}
+
+{% block libs %}
+ {{ super() }}
+
+
+
+{% endblock libs %}
+
+{% block scripts %}
+ {{ super() }}
+
+{% endblock scripts %}
diff --git a/v1/404.html b/v1/404.html
deleted file mode 100644
index 64d33153..00000000
--- a/v1/404.html
+++ /dev/null
@@ -1,3195 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1Panel 文档
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 404 - Not found
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/v1/assets/images/favicon.png b/v1/assets/images/favicon.png
deleted file mode 100644
index 1cf13b9f..00000000
Binary files a/v1/assets/images/favicon.png and /dev/null differ
diff --git a/v1/assets/javascripts/bundle.f55a23d4.min.js b/v1/assets/javascripts/bundle.f55a23d4.min.js
deleted file mode 100644
index 01a46ad8..00000000
--- a/v1/assets/javascripts/bundle.f55a23d4.min.js
+++ /dev/null
@@ -1,16 +0,0 @@
-"use strict";(()=>{var Wi=Object.create;var gr=Object.defineProperty;var Vi=Object.getOwnPropertyDescriptor;var Di=Object.getOwnPropertyNames,Vt=Object.getOwnPropertySymbols,zi=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,ao=Object.prototype.propertyIsEnumerable;var io=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,$=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&io(e,r,t[r]);if(Vt)for(var r of Vt(t))ao.call(t,r)&&io(e,r,t[r]);return e};var so=(e,t)=>{var r={};for(var o in e)yr.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Vt)for(var o of Vt(e))t.indexOf(o)<0&&ao.call(e,o)&&(r[o]=e[o]);return r};var xr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Ni=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Di(t))!yr.call(e,n)&&n!==r&&gr(e,n,{get:()=>t[n],enumerable:!(o=Vi(t,n))||o.enumerable});return e};var Lt=(e,t,r)=>(r=e!=null?Wi(zi(e)):{},Ni(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var co=(e,t,r)=>new Promise((o,n)=>{var i=p=>{try{s(r.next(p))}catch(c){n(c)}},a=p=>{try{s(r.throw(p))}catch(c){n(c)}},s=p=>p.done?o(p.value):Promise.resolve(p.value).then(i,a);s((r=r.apply(e,t)).next())});var lo=xr((Er,po)=>{(function(e,t){typeof Er=="object"&&typeof po!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Er,(function(){"use strict";function e(r){var o=!0,n=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(k){return!!(k&&k!==document&&k.nodeName!=="HTML"&&k.nodeName!=="BODY"&&"classList"in k&&"contains"in k.classList)}function p(k){var ft=k.type,qe=k.tagName;return!!(qe==="INPUT"&&a[ft]&&!k.readOnly||qe==="TEXTAREA"&&!k.readOnly||k.isContentEditable)}function c(k){k.classList.contains("focus-visible")||(k.classList.add("focus-visible"),k.setAttribute("data-focus-visible-added",""))}function l(k){k.hasAttribute("data-focus-visible-added")&&(k.classList.remove("focus-visible"),k.removeAttribute("data-focus-visible-added"))}function f(k){k.metaKey||k.altKey||k.ctrlKey||(s(r.activeElement)&&c(r.activeElement),o=!0)}function u(k){o=!1}function d(k){s(k.target)&&(o||p(k.target))&&c(k.target)}function y(k){s(k.target)&&(k.target.classList.contains("focus-visible")||k.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(k.target))}function L(k){document.visibilityState==="hidden"&&(n&&(o=!0),X())}function X(){document.addEventListener("mousemove",J),document.addEventListener("mousedown",J),document.addEventListener("mouseup",J),document.addEventListener("pointermove",J),document.addEventListener("pointerdown",J),document.addEventListener("pointerup",J),document.addEventListener("touchmove",J),document.addEventListener("touchstart",J),document.addEventListener("touchend",J)}function ee(){document.removeEventListener("mousemove",J),document.removeEventListener("mousedown",J),document.removeEventListener("mouseup",J),document.removeEventListener("pointermove",J),document.removeEventListener("pointerdown",J),document.removeEventListener("pointerup",J),document.removeEventListener("touchmove",J),document.removeEventListener("touchstart",J),document.removeEventListener("touchend",J)}function J(k){k.target.nodeName&&k.target.nodeName.toLowerCase()==="html"||(o=!1,ee())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",L,!0),X(),r.addEventListener("focus",d,!0),r.addEventListener("blur",y,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)}))});var qr=xr((dy,On)=>{"use strict";/*!
- * escape-html
- * Copyright(c) 2012-2013 TJ Holowaychuk
- * Copyright(c) 2015 Andreas Lubbe
- * Copyright(c) 2015 Tiancheng "Timothy" Gu
- * MIT Licensed
- */var $a=/["'&<>]/;On.exports=Pa;function Pa(e){var t=""+e,r=$a.exec(t);if(!r)return t;var o,n="",i=0,a=0;for(i=r.index;i{/*!
- * clipboard.js v2.0.11
- * https://clipboardjs.com/
- *
- * Licensed MIT © Zeno Rocha
- */(function(t,r){typeof Rt=="object"&&typeof Yr=="object"?Yr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Rt=="object"?Rt.ClipboardJS=r():t.ClipboardJS=r()})(Rt,function(){return(function(){var e={686:(function(o,n,i){"use strict";i.d(n,{default:function(){return Ui}});var a=i(279),s=i.n(a),p=i(370),c=i.n(p),l=i(817),f=i.n(l);function u(D){try{return document.execCommand(D)}catch(A){return!1}}var d=function(A){var M=f()(A);return u("cut"),M},y=d;function L(D){var A=document.documentElement.getAttribute("dir")==="rtl",M=document.createElement("textarea");M.style.fontSize="12pt",M.style.border="0",M.style.padding="0",M.style.margin="0",M.style.position="absolute",M.style[A?"right":"left"]="-9999px";var F=window.pageYOffset||document.documentElement.scrollTop;return M.style.top="".concat(F,"px"),M.setAttribute("readonly",""),M.value=D,M}var X=function(A,M){var F=L(A);M.container.appendChild(F);var V=f()(F);return u("copy"),F.remove(),V},ee=function(A){var M=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},F="";return typeof A=="string"?F=X(A,M):A instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(A==null?void 0:A.type)?F=X(A.value,M):(F=f()(A),u("copy")),F},J=ee;function k(D){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?k=function(M){return typeof M}:k=function(M){return M&&typeof Symbol=="function"&&M.constructor===Symbol&&M!==Symbol.prototype?"symbol":typeof M},k(D)}var ft=function(){var A=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},M=A.action,F=M===void 0?"copy":M,V=A.container,Y=A.target,$e=A.text;if(F!=="copy"&&F!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(Y!==void 0)if(Y&&k(Y)==="object"&&Y.nodeType===1){if(F==="copy"&&Y.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(F==="cut"&&(Y.hasAttribute("readonly")||Y.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if($e)return J($e,{container:V});if(Y)return F==="cut"?y(Y):J(Y,{container:V})},qe=ft;function Fe(D){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Fe=function(M){return typeof M}:Fe=function(M){return M&&typeof Symbol=="function"&&M.constructor===Symbol&&M!==Symbol.prototype?"symbol":typeof M},Fe(D)}function ki(D,A){if(!(D instanceof A))throw new TypeError("Cannot call a class as a function")}function no(D,A){for(var M=0;M0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof V.action=="function"?V.action:this.defaultAction,this.target=typeof V.target=="function"?V.target:this.defaultTarget,this.text=typeof V.text=="function"?V.text:this.defaultText,this.container=Fe(V.container)==="object"?V.container:document.body}},{key:"listenClick",value:function(V){var Y=this;this.listener=c()(V,"click",function($e){return Y.onClick($e)})}},{key:"onClick",value:function(V){var Y=V.delegateTarget||V.currentTarget,$e=this.action(Y)||"copy",Wt=qe({action:$e,container:this.container,target:this.target(Y),text:this.text(Y)});this.emit(Wt?"success":"error",{action:$e,text:Wt,trigger:Y,clearSelection:function(){Y&&Y.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(V){return vr("action",V)}},{key:"defaultTarget",value:function(V){var Y=vr("target",V);if(Y)return document.querySelector(Y)}},{key:"defaultText",value:function(V){return vr("text",V)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(V){var Y=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return J(V,Y)}},{key:"cut",value:function(V){return y(V)}},{key:"isSupported",value:function(){var V=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Y=typeof V=="string"?[V]:V,$e=!!document.queryCommandSupported;return Y.forEach(function(Wt){$e=$e&&!!document.queryCommandSupported(Wt)}),$e}}]),M})(s()),Ui=Fi}),828:(function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,p){for(;s&&s.nodeType!==n;){if(typeof s.matches=="function"&&s.matches(p))return s;s=s.parentNode}}o.exports=a}),438:(function(o,n,i){var a=i(828);function s(l,f,u,d,y){var L=c.apply(this,arguments);return l.addEventListener(u,L,y),{destroy:function(){l.removeEventListener(u,L,y)}}}function p(l,f,u,d,y){return typeof l.addEventListener=="function"?s.apply(null,arguments):typeof u=="function"?s.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(L){return s(L,f,u,d,y)}))}function c(l,f,u,d){return function(y){y.delegateTarget=a(y.target,f),y.delegateTarget&&d.call(l,y)}}o.exports=p}),879:(function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}}),370:(function(o,n,i){var a=i(879),s=i(438);function p(u,d,y){if(!u&&!d&&!y)throw new Error("Missing required arguments");if(!a.string(d))throw new TypeError("Second argument must be a String");if(!a.fn(y))throw new TypeError("Third argument must be a Function");if(a.node(u))return c(u,d,y);if(a.nodeList(u))return l(u,d,y);if(a.string(u))return f(u,d,y);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(u,d,y){return u.addEventListener(d,y),{destroy:function(){u.removeEventListener(d,y)}}}function l(u,d,y){return Array.prototype.forEach.call(u,function(L){L.addEventListener(d,y)}),{destroy:function(){Array.prototype.forEach.call(u,function(L){L.removeEventListener(d,y)})}}}function f(u,d,y){return s(document.body,u,d,y)}o.exports=p}),817:(function(o){function n(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var p=window.getSelection(),c=document.createRange();c.selectNodeContents(i),p.removeAllRanges(),p.addRange(c),a=p.toString()}return a}o.exports=n}),279:(function(o){function n(){}n.prototype={on:function(i,a,s){var p=this.e||(this.e={});return(p[i]||(p[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var p=this;function c(){p.off(i,c),a.apply(s,arguments)}return c._=a,this.on(i,c,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),p=0,c=s.length;for(p;p0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function z(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],a;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(s){a={error:s}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(a)throw a.error}}return i}function q(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||p(d,L)})},y&&(n[d]=y(n[d])))}function p(d,y){try{c(o[d](y))}catch(L){u(i[0][3],L)}}function c(d){d.value instanceof nt?Promise.resolve(d.value.v).then(l,f):u(i[0][2],d)}function l(d){p("next",d)}function f(d){p("throw",d)}function u(d,y){d(y),i.shift(),i.length&&p(i[0][0],i[0][1])}}function uo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof he=="function"?he(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(a){return new Promise(function(s,p){a=e[i](a),n(s,p,a.done,a.value)})}}function n(i,a,s,p){Promise.resolve(p).then(function(c){i({value:c,done:s})},a)}}function H(e){return typeof e=="function"}function ut(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var zt=ut(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription:
-`+r.map(function(o,n){return n+1+") "+o.toString()}).join(`
- `):"",this.name="UnsubscriptionError",this.errors=r}});function Qe(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ue=(function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a)if(this._parentage=null,Array.isArray(a))try{for(var s=he(a),p=s.next();!p.done;p=s.next()){var c=p.value;c.remove(this)}}catch(L){t={error:L}}finally{try{p&&!p.done&&(r=s.return)&&r.call(s)}finally{if(t)throw t.error}}else a.remove(this);var l=this.initialTeardown;if(H(l))try{l()}catch(L){i=L instanceof zt?L.errors:[L]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=he(f),d=u.next();!d.done;d=u.next()){var y=d.value;try{ho(y)}catch(L){i=i!=null?i:[],L instanceof zt?i=q(q([],z(i)),z(L.errors)):i.push(L)}}}catch(L){o={error:L}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new zt(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)ho(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Qe(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Qe(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=(function(){var t=new e;return t.closed=!0,t})(),e})();var Tr=Ue.EMPTY;function Nt(e){return e instanceof Ue||e&&"closed"in e&&H(e.remove)&&H(e.add)&&H(e.unsubscribe)}function ho(e){H(e)?e():e.unsubscribe()}var Pe={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var dt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,a=n.isStopped,s=n.observers;return i||a?Tr:(this.currentObservers=null,s.push(r),new Ue(function(){o.currentObservers=null,Qe(s,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,a=o.isStopped;n?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new j;return r.source=this,r},t.create=function(r,o){return new To(r,o)},t})(j);var To=(function(e){oe(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:Tr},t})(g);var _r=(function(e){oe(t,e);function t(r){var o=e.call(this)||this;return o._value=r,o}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var o=e.prototype._subscribe.call(this,r);return!o.closed&&r.next(this._value),o},t.prototype.getValue=function(){var r=this,o=r.hasError,n=r.thrownError,i=r._value;if(o)throw n;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t})(g);var _t={now:function(){return(_t.delegate||Date).now()},delegate:void 0};var At=(function(e){oe(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=_t);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,a=o._infiniteTimeWindow,s=o._timestampProvider,p=o._windowTime;n||(i.push(r),!a&&i.push(s.now()+p)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,a=n._buffer,s=a.slice(),p=0;p0?e.prototype.schedule.call(this,r,o):(this.delay=o,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,o){return o>0||this.closed?e.prototype.execute.call(this,r,o):this._execute(r,o)},t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.flush(this),0)},t})(gt);var Lo=(function(e){oe(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t})(yt);var kr=new Lo(Oo);var Mo=(function(e){oe(t,e);function t(r,o){var n=e.call(this,r,o)||this;return n.scheduler=r,n.work=o,n}return t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!==null&&n>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=vt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var a=r.actions;o!=null&&o===r._scheduled&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==o&&(vt.cancelAnimationFrame(o),r._scheduled=void 0)},t})(gt);var _o=(function(e){oe(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o;r?o=r.id:(o=this._scheduled,this._scheduled=void 0);var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t})(yt);var me=new _o(Mo);var S=new j(function(e){return e.complete()});function Kt(e){return e&&H(e.schedule)}function Hr(e){return e[e.length-1]}function Xe(e){return H(Hr(e))?e.pop():void 0}function ke(e){return Kt(Hr(e))?e.pop():void 0}function Yt(e,t){return typeof Hr(e)=="number"?e.pop():t}var xt=(function(e){return e&&typeof e.length=="number"&&typeof e!="function"});function Bt(e){return H(e==null?void 0:e.then)}function Gt(e){return H(e[bt])}function Jt(e){return Symbol.asyncIterator&&H(e==null?void 0:e[Symbol.asyncIterator])}function Xt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Zi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Zt=Zi();function er(e){return H(e==null?void 0:e[Zt])}function tr(e){return fo(this,arguments,function(){var r,o,n,i;return Dt(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,nt(r.read())];case 3:return o=a.sent(),n=o.value,i=o.done,i?[4,nt(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,nt(n)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function rr(e){return H(e==null?void 0:e.getReader)}function U(e){if(e instanceof j)return e;if(e!=null){if(Gt(e))return ea(e);if(xt(e))return ta(e);if(Bt(e))return ra(e);if(Jt(e))return Ao(e);if(er(e))return oa(e);if(rr(e))return na(e)}throw Xt(e)}function ea(e){return new j(function(t){var r=e[bt]();if(H(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function ta(e){return new j(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?b(function(n,i){return e(n,i,o)}):le,Te(1),r?Ve(t):Qo(function(){return new nr}))}}function jr(e){return e<=0?function(){return S}:E(function(t,r){var o=[];t.subscribe(T(r,function(n){o.push(n),e=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new g}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,p=s===void 0?!0:s;return function(c){var l,f,u,d=0,y=!1,L=!1,X=function(){f==null||f.unsubscribe(),f=void 0},ee=function(){X(),l=u=void 0,y=L=!1},J=function(){var k=l;ee(),k==null||k.unsubscribe()};return E(function(k,ft){d++,!L&&!y&&X();var qe=u=u!=null?u:r();ft.add(function(){d--,d===0&&!L&&!y&&(f=Ur(J,p))}),qe.subscribe(ft),!l&&d>0&&(l=new at({next:function(Fe){return qe.next(Fe)},error:function(Fe){L=!0,X(),f=Ur(ee,n,Fe),qe.error(Fe)},complete:function(){y=!0,X(),f=Ur(ee,a),qe.complete()}}),U(k).subscribe(l))})(c)}}function Ur(e,t){for(var r=[],o=2;oe.next(document)),e}function P(e,t=document){return Array.from(t.querySelectorAll(e))}function R(e,t=document){let r=fe(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function fe(e,t=document){return t.querySelector(e)||void 0}function Ie(){var e,t,r,o;return(o=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?o:void 0}var wa=O(h(document.body,"focusin"),h(document.body,"focusout")).pipe(_e(1),Q(void 0),m(()=>Ie()||document.body),G(1));function et(e){return wa.pipe(m(t=>e.contains(t)),K())}function Ht(e,t){return C(()=>O(h(e,"mouseenter").pipe(m(()=>!0)),h(e,"mouseleave").pipe(m(()=>!1))).pipe(t?kt(r=>Le(+!r*t)):le,Q(e.matches(":hover"))))}function Jo(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)Jo(e,r)}function x(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)Jo(o,n);return o}function sr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function wt(e){let t=x("script",{src:e});return C(()=>(document.head.appendChild(t),O(h(t,"load"),h(t,"error").pipe(v(()=>$r(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),_(()=>document.head.removeChild(t)),Te(1))))}var Xo=new g,Ta=C(()=>typeof ResizeObserver=="undefined"?wt("https://unpkg.com/resize-observer-polyfill"):I(void 0)).pipe(m(()=>new ResizeObserver(e=>e.forEach(t=>Xo.next(t)))),v(e=>O(Ye,I(e)).pipe(_(()=>e.disconnect()))),G(1));function ce(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ge(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return Ta.pipe(w(r=>r.observe(t)),v(r=>Xo.pipe(b(o=>o.target===t),_(()=>r.unobserve(t)))),m(()=>ce(e)),Q(ce(e)))}function Tt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function cr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function Zo(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function De(e){return{x:e.offsetLeft,y:e.offsetTop}}function en(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function tn(e){return O(h(window,"load"),h(window,"resize")).pipe(Me(0,me),m(()=>De(e)),Q(De(e)))}function pr(e){return{x:e.scrollLeft,y:e.scrollTop}}function ze(e){return O(h(e,"scroll"),h(window,"scroll"),h(window,"resize")).pipe(Me(0,me),m(()=>pr(e)),Q(pr(e)))}var rn=new g,Sa=C(()=>I(new IntersectionObserver(e=>{for(let t of e)rn.next(t)},{threshold:0}))).pipe(v(e=>O(Ye,I(e)).pipe(_(()=>e.disconnect()))),G(1));function tt(e){return Sa.pipe(w(t=>t.observe(e)),v(t=>rn.pipe(b(({target:r})=>r===e),_(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function on(e,t=16){return ze(e).pipe(m(({y:r})=>{let o=ce(e),n=Tt(e);return r>=n.height-o.height-t}),K())}var lr={drawer:R("[data-md-toggle=drawer]"),search:R("[data-md-toggle=search]")};function nn(e){return lr[e].checked}function Je(e,t){lr[e].checked!==t&&lr[e].click()}function Ne(e){let t=lr[e];return h(t,"change").pipe(m(()=>t.checked),Q(t.checked))}function Oa(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function La(){return O(h(window,"compositionstart").pipe(m(()=>!0)),h(window,"compositionend").pipe(m(()=>!1))).pipe(Q(!1))}function an(){let e=h(window,"keydown").pipe(b(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:nn("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),b(({mode:t,type:r})=>{if(t==="global"){let o=Ie();if(typeof o!="undefined")return!Oa(o,r)}return!0}),pe());return La().pipe(v(t=>t?S:e))}function ye(){return new URL(location.href)}function lt(e,t=!1){if(B("navigation.instant")&&!t){let r=x("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function sn(){return new g}function cn(){return location.hash.slice(1)}function pn(e){let t=x("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Ma(e){return O(h(window,"hashchange"),e).pipe(m(cn),Q(cn()),b(t=>t.length>0),G(1))}function ln(e){return Ma(e).pipe(m(t=>fe(`[id="${t}"]`)),b(t=>typeof t!="undefined"))}function $t(e){let t=matchMedia(e);return ir(r=>t.addListener(()=>r(t.matches))).pipe(Q(t.matches))}function mn(){let e=matchMedia("print");return O(h(window,"beforeprint").pipe(m(()=>!0)),h(window,"afterprint").pipe(m(()=>!1))).pipe(Q(e.matches))}function zr(e,t){return e.pipe(v(r=>r?t():S))}function Nr(e,t){return new j(r=>{let o=new XMLHttpRequest;return o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network error"))}),o.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{var i;if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let a=(i=o.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(n.loaded/+a*100)}}),t.progress$.next(5)),o.send(),()=>o.abort()})}function je(e,t){return Nr(e,t).pipe(v(r=>r.text()),m(r=>JSON.parse(r)),G(1))}function fn(e,t){let r=new DOMParser;return Nr(e,t).pipe(v(o=>o.text()),m(o=>r.parseFromString(o,"text/html")),G(1))}function un(e,t){let r=new DOMParser;return Nr(e,t).pipe(v(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),G(1))}function dn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function hn(){return O(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(m(dn),Q(dn()))}function bn(){return{width:innerWidth,height:innerHeight}}function vn(){return h(window,"resize",{passive:!0}).pipe(m(bn),Q(bn()))}function gn(){return N([hn(),vn()]).pipe(m(([e,t])=>({offset:e,size:t})),G(1))}function mr(e,{viewport$:t,header$:r}){let o=t.pipe(te("size")),n=N([o,r]).pipe(m(()=>De(e)));return N([r,t,n]).pipe(m(([{height:i},{offset:a,size:s},{x:p,y:c}])=>({offset:{x:a.x-p,y:a.y-c+i},size:s})))}function _a(e){return h(e,"message",t=>t.data)}function Aa(e){let t=new g;return t.subscribe(r=>e.postMessage(r)),t}function yn(e,t=new Worker(e)){let r=_a(t),o=Aa(t),n=new g;n.subscribe(o);let i=o.pipe(Z(),ie(!0));return n.pipe(Z(),Re(r.pipe(W(i))),pe())}var Ca=R("#__config"),St=JSON.parse(Ca.textContent);St.base=`${new URL(St.base,ye())}`;function xe(){return St}function B(e){return St.features.includes(e)}function Ee(e,t){return typeof t!="undefined"?St.translations[e].replace("#",t.toString()):St.translations[e]}function Se(e,t=document){return R(`[data-md-component=${e}]`,t)}function ae(e,t=document){return P(`[data-md-component=${e}]`,t)}function ka(e){let t=R(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(m(()=>R(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function xn(e){if(!B("announce.dismiss")||!e.childElementCount)return S;if(!e.hidden){let t=R(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return C(()=>{let t=new g;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),ka(e).pipe(w(r=>t.next(r)),_(()=>t.complete()),m(r=>$({ref:e},r)))})}function Ha(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function En(e,t){let r=new g;return r.subscribe(({hidden:o})=>{e.hidden=o}),Ha(e,t).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))}function Pt(e,t){return t==="inline"?x("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},x("div",{class:"md-tooltip__inner md-typeset"})):x("div",{class:"md-tooltip",id:e,role:"tooltip"},x("div",{class:"md-tooltip__inner md-typeset"}))}function wn(...e){return x("div",{class:"md-tooltip2",role:"tooltip"},x("div",{class:"md-tooltip2__inner md-typeset"},e))}function Tn(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return x("aside",{class:"md-annotation",tabIndex:0},Pt(t),x("a",{href:r,class:"md-annotation__index",tabIndex:-1},x("span",{"data-md-annotation-id":e})))}else return x("aside",{class:"md-annotation",tabIndex:0},Pt(t),x("span",{class:"md-annotation__index",tabIndex:-1},x("span",{"data-md-annotation-id":e})))}function Sn(e){return x("button",{class:"md-clipboard md-icon",title:Ee("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}var Ln=Lt(qr());function Qr(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(p=>!e.terms[p]).reduce((p,c)=>[...p,x("del",null,(0,Ln.default)(c))," "],[]).slice(0,-1),i=xe(),a=new URL(e.location,i.base);B("search.highlight")&&a.searchParams.set("h",Object.entries(e.terms).filter(([,p])=>p).reduce((p,[c])=>`${p} ${c}`.trim(),""));let{tags:s}=xe();return x("a",{href:`${a}`,class:"md-search-result__link",tabIndex:-1},x("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&x("div",{class:"md-search-result__icon md-icon"}),r>0&&x("h1",null,e.title),r<=0&&x("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&x("nav",{class:"md-tags"},e.tags.map(p=>{let c=s?p in s?`md-tag-icon md-tag--${s[p]}`:"md-tag-icon":"";return x("span",{class:`md-tag ${c}`},p)})),o>0&&n.length>0&&x("p",{class:"md-search-result__terms"},Ee("search.result.term.missing"),": ",...n)))}function Mn(e){let t=e[0].score,r=[...e],o=xe(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),a=r.findIndex(l=>l.scoreQr(l,1)),...p.length?[x("details",{class:"md-search-result__more"},x("summary",{tabIndex:-1},x("div",null,p.length>0&&p.length===1?Ee("search.result.more.one"):Ee("search.result.more.other",p.length))),...p.map(l=>Qr(l,1)))]:[]];return x("li",{class:"md-search-result__item"},c)}function _n(e){return x("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>x("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?sr(r):r)))}function Kr(e){let t=`tabbed-control tabbed-control--${e}`;return x("div",{class:t,hidden:!0},x("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function An(e){return x("div",{class:"md-typeset__scrollwrap"},x("div",{class:"md-typeset__table"},e))}function Ra(e){var o;let t=xe(),r=new URL(`../${e.version}/`,t.base);return x("li",{class:"md-version__item"},x("a",{href:`${r}`,class:"md-version__link"},e.title,((o=t.version)==null?void 0:o.alias)&&e.aliases.length>0&&x("span",{class:"md-version__alias"},e.aliases[0])))}function Cn(e,t){var o;let r=xe();return e=e.filter(n=>{var i;return!((i=n.properties)!=null&&i.hidden)}),x("div",{class:"md-version"},x("button",{class:"md-version__current","aria-label":Ee("select.version")},t.title,((o=r.version)==null?void 0:o.alias)&&t.aliases.length>0&&x("span",{class:"md-version__alias"},t.aliases[0])),x("ul",{class:"md-version__list"},e.map(Ra)))}var Ia=0;function ja(e){let t=N([et(e),Ht(e)]).pipe(m(([o,n])=>o||n),K()),r=C(()=>Zo(e)).pipe(ne(ze),pt(1),He(t),m(()=>en(e)));return t.pipe(Ae(o=>o),v(()=>N([t,r])),m(([o,n])=>({active:o,offset:n})),pe())}function Fa(e,t){let{content$:r,viewport$:o}=t,n=`__tooltip2_${Ia++}`;return C(()=>{let i=new g,a=new _r(!1);i.pipe(Z(),ie(!1)).subscribe(a);let s=a.pipe(kt(c=>Le(+!c*250,kr)),K(),v(c=>c?r:S),w(c=>c.id=n),pe());N([i.pipe(m(({active:c})=>c)),s.pipe(v(c=>Ht(c,250)),Q(!1))]).pipe(m(c=>c.some(l=>l))).subscribe(a);let p=a.pipe(b(c=>c),re(s,o),m(([c,l,{size:f}])=>{let u=e.getBoundingClientRect(),d=u.width/2;if(l.role==="tooltip")return{x:d,y:8+u.height};if(u.y>=f.height/2){let{height:y}=ce(l);return{x:d,y:-16-y}}else return{x:d,y:16+u.height}}));return N([s,i,p]).subscribe(([c,{offset:l},f])=>{c.style.setProperty("--md-tooltip-host-x",`${l.x}px`),c.style.setProperty("--md-tooltip-host-y",`${l.y}px`),c.style.setProperty("--md-tooltip-x",`${f.x}px`),c.style.setProperty("--md-tooltip-y",`${f.y}px`),c.classList.toggle("md-tooltip2--top",f.y<0),c.classList.toggle("md-tooltip2--bottom",f.y>=0)}),a.pipe(b(c=>c),re(s,(c,l)=>l),b(c=>c.role==="tooltip")).subscribe(c=>{let l=ce(R(":scope > *",c));c.style.setProperty("--md-tooltip-width",`${l.width}px`),c.style.setProperty("--md-tooltip-tail","0px")}),a.pipe(K(),ve(me),re(s)).subscribe(([c,l])=>{l.classList.toggle("md-tooltip2--active",c)}),N([a.pipe(b(c=>c)),s]).subscribe(([c,l])=>{l.role==="dialog"?(e.setAttribute("aria-controls",n),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",n)}),a.pipe(b(c=>!c)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),ja(e).pipe(w(c=>i.next(c)),_(()=>i.complete()),m(c=>$({ref:e},c)))})}function mt(e,{viewport$:t},r=document.body){return Fa(e,{content$:new j(o=>{let n=e.title,i=wn(n);return o.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",n)}}),viewport$:t})}function Ua(e,t){let r=C(()=>N([tn(e),ze(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:a,height:s}=ce(e);return{x:o-i.x+a/2,y:n-i.y+s/2}}));return et(e).pipe(v(o=>r.pipe(m(n=>({active:o,offset:n})),Te(+!o||1/0))))}function kn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return C(()=>{let i=new g,a=i.pipe(Z(),ie(!0));return i.subscribe({next({offset:s}){e.style.setProperty("--md-tooltip-x",`${s.x}px`),e.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),tt(e).pipe(W(a)).subscribe(s=>{e.toggleAttribute("data-md-visible",s)}),O(i.pipe(b(({active:s})=>s)),i.pipe(_e(250),b(({active:s})=>!s))).subscribe({next({active:s}){s?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe(Me(16,me)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(pt(125,me),b(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?e.style.setProperty("--md-tooltip-0",`${-s}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(W(a),b(s=>!(s.metaKey||s.ctrlKey))).subscribe(s=>{s.stopPropagation(),s.preventDefault()}),h(n,"mousedown").pipe(W(a),re(i)).subscribe(([s,{active:p}])=>{var c;if(s.button!==0||s.metaKey||s.ctrlKey)s.preventDefault();else if(p){s.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(c=Ie())==null||c.blur()}}),r.pipe(W(a),b(s=>s===o),Ge(125)).subscribe(()=>e.focus()),Ua(e,t).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))})}function Wa(e){return e.tagName==="CODE"?P(".c, .c1, .cm",e):[e]}function Va(e){let t=[];for(let r of Wa(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let a;for(;a=/(\(\d+\))(!)?/.exec(i.textContent);){let[,s,p]=a;if(typeof p=="undefined"){let c=i.splitText(a.index);i=c.splitText(s.length),t.push(c)}else{i.textContent=s,t.push(i);break}}}}return t}function Hn(e,t){t.append(...Array.from(e.childNodes))}function fr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,a=new Map;for(let s of Va(t)){let[,p]=s.textContent.match(/\((\d+)\)/);fe(`:scope > li:nth-child(${p})`,e)&&(a.set(p,Tn(p,i)),s.replaceWith(a.get(p)))}return a.size===0?S:C(()=>{let s=new g,p=s.pipe(Z(),ie(!0)),c=[];for(let[l,f]of a)c.push([R(".md-typeset",f),R(`:scope > li:nth-child(${l})`,e)]);return o.pipe(W(p)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of c)l?Hn(f,u):Hn(u,f)}),O(...[...a].map(([,l])=>kn(l,t,{target$:r}))).pipe(_(()=>s.complete()),pe())})}function $n(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return $n(t)}}function Pn(e,t){return C(()=>{let r=$n(e);return typeof r!="undefined"?fr(r,e,t):S})}var Rn=Lt(Br());var Da=0;function In(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return In(t)}}function za(e){return ge(e).pipe(m(({width:t})=>({scrollable:Tt(e).width>t})),te("scrollable"))}function jn(e,t){let{matches:r}=matchMedia("(hover)"),o=C(()=>{let n=new g,i=n.pipe(jr(1));n.subscribe(({scrollable:c})=>{c&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let a=[];if(Rn.default.isSupported()&&(e.closest(".copy")||B("content.code.copy")&&!e.closest(".no-copy"))){let c=e.closest("pre");c.id=`__code_${Da++}`;let l=Sn(c.id);c.insertBefore(l,e),B("content.tooltips")&&a.push(mt(l,{viewport$}))}let s=e.closest(".highlight");if(s instanceof HTMLElement){let c=In(s);if(typeof c!="undefined"&&(s.classList.contains("annotate")||B("content.code.annotate"))){let l=fr(c,e,t);a.push(ge(s).pipe(W(i),m(({width:f,height:u})=>f&&u),K(),v(f=>f?l:S)))}}return P(":scope > span[id]",e).length&&e.classList.add("md-code__content"),za(e).pipe(w(c=>n.next(c)),_(()=>n.complete()),m(c=>$({ref:e},c)),Re(...a))});return B("content.lazy")?tt(e).pipe(b(n=>n),Te(1),v(()=>o)):o}function Na(e,{target$:t,print$:r}){let o=!0;return O(t.pipe(m(n=>n.closest("details:not([open])")),b(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(b(n=>n||!o),w(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function Fn(e,t){return C(()=>{let r=new g;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),Na(e,t).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}var Un=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.flowchartTitleText{fill:var(--md-mermaid-label-fg-color)}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel p,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel p{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color)}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}.classDiagramTitleText{fill:var(--md-mermaid-label-fg-color)}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs marker.marker.composition.class path,defs marker.marker.dependency.class path,defs marker.marker.extension.class path{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs marker.marker.aggregation.class path{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}.statediagramTitleText{fill:var(--md-mermaid-label-fg-color)}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}a .nodeLabel{text-decoration:underline}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}[id^=entity] path,[id^=entity] rect{fill:var(--md-default-bg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs .marker.oneOrMore.er *,defs .marker.onlyOne.er *,defs .marker.zeroOrMore.er *,defs .marker.zeroOrOne.er *{stroke:var(--md-mermaid-edge-color)!important}text:not([class]):last-child{fill:var(--md-mermaid-label-fg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var Gr,Qa=0;function Ka(){return typeof mermaid=="undefined"||mermaid instanceof Element?wt("https://unpkg.com/mermaid@11/dist/mermaid.min.js"):I(void 0)}function Wn(e){return e.classList.remove("mermaid"),Gr||(Gr=Ka().pipe(w(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Un,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),G(1))),Gr.subscribe(()=>co(null,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${Qa++}`,r=x("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),a=r.attachShadow({mode:"closed"});a.innerHTML=n,e.replaceWith(r),i==null||i(a)})),Gr.pipe(m(()=>({ref:e})))}var Vn=x("table");function Dn(e){return e.replaceWith(Vn),Vn.replaceWith(An(e)),I({ref:e})}function Ya(e){let t=e.find(r=>r.checked)||e[0];return O(...e.map(r=>h(r,"change").pipe(m(()=>R(`label[for="${r.id}"]`))))).pipe(Q(R(`label[for="${t.id}"]`)),m(r=>({active:r})))}function zn(e,{viewport$:t,target$:r}){let o=R(".tabbed-labels",e),n=P(":scope > input",e),i=Kr("prev");e.append(i);let a=Kr("next");return e.append(a),C(()=>{let s=new g,p=s.pipe(Z(),ie(!0));N([s,ge(e),tt(e)]).pipe(W(p),Me(1,me)).subscribe({next([{active:c},l]){let f=De(c),{width:u}=ce(c);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=pr(o);(f.xd.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),N([ze(o),ge(o)]).pipe(W(p)).subscribe(([c,l])=>{let f=Tt(o);i.hidden=c.x<16,a.hidden=c.x>f.width-l.width-16}),O(h(i,"click").pipe(m(()=>-1)),h(a,"click").pipe(m(()=>1))).pipe(W(p)).subscribe(c=>{let{width:l}=ce(o);o.scrollBy({left:l*c,behavior:"smooth"})}),r.pipe(W(p),b(c=>n.includes(c))).subscribe(c=>c.click()),o.classList.add("tabbed-labels--linked");for(let c of n){let l=R(`label[for="${c.id}"]`);l.replaceChildren(x("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),h(l.firstElementChild,"click").pipe(W(p),b(f=>!(f.metaKey||f.ctrlKey)),w(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return B("content.tabs.link")&&s.pipe(Ce(1),re(t)).subscribe(([{active:c},{offset:l}])=>{let f=c.innerText.trim();if(c.hasAttribute("data-md-switching"))c.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let y of P("[data-tabs]"))for(let L of P(":scope > input",y)){let X=R(`label[for="${L.id}"]`);if(X!==c&&X.innerText.trim()===f){X.setAttribute("data-md-switching",""),L.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...d])])}}),s.pipe(W(p)).subscribe(()=>{for(let c of P("audio, video",e))c.offsetWidth&&c.autoplay?c.play().catch(()=>{}):c.pause()}),Ya(n).pipe(w(c=>s.next(c)),_(()=>s.complete()),m(c=>$({ref:e},c)))}).pipe(Ke(se))}function Nn(e,{viewport$:t,target$:r,print$:o}){return O(...P(".annotate:not(.highlight)",e).map(n=>Pn(n,{target$:r,print$:o})),...P("pre:not(.mermaid) > code",e).map(n=>jn(n,{target$:r,print$:o})),...P("pre.mermaid",e).map(n=>Wn(n)),...P("table:not([class])",e).map(n=>Dn(n)),...P("details",e).map(n=>Fn(n,{target$:r,print$:o})),...P("[data-tabs]",e).map(n=>zn(n,{viewport$:t,target$:r})),...P("[title]",e).filter(()=>B("content.tooltips")).map(n=>mt(n,{viewport$:t})))}function Ba(e,{alert$:t}){return t.pipe(v(r=>O(I(!0),I(!1).pipe(Ge(2e3))).pipe(m(o=>({message:r,active:o})))))}function qn(e,t){let r=R(".md-typeset",e);return C(()=>{let o=new g;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),Ba(e,t).pipe(w(n=>o.next(n)),_(()=>o.complete()),m(n=>$({ref:e},n)))})}var Ga=0;function Ja(e,t){document.body.append(e);let{width:r}=ce(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=cr(t),n=typeof o!="undefined"?ze(o):I({x:0,y:0}),i=O(et(t),Ht(t)).pipe(K());return N([i,n]).pipe(m(([a,s])=>{let{x:p,y:c}=De(t),l=ce(t),f=t.closest("table");return f&&t.parentElement&&(p+=f.offsetLeft+t.parentElement.offsetLeft,c+=f.offsetTop+t.parentElement.offsetTop),{active:a,offset:{x:p-s.x+l.width/2-r/2,y:c-s.y+l.height+8}}}))}function Qn(e){let t=e.title;if(!t.length)return S;let r=`__tooltip_${Ga++}`,o=Pt(r,"inline"),n=R(".md-typeset",o);return n.innerHTML=t,C(()=>{let i=new g;return i.subscribe({next({offset:a}){o.style.setProperty("--md-tooltip-x",`${a.x}px`),o.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),O(i.pipe(b(({active:a})=>a)),i.pipe(_e(250),b(({active:a})=>!a))).subscribe({next({active:a}){a?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe(Me(16,me)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(pt(125,me),b(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?o.style.setProperty("--md-tooltip-0",`${-a}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),Ja(o,e).pipe(w(a=>i.next(a)),_(()=>i.complete()),m(a=>$({ref:e},a)))}).pipe(Ke(se))}function Xa({viewport$:e}){if(!B("header.autohide"))return I(!1);let t=e.pipe(m(({offset:{y:n}})=>n),Be(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),K()),o=Ne("search");return N([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),K(),v(n=>n?r:I(!1)),Q(!1))}function Kn(e,t){return C(()=>N([ge(e),Xa(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),K((r,o)=>r.height===o.height&&r.hidden===o.hidden),G(1))}function Yn(e,{header$:t,main$:r}){return C(()=>{let o=new g,n=o.pipe(Z(),ie(!0));o.pipe(te("active"),He(t)).subscribe(([{active:a},{hidden:s}])=>{e.classList.toggle("md-header--shadow",a&&!s),e.hidden=s});let i=ue(P("[title]",e)).pipe(b(()=>B("content.tooltips")),ne(a=>Qn(a)));return r.subscribe(o),t.pipe(W(n),m(a=>$({ref:e},a)),Re(i.pipe(W(n))))})}function Za(e,{viewport$:t,header$:r}){return mr(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=ce(e);return{active:n>0&&o>=n}}),te("active"))}function Bn(e,t){return C(()=>{let r=new g;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=fe(".md-content h1");return typeof o=="undefined"?S:Za(o,t).pipe(w(n=>r.next(n)),_(()=>r.complete()),m(n=>$({ref:e},n)))})}function Gn(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),K()),n=o.pipe(v(()=>ge(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),te("bottom"))));return N([o,n,t]).pipe(m(([i,{top:a,bottom:s},{offset:{y:p},size:{height:c}}])=>(c=Math.max(0,c-Math.max(0,a-p,i)-Math.max(0,c+p-s)),{offset:a-i,height:c,active:a-i<=p})),K((i,a)=>i.offset===a.offset&&i.height===a.height&&i.active===a.active))}function es(e){let t=__md_get("__palette")||{index:e.findIndex(o=>matchMedia(o.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return I(...e).pipe(ne(o=>h(o,"change").pipe(m(()=>o))),Q(e[r]),m(o=>({index:e.indexOf(o),color:{media:o.getAttribute("data-md-color-media"),scheme:o.getAttribute("data-md-color-scheme"),primary:o.getAttribute("data-md-color-primary"),accent:o.getAttribute("data-md-color-accent")}})),G(1))}function Jn(e){let t=P("input",e),r=x("meta",{name:"theme-color"});document.head.appendChild(r);let o=x("meta",{name:"color-scheme"});document.head.appendChild(o);let n=$t("(prefers-color-scheme: light)");return C(()=>{let i=new g;return i.subscribe(a=>{if(document.body.setAttribute("data-md-color-switching",""),a.color.media==="(prefers-color-scheme)"){let s=matchMedia("(prefers-color-scheme: light)"),p=document.querySelector(s.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");a.color.scheme=p.getAttribute("data-md-color-scheme"),a.color.primary=p.getAttribute("data-md-color-primary"),a.color.accent=p.getAttribute("data-md-color-accent")}for(let[s,p]of Object.entries(a.color))document.body.setAttribute(`data-md-color-${s}`,p);for(let s=0;sa.key==="Enter"),re(i,(a,s)=>s)).subscribe(({index:a})=>{a=(a+1)%t.length,t[a].click(),t[a].focus()}),i.pipe(m(()=>{let a=Se("header"),s=window.getComputedStyle(a);return o.content=s.colorScheme,s.backgroundColor.match(/\d+/g).map(p=>(+p).toString(16).padStart(2,"0")).join("")})).subscribe(a=>r.content=`#${a}`),i.pipe(ve(se)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),es(t).pipe(W(n.pipe(Ce(1))),ct(),w(a=>i.next(a)),_(()=>i.complete()),m(a=>$({ref:e},a)))})}function Xn(e,{progress$:t}){return C(()=>{let r=new g;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(w(o=>r.next({value:o})),_(()=>r.complete()),m(o=>({ref:e,value:o})))})}var Jr=Lt(Br());function ts(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function Zn({alert$:e}){Jr.default.isSupported()&&new j(t=>{new Jr.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||ts(R(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(w(t=>{t.trigger.focus()}),m(()=>Ee("clipboard.copied"))).subscribe(e)}function ei(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,e}function rs(e,t){let r=new Map;for(let o of P("url",e)){let n=R("loc",o),i=[ei(new URL(n.textContent),t)];r.set(`${i[0]}`,i);for(let a of P("[rel=alternate]",o)){let s=a.getAttribute("href");s!=null&&i.push(ei(new URL(s),t))}}return r}function ur(e){return un(new URL("sitemap.xml",e)).pipe(m(t=>rs(t,new URL(e))),de(()=>I(new Map)))}function os(e,t){if(!(e.target instanceof Element))return S;let r=e.target.closest("a");if(r===null)return S;if(r.target||e.metaKey||e.ctrlKey)return S;let o=new URL(r.href);return o.search=o.hash="",t.has(`${o}`)?(e.preventDefault(),I(new URL(r.href))):S}function ti(e){let t=new Map;for(let r of P(":scope > *",e.head))t.set(r.outerHTML,r);return t}function ri(e){for(let t of P("[href], [src]",e))for(let r of["href","src"]){let o=t.getAttribute(r);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){t[r]=t[r];break}}return I(e)}function ns(e){for(let o of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...B("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let n=fe(o),i=fe(o,e);typeof n!="undefined"&&typeof i!="undefined"&&n.replaceWith(i)}let t=ti(document);for(let[o,n]of ti(e))t.has(o)?t.delete(o):document.head.appendChild(n);for(let o of t.values()){let n=o.getAttribute("name");n!=="theme-color"&&n!=="color-scheme"&&o.remove()}let r=Se("container");return We(P("script",r)).pipe(v(o=>{let n=e.createElement("script");if(o.src){for(let i of o.getAttributeNames())n.setAttribute(i,o.getAttribute(i));return o.replaceWith(n),new j(i=>{n.onload=()=>i.complete()})}else return n.textContent=o.textContent,o.replaceWith(n),S}),Z(),ie(document))}function oi({location$:e,viewport$:t,progress$:r}){let o=xe();if(location.protocol==="file:")return S;let n=ur(o.base);I(document).subscribe(ri);let i=h(document.body,"click").pipe(He(n),v(([p,c])=>os(p,c)),pe()),a=h(window,"popstate").pipe(m(ye),pe());i.pipe(re(t)).subscribe(([p,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",p)}),O(i,a).subscribe(e);let s=e.pipe(te("pathname"),v(p=>fn(p,{progress$:r}).pipe(de(()=>(lt(p,!0),S)))),v(ri),v(ns),pe());return O(s.pipe(re(e,(p,c)=>c)),s.pipe(v(()=>e),te("hash")),e.pipe(K((p,c)=>p.pathname===c.pathname&&p.hash===c.hash),v(()=>i),w(()=>history.back()))).subscribe(p=>{var c,l;history.state!==null||!p.hash?window.scrollTo(0,(l=(c=history.state)==null?void 0:c.y)!=null?l:0):(history.scrollRestoration="auto",pn(p.hash),history.scrollRestoration="manual")}),e.subscribe(()=>{history.scrollRestoration="manual"}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),t.pipe(te("offset"),_e(100)).subscribe(({offset:p})=>{history.replaceState(p,"")}),s}var ni=Lt(qr());function ii(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,a)=>`${i}${a}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").replace(/&/g,"&").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return a=>(0,ni.default)(a).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function It(e){return e.type===1}function dr(e){return e.type===3}function ai(e,t){let r=yn(e);return O(I(location.protocol!=="file:"),Ne("search")).pipe(Ae(o=>o),v(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:B("search.suggest")}}})),r}function si(e){var l;let{selectedVersionSitemap:t,selectedVersionBaseURL:r,currentLocation:o,currentBaseURL:n}=e,i=(l=Xr(n))==null?void 0:l.pathname;if(i===void 0)return;let a=ss(o.pathname,i);if(a===void 0)return;let s=ps(t.keys());if(!t.has(s))return;let p=Xr(a,s);if(!p||!t.has(p.href))return;let c=Xr(a,r);if(c)return c.hash=o.hash,c.search=o.search,c}function Xr(e,t){try{return new URL(e,t)}catch(r){return}}function ss(e,t){if(e.startsWith(t))return e.slice(t.length)}function cs(e,t){let r=Math.min(e.length,t.length),o;for(o=0;oS)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:a,aliases:s})=>a===i||s.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),v(n=>h(document.body,"click").pipe(b(i=>!i.metaKey&&!i.ctrlKey),re(o),v(([i,a])=>{if(i.target instanceof Element){let s=i.target.closest("a");if(s&&!s.target&&n.has(s.href)){let p=s.href;return!i.target.closest(".md-version")&&n.get(p)===a?S:(i.preventDefault(),I(new URL(p)))}}return S}),v(i=>ur(i).pipe(m(a=>{var s;return(s=si({selectedVersionSitemap:a,selectedVersionBaseURL:i,currentLocation:ye(),currentBaseURL:t.base}))!=null?s:i})))))).subscribe(n=>lt(n,!0)),N([r,o]).subscribe(([n,i])=>{R(".md-header__topic").appendChild(Cn(n,i))}),e.pipe(v(()=>o)).subscribe(n=>{var s;let i=new URL(t.base),a=__md_get("__outdated",sessionStorage,i);if(a===null){a=!0;let p=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(p)||(p=[p]);e:for(let c of p)for(let l of n.aliases.concat(n.version))if(new RegExp(c,"i").test(l)){a=!1;break e}__md_set("__outdated",a,sessionStorage,i)}if(a)for(let p of ae("outdated"))p.hidden=!1})}function ls(e,{worker$:t}){let{searchParams:r}=ye();r.has("q")&&(Je("search",!0),e.value=r.get("q"),e.focus(),Ne("search").pipe(Ae(i=>!i)).subscribe(()=>{let i=ye();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=et(e),n=O(t.pipe(Ae(It)),h(e,"keyup"),o).pipe(m(()=>e.value),K());return N([n,o]).pipe(m(([i,a])=>({value:i,focus:a})),G(1))}function pi(e,{worker$:t}){let r=new g,o=r.pipe(Z(),ie(!0));N([t.pipe(Ae(It)),r],(i,a)=>a).pipe(te("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(te("focus")).subscribe(({focus:i})=>{i&&Je("search",i)}),h(e.form,"reset").pipe(W(o)).subscribe(()=>e.focus());let n=R("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),ls(e,{worker$:t}).pipe(w(i=>r.next(i)),_(()=>r.complete()),m(i=>$({ref:e},i)),G(1))}function li(e,{worker$:t,query$:r}){let o=new g,n=on(e.parentElement).pipe(b(Boolean)),i=e.parentElement,a=R(":scope > :first-child",e),s=R(":scope > :last-child",e);Ne("search").subscribe(l=>{s.setAttribute("role",l?"list":"presentation"),s.hidden=!l}),o.pipe(re(r),Wr(t.pipe(Ae(It)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:a.textContent=f.length?Ee("search.result.none"):Ee("search.result.placeholder");break;case 1:a.textContent=Ee("search.result.one");break;default:let u=sr(l.length);a.textContent=Ee("search.result.other",u)}});let p=o.pipe(w(()=>s.innerHTML=""),v(({items:l})=>O(I(...l.slice(0,10)),I(...l.slice(10)).pipe(Be(4),Dr(n),v(([f])=>f)))),m(Mn),pe());return p.subscribe(l=>s.appendChild(l)),p.pipe(ne(l=>{let f=fe("details",l);return typeof f=="undefined"?S:h(f,"toggle").pipe(W(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(b(dr),m(({data:l})=>l)).pipe(w(l=>o.next(l)),_(()=>o.complete()),m(l=>$({ref:e},l)))}function ms(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=ye();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function mi(e,t){let r=new g,o=r.pipe(Z(),ie(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(W(o)).subscribe(n=>n.preventDefault()),ms(e,t).pipe(w(n=>r.next(n)),_(()=>r.complete()),m(n=>$({ref:e},n)))}function fi(e,{worker$:t,keyboard$:r}){let o=new g,n=Se("search-query"),i=O(h(n,"keydown"),h(n,"focus")).pipe(ve(se),m(()=>n.value),K());return o.pipe(He(i),m(([{suggest:s},p])=>{let c=p.split(/([\s-]+)/);if(s!=null&&s.length&&c[c.length-1]){let l=s[s.length-1];l.startsWith(c[c.length-1])&&(c[c.length-1]=l)}else c.length=0;return c})).subscribe(s=>e.innerHTML=s.join("").replace(/\s/g," ")),r.pipe(b(({mode:s})=>s==="search")).subscribe(s=>{switch(s.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(b(dr),m(({data:s})=>s)).pipe(w(s=>o.next(s)),_(()=>o.complete()),m(()=>({ref:e})))}function ui(e,{index$:t,keyboard$:r}){let o=xe();try{let n=ai(o.search,t),i=Se("search-query",e),a=Se("search-result",e);h(e,"click").pipe(b(({target:p})=>p instanceof Element&&!!p.closest("a"))).subscribe(()=>Je("search",!1)),r.pipe(b(({mode:p})=>p==="search")).subscribe(p=>{let c=Ie();switch(p.type){case"Enter":if(c===i){let l=new Map;for(let f of P(":first-child [href]",a)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,d])=>d-u);f.click()}p.claim()}break;case"Escape":case"Tab":Je("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof c=="undefined")i.focus();else{let l=[i,...P(":not(details) > [href], summary, details[open] [href]",a)],f=Math.max(0,(Math.max(0,l.indexOf(c))+l.length+(p.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}p.claim();break;default:i!==Ie()&&i.focus()}}),r.pipe(b(({mode:p})=>p==="global")).subscribe(p=>{switch(p.type){case"f":case"s":case"/":i.focus(),i.select(),p.claim();break}});let s=pi(i,{worker$:n});return O(s,li(a,{worker$:n,query$:s})).pipe(Re(...ae("search-share",e).map(p=>mi(p,{query$:s})),...ae("search-suggest",e).map(p=>fi(p,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,Ye}}function di(e,{index$:t,location$:r}){return N([t,r.pipe(Q(ye()),b(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>ii(o.config)(n.searchParams.get("h"))),m(o=>{var a;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let s=i.nextNode();s;s=i.nextNode())if((a=s.parentElement)!=null&&a.offsetHeight){let p=s.textContent,c=o(p);c.length>p.length&&n.set(s,c)}for(let[s,p]of n){let{childNodes:c}=x("span",null,p);s.replaceWith(...Array.from(c))}return{ref:e,nodes:n}}))}function fs(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return N([r,t]).pipe(m(([{offset:i,height:a},{offset:{y:s}}])=>(a=a+Math.min(n,Math.max(0,s-i))-n,{height:a,locked:s>=i+n})),K((i,a)=>i.height===a.height&&i.locked===a.locked))}function Zr(e,o){var n=o,{header$:t}=n,r=so(n,["header$"]);let i=R(".md-sidebar__scrollwrap",e),{y:a}=De(i);return C(()=>{let s=new g,p=s.pipe(Z(),ie(!0)),c=s.pipe(Me(0,me));return c.pipe(re(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*a}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),c.pipe(Ae()).subscribe(()=>{for(let l of P(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=ce(f);f.scrollTo({top:u-d/2})}}}),ue(P("label[tabindex]",e)).pipe(ne(l=>h(l,"click").pipe(ve(se),m(()=>l),W(p)))).subscribe(l=>{let f=R(`[id="${l.htmlFor}"]`);R(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),fs(e,r).pipe(w(l=>s.next(l)),_(()=>s.complete()),m(l=>$({ref:e},l)))})}function hi(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return st(je(`${r}/releases/latest`).pipe(de(()=>S),m(o=>({version:o.tag_name})),Ve({})),je(r).pipe(de(()=>S),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),Ve({}))).pipe(m(([o,n])=>$($({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return je(r).pipe(m(o=>({repositories:o.public_repos})),Ve({}))}}function bi(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return st(je(`${r}/releases/permalink/latest`).pipe(de(()=>S),m(({tag_name:o})=>({version:o})),Ve({})),je(r).pipe(de(()=>S),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),Ve({}))).pipe(m(([o,n])=>$($({},o),n)))}function vi(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return hi(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return bi(r,o)}return S}var us;function ds(e){return us||(us=C(()=>{let t=__md_get("__source",sessionStorage);if(t)return I(t);if(ae("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return S}return vi(e.href).pipe(w(o=>__md_set("__source",o,sessionStorage)))}).pipe(de(()=>S),b(t=>Object.keys(t).length>0),m(t=>({facts:t})),G(1)))}function gi(e){let t=R(":scope > :last-child",e);return C(()=>{let r=new g;return r.subscribe(({facts:o})=>{t.appendChild(_n(o)),t.classList.add("md-source__repository--active")}),ds(e).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}function hs(e,{viewport$:t,header$:r}){return ge(document.body).pipe(v(()=>mr(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),te("hidden"))}function yi(e,t){return C(()=>{let r=new g;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(B("navigation.tabs.sticky")?I({hidden:!1}):hs(e,t)).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}function bs(e,{viewport$:t,header$:r}){let o=new Map,n=P(".md-nav__link",e);for(let s of n){let p=decodeURIComponent(s.hash.substring(1)),c=fe(`[id="${p}"]`);typeof c!="undefined"&&o.set(s,c)}let i=r.pipe(te("height"),m(({height:s})=>{let p=Se("main"),c=R(":scope > :first-child",p);return s+.8*(c.offsetTop-p.offsetTop)}),pe());return ge(document.body).pipe(te("height"),v(s=>C(()=>{let p=[];return I([...o].reduce((c,[l,f])=>{for(;p.length&&o.get(p[p.length-1]).tagName>=f.tagName;)p.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return c.set([...p=[...p,l]].reverse(),u)},new Map))}).pipe(m(p=>new Map([...p].sort(([,c],[,l])=>c-l))),He(i),v(([p,c])=>t.pipe(Fr(([l,f],{offset:{y:u},size:d})=>{let y=u+d.height>=Math.floor(s.height);for(;f.length;){let[,L]=f[0];if(L-c=u&&!y)f=[l.pop(),...f];else break}return[l,f]},[[],[...p]]),K((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([s,p])=>({prev:s.map(([c])=>c),next:p.map(([c])=>c)})),Q({prev:[],next:[]}),Be(2,1),m(([s,p])=>s.prev.length{let i=new g,a=i.pipe(Z(),ie(!0));if(i.subscribe(({prev:s,next:p})=>{for(let[c]of p)c.classList.remove("md-nav__link--passed"),c.classList.remove("md-nav__link--active");for(let[c,[l]]of s.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",c===s.length-1)}),B("toc.follow")){let s=O(t.pipe(_e(1),m(()=>{})),t.pipe(_e(250),m(()=>"smooth")));i.pipe(b(({prev:p})=>p.length>0),He(o.pipe(ve(se))),re(s)).subscribe(([[{prev:p}],c])=>{let[l]=p[p.length-1];if(l.offsetHeight){let f=cr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=ce(f);f.scrollTo({top:u-d/2,behavior:c})}}})}return B("navigation.tracking")&&t.pipe(W(a),te("offset"),_e(250),Ce(1),W(n.pipe(Ce(1))),ct({delay:250}),re(i)).subscribe(([,{prev:s}])=>{let p=ye(),c=s[s.length-1];if(c&&c.length){let[l]=c,{hash:f}=new URL(l.href);p.hash!==f&&(p.hash=f,history.replaceState({},"",`${p}`))}else p.hash="",history.replaceState({},"",`${p}`)}),bs(e,{viewport$:t,header$:r}).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))})}function vs(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:a}})=>a),Be(2,1),m(([a,s])=>a>s&&s>0),K()),i=r.pipe(m(({active:a})=>a));return N([i,n]).pipe(m(([a,s])=>!(a&&s)),K(),W(o.pipe(Ce(1))),ie(!0),ct({delay:250}),m(a=>({hidden:a})))}function Ei(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new g,a=i.pipe(Z(),ie(!0));return i.subscribe({next({hidden:s}){e.hidden=s,s?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(W(a),te("height")).subscribe(({height:s})=>{e.style.top=`${s+16}px`}),h(e,"click").subscribe(s=>{s.preventDefault(),window.scrollTo({top:0})}),vs(e,{viewport$:t,main$:o,target$:n}).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))}function wi({document$:e,viewport$:t}){e.pipe(v(()=>P(".md-ellipsis")),ne(r=>tt(r).pipe(W(e.pipe(Ce(1))),b(o=>o),m(()=>r),Te(1))),b(r=>r.offsetWidth{let o=r.innerText,n=r.closest("a")||r;return n.title=o,B("content.tooltips")?mt(n,{viewport$:t}).pipe(W(e.pipe(Ce(1))),_(()=>n.removeAttribute("title"))):S})).subscribe(),B("content.tooltips")&&e.pipe(v(()=>P(".md-status")),ne(r=>mt(r,{viewport$:t}))).subscribe()}function Ti({document$:e,tablet$:t}){e.pipe(v(()=>P(".md-toggle--indeterminate")),w(r=>{r.indeterminate=!0,r.checked=!1}),ne(r=>h(r,"change").pipe(Vr(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),re(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function gs(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Si({document$:e}){e.pipe(v(()=>P("[data-md-scrollfix]")),w(t=>t.removeAttribute("data-md-scrollfix")),b(gs),ne(t=>h(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Oi({viewport$:e,tablet$:t}){N([Ne("search"),t]).pipe(m(([r,o])=>r&&!o),v(r=>I(r).pipe(Ge(r?400:100))),re(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function ys(){return location.protocol==="file:"?wt(`${new URL("search/search_index.js",eo.base)}`).pipe(m(()=>__index),G(1)):je(new URL("search/search_index.json",eo.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var ot=Go(),Ft=sn(),Ot=ln(Ft),to=an(),Oe=gn(),hr=$t("(min-width: 60em)"),Mi=$t("(min-width: 76.25em)"),_i=mn(),eo=xe(),Ai=document.forms.namedItem("search")?ys():Ye,ro=new g;Zn({alert$:ro});var oo=new g;B("navigation.instant")&&oi({location$:Ft,viewport$:Oe,progress$:oo}).subscribe(ot);var Li;((Li=eo.version)==null?void 0:Li.provider)==="mike"&&ci({document$:ot});O(Ft,Ot).pipe(Ge(125)).subscribe(()=>{Je("drawer",!1),Je("search",!1)});to.pipe(b(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=fe("link[rel=prev]");typeof t!="undefined"&<(t);break;case"n":case".":let r=fe("link[rel=next]");typeof r!="undefined"&<(r);break;case"Enter":let o=Ie();o instanceof HTMLLabelElement&&o.click()}});wi({viewport$:Oe,document$:ot});Ti({document$:ot,tablet$:hr});Si({document$:ot});Oi({viewport$:Oe,tablet$:hr});var rt=Kn(Se("header"),{viewport$:Oe}),jt=ot.pipe(m(()=>Se("main")),v(e=>Gn(e,{viewport$:Oe,header$:rt})),G(1)),xs=O(...ae("consent").map(e=>En(e,{target$:Ot})),...ae("dialog").map(e=>qn(e,{alert$:ro})),...ae("palette").map(e=>Jn(e)),...ae("progress").map(e=>Xn(e,{progress$:oo})),...ae("search").map(e=>ui(e,{index$:Ai,keyboard$:to})),...ae("source").map(e=>gi(e))),Es=C(()=>O(...ae("announce").map(e=>xn(e)),...ae("content").map(e=>Nn(e,{viewport$:Oe,target$:Ot,print$:_i})),...ae("content").map(e=>B("search.highlight")?di(e,{index$:Ai,location$:Ft}):S),...ae("header").map(e=>Yn(e,{viewport$:Oe,header$:rt,main$:jt})),...ae("header-title").map(e=>Bn(e,{viewport$:Oe,header$:rt})),...ae("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?zr(Mi,()=>Zr(e,{viewport$:Oe,header$:rt,main$:jt})):zr(hr,()=>Zr(e,{viewport$:Oe,header$:rt,main$:jt}))),...ae("tabs").map(e=>yi(e,{viewport$:Oe,header$:rt})),...ae("toc").map(e=>xi(e,{viewport$:Oe,header$:rt,main$:jt,target$:Ot})),...ae("top").map(e=>Ei(e,{viewport$:Oe,header$:rt,main$:jt,target$:Ot})))),Ci=ot.pipe(v(()=>Es),Re(xs),G(1));Ci.subscribe();window.document$=ot;window.location$=Ft;window.target$=Ot;window.keyboard$=to;window.viewport$=Oe;window.tablet$=hr;window.screen$=Mi;window.print$=_i;window.alert$=ro;window.progress$=oo;window.component$=Ci;})();
-//# sourceMappingURL=bundle.f55a23d4.min.js.map
-
diff --git a/v1/assets/javascripts/bundle.f55a23d4.min.js.map b/v1/assets/javascripts/bundle.f55a23d4.min.js.map
deleted file mode 100644
index e3de73ff..00000000
--- a/v1/assets/javascripts/bundle.f55a23d4.min.js.map
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "version": 3,
- "sources": ["node_modules/focus-visible/dist/focus-visible.js", "node_modules/escape-html/index.js", "node_modules/clipboard/dist/clipboard.js", "src/templates/assets/javascripts/bundle.ts", "node_modules/tslib/tslib.es6.mjs", "node_modules/rxjs/src/internal/util/isFunction.ts", "node_modules/rxjs/src/internal/util/createErrorClass.ts", "node_modules/rxjs/src/internal/util/UnsubscriptionError.ts", "node_modules/rxjs/src/internal/util/arrRemove.ts", "node_modules/rxjs/src/internal/Subscription.ts", "node_modules/rxjs/src/internal/config.ts", "node_modules/rxjs/src/internal/scheduler/timeoutProvider.ts", "node_modules/rxjs/src/internal/util/reportUnhandledError.ts", "node_modules/rxjs/src/internal/util/noop.ts", "node_modules/rxjs/src/internal/NotificationFactories.ts", "node_modules/rxjs/src/internal/util/errorContext.ts", "node_modules/rxjs/src/internal/Subscriber.ts", "node_modules/rxjs/src/internal/symbol/observable.ts", "node_modules/rxjs/src/internal/util/identity.ts", "node_modules/rxjs/src/internal/util/pipe.ts", "node_modules/rxjs/src/internal/Observable.ts", "node_modules/rxjs/src/internal/util/lift.ts", "node_modules/rxjs/src/internal/operators/OperatorSubscriber.ts", "node_modules/rxjs/src/internal/scheduler/animationFrameProvider.ts", "node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts", "node_modules/rxjs/src/internal/Subject.ts", "node_modules/rxjs/src/internal/BehaviorSubject.ts", "node_modules/rxjs/src/internal/scheduler/dateTimestampProvider.ts", "node_modules/rxjs/src/internal/ReplaySubject.ts", "node_modules/rxjs/src/internal/scheduler/Action.ts", "node_modules/rxjs/src/internal/scheduler/intervalProvider.ts", "node_modules/rxjs/src/internal/scheduler/AsyncAction.ts", "node_modules/rxjs/src/internal/Scheduler.ts", "node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts", "node_modules/rxjs/src/internal/scheduler/async.ts", "node_modules/rxjs/src/internal/scheduler/QueueAction.ts", "node_modules/rxjs/src/internal/scheduler/QueueScheduler.ts", "node_modules/rxjs/src/internal/scheduler/queue.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameAction.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameScheduler.ts", "node_modules/rxjs/src/internal/scheduler/animationFrame.ts", "node_modules/rxjs/src/internal/observable/empty.ts", "node_modules/rxjs/src/internal/util/isScheduler.ts", "node_modules/rxjs/src/internal/util/args.ts", "node_modules/rxjs/src/internal/util/isArrayLike.ts", "node_modules/rxjs/src/internal/util/isPromise.ts", "node_modules/rxjs/src/internal/util/isInteropObservable.ts", "node_modules/rxjs/src/internal/util/isAsyncIterable.ts", "node_modules/rxjs/src/internal/util/throwUnobservableError.ts", "node_modules/rxjs/src/internal/symbol/iterator.ts", "node_modules/rxjs/src/internal/util/isIterable.ts", "node_modules/rxjs/src/internal/util/isReadableStreamLike.ts", "node_modules/rxjs/src/internal/observable/innerFrom.ts", "node_modules/rxjs/src/internal/util/executeSchedule.ts", "node_modules/rxjs/src/internal/operators/observeOn.ts", "node_modules/rxjs/src/internal/operators/subscribeOn.ts", "node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts", "node_modules/rxjs/src/internal/scheduled/schedulePromise.ts", "node_modules/rxjs/src/internal/scheduled/scheduleArray.ts", "node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleAsyncIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduled.ts", "node_modules/rxjs/src/internal/observable/from.ts", "node_modules/rxjs/src/internal/observable/of.ts", "node_modules/rxjs/src/internal/observable/throwError.ts", "node_modules/rxjs/src/internal/util/EmptyError.ts", "node_modules/rxjs/src/internal/util/isDate.ts", "node_modules/rxjs/src/internal/operators/map.ts", "node_modules/rxjs/src/internal/util/mapOneOrManyArgs.ts", "node_modules/rxjs/src/internal/util/argsArgArrayOrObject.ts", "node_modules/rxjs/src/internal/util/createObject.ts", "node_modules/rxjs/src/internal/observable/combineLatest.ts", "node_modules/rxjs/src/internal/operators/mergeInternals.ts", "node_modules/rxjs/src/internal/operators/mergeMap.ts", "node_modules/rxjs/src/internal/operators/mergeAll.ts", "node_modules/rxjs/src/internal/operators/concatAll.ts", "node_modules/rxjs/src/internal/observable/concat.ts", "node_modules/rxjs/src/internal/observable/defer.ts", "node_modules/rxjs/src/internal/observable/fromEvent.ts", "node_modules/rxjs/src/internal/observable/fromEventPattern.ts", "node_modules/rxjs/src/internal/observable/timer.ts", "node_modules/rxjs/src/internal/observable/merge.ts", "node_modules/rxjs/src/internal/observable/never.ts", "node_modules/rxjs/src/internal/util/argsOrArgArray.ts", "node_modules/rxjs/src/internal/operators/filter.ts", "node_modules/rxjs/src/internal/observable/zip.ts", "node_modules/rxjs/src/internal/operators/audit.ts", "node_modules/rxjs/src/internal/operators/auditTime.ts", "node_modules/rxjs/src/internal/operators/bufferCount.ts", "node_modules/rxjs/src/internal/operators/catchError.ts", "node_modules/rxjs/src/internal/operators/scanInternals.ts", "node_modules/rxjs/src/internal/operators/combineLatest.ts", "node_modules/rxjs/src/internal/operators/combineLatestWith.ts", "node_modules/rxjs/src/internal/operators/debounce.ts", "node_modules/rxjs/src/internal/operators/debounceTime.ts", "node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts", "node_modules/rxjs/src/internal/operators/take.ts", "node_modules/rxjs/src/internal/operators/ignoreElements.ts", "node_modules/rxjs/src/internal/operators/mapTo.ts", "node_modules/rxjs/src/internal/operators/delayWhen.ts", "node_modules/rxjs/src/internal/operators/delay.ts", "node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts", "node_modules/rxjs/src/internal/operators/distinctUntilKeyChanged.ts", "node_modules/rxjs/src/internal/operators/throwIfEmpty.ts", "node_modules/rxjs/src/internal/operators/endWith.ts", "node_modules/rxjs/src/internal/operators/finalize.ts", "node_modules/rxjs/src/internal/operators/first.ts", "node_modules/rxjs/src/internal/operators/takeLast.ts", "node_modules/rxjs/src/internal/operators/merge.ts", "node_modules/rxjs/src/internal/operators/mergeWith.ts", "node_modules/rxjs/src/internal/operators/repeat.ts", "node_modules/rxjs/src/internal/operators/scan.ts", "node_modules/rxjs/src/internal/operators/share.ts", "node_modules/rxjs/src/internal/operators/shareReplay.ts", "node_modules/rxjs/src/internal/operators/skip.ts", "node_modules/rxjs/src/internal/operators/skipUntil.ts", "node_modules/rxjs/src/internal/operators/startWith.ts", "node_modules/rxjs/src/internal/operators/switchMap.ts", "node_modules/rxjs/src/internal/operators/takeUntil.ts", "node_modules/rxjs/src/internal/operators/takeWhile.ts", "node_modules/rxjs/src/internal/operators/tap.ts", "node_modules/rxjs/src/internal/operators/throttle.ts", "node_modules/rxjs/src/internal/operators/throttleTime.ts", "node_modules/rxjs/src/internal/operators/withLatestFrom.ts", "node_modules/rxjs/src/internal/operators/zip.ts", "node_modules/rxjs/src/internal/operators/zipWith.ts", "src/templates/assets/javascripts/browser/document/index.ts", "src/templates/assets/javascripts/browser/element/_/index.ts", "src/templates/assets/javascripts/browser/element/focus/index.ts", "src/templates/assets/javascripts/browser/element/hover/index.ts", "src/templates/assets/javascripts/utilities/h/index.ts", "src/templates/assets/javascripts/utilities/round/index.ts", "src/templates/assets/javascripts/browser/script/index.ts", "src/templates/assets/javascripts/browser/element/size/_/index.ts", "src/templates/assets/javascripts/browser/element/size/content/index.ts", "src/templates/assets/javascripts/browser/element/offset/_/index.ts", "src/templates/assets/javascripts/browser/element/offset/content/index.ts", "src/templates/assets/javascripts/browser/element/visibility/index.ts", "src/templates/assets/javascripts/browser/toggle/index.ts", "src/templates/assets/javascripts/browser/keyboard/index.ts", "src/templates/assets/javascripts/browser/location/_/index.ts", "src/templates/assets/javascripts/browser/location/hash/index.ts", "src/templates/assets/javascripts/browser/media/index.ts", "src/templates/assets/javascripts/browser/request/index.ts", "src/templates/assets/javascripts/browser/viewport/offset/index.ts", "src/templates/assets/javascripts/browser/viewport/size/index.ts", "src/templates/assets/javascripts/browser/viewport/_/index.ts", "src/templates/assets/javascripts/browser/viewport/at/index.ts", "src/templates/assets/javascripts/browser/worker/index.ts", "src/templates/assets/javascripts/_/index.ts", "src/templates/assets/javascripts/components/_/index.ts", "src/templates/assets/javascripts/components/announce/index.ts", "src/templates/assets/javascripts/components/consent/index.ts", "src/templates/assets/javascripts/templates/tooltip/index.tsx", "src/templates/assets/javascripts/templates/annotation/index.tsx", "src/templates/assets/javascripts/templates/clipboard/index.tsx", "src/templates/assets/javascripts/templates/search/index.tsx", "src/templates/assets/javascripts/templates/source/index.tsx", "src/templates/assets/javascripts/templates/tabbed/index.tsx", "src/templates/assets/javascripts/templates/table/index.tsx", "src/templates/assets/javascripts/templates/version/index.tsx", "src/templates/assets/javascripts/components/tooltip2/index.ts", "src/templates/assets/javascripts/components/content/annotation/_/index.ts", "src/templates/assets/javascripts/components/content/annotation/list/index.ts", "src/templates/assets/javascripts/components/content/annotation/block/index.ts", "src/templates/assets/javascripts/components/content/code/_/index.ts", "src/templates/assets/javascripts/components/content/details/index.ts", "src/templates/assets/javascripts/components/content/mermaid/index.css", "src/templates/assets/javascripts/components/content/mermaid/index.ts", "src/templates/assets/javascripts/components/content/table/index.ts", "src/templates/assets/javascripts/components/content/tabs/index.ts", "src/templates/assets/javascripts/components/content/_/index.ts", "src/templates/assets/javascripts/components/dialog/index.ts", "src/templates/assets/javascripts/components/tooltip/index.ts", "src/templates/assets/javascripts/components/header/_/index.ts", "src/templates/assets/javascripts/components/header/title/index.ts", "src/templates/assets/javascripts/components/main/index.ts", "src/templates/assets/javascripts/components/palette/index.ts", "src/templates/assets/javascripts/components/progress/index.ts", "src/templates/assets/javascripts/integrations/clipboard/index.ts", "src/templates/assets/javascripts/integrations/sitemap/index.ts", "src/templates/assets/javascripts/integrations/instant/index.ts", "src/templates/assets/javascripts/integrations/search/highlighter/index.ts", "src/templates/assets/javascripts/integrations/search/worker/message/index.ts", "src/templates/assets/javascripts/integrations/search/worker/_/index.ts", "src/templates/assets/javascripts/integrations/version/findurl/index.ts", "src/templates/assets/javascripts/integrations/version/index.ts", "src/templates/assets/javascripts/components/search/query/index.ts", "src/templates/assets/javascripts/components/search/result/index.ts", "src/templates/assets/javascripts/components/search/share/index.ts", "src/templates/assets/javascripts/components/search/suggest/index.ts", "src/templates/assets/javascripts/components/search/_/index.ts", "src/templates/assets/javascripts/components/search/highlight/index.ts", "src/templates/assets/javascripts/components/sidebar/index.ts", "src/templates/assets/javascripts/components/source/facts/github/index.ts", "src/templates/assets/javascripts/components/source/facts/gitlab/index.ts", "src/templates/assets/javascripts/components/source/facts/_/index.ts", "src/templates/assets/javascripts/components/source/_/index.ts", "src/templates/assets/javascripts/components/tabs/index.ts", "src/templates/assets/javascripts/components/toc/index.ts", "src/templates/assets/javascripts/components/top/index.ts", "src/templates/assets/javascripts/patches/ellipsis/index.ts", "src/templates/assets/javascripts/patches/indeterminate/index.ts", "src/templates/assets/javascripts/patches/scrollfix/index.ts", "src/templates/assets/javascripts/patches/scrolllock/index.ts", "src/templates/assets/javascripts/polyfills/index.ts"],
- "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. \u00AF\\_(\u30C4)_/\u00AF\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*!\n * clipboard.js v2.0.11\n * https://clipboardjs.com/\n *\n * Licensed MIT \u00A9 Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 686:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/common/command.js\n/**\n * Executes a given operation type.\n * @param {String} type\n * @return {Boolean}\n */\nfunction command(type) {\n try {\n return document.execCommand(type);\n } catch (err) {\n return false;\n }\n}\n;// CONCATENATED MODULE: ./src/actions/cut.js\n\n\n/**\n * Cut action wrapper.\n * @param {String|HTMLElement} target\n * @return {String}\n */\n\nvar ClipboardActionCut = function ClipboardActionCut(target) {\n var selectedText = select_default()(target);\n command('cut');\n return selectedText;\n};\n\n/* harmony default export */ var actions_cut = (ClipboardActionCut);\n;// CONCATENATED MODULE: ./src/common/create-fake-element.js\n/**\n * Creates a fake textarea element with a value.\n * @param {String} value\n * @return {HTMLElement}\n */\nfunction createFakeElement(value) {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS\n\n fakeElement.style.fontSize = '12pt'; // Reset box model\n\n fakeElement.style.border = '0';\n fakeElement.style.padding = '0';\n fakeElement.style.margin = '0'; // Move element out of screen horizontally\n\n fakeElement.style.position = 'absolute';\n fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n fakeElement.style.top = \"\".concat(yPosition, \"px\");\n fakeElement.setAttribute('readonly', '');\n fakeElement.value = value;\n return fakeElement;\n}\n;// CONCATENATED MODULE: ./src/actions/copy.js\n\n\n\n/**\n * Create fake copy action wrapper using a fake element.\n * @param {String} target\n * @param {Object} options\n * @return {String}\n */\n\nvar fakeCopyAction = function fakeCopyAction(value, options) {\n var fakeElement = createFakeElement(value);\n options.container.appendChild(fakeElement);\n var selectedText = select_default()(fakeElement);\n command('copy');\n fakeElement.remove();\n return selectedText;\n};\n/**\n * Copy action wrapper.\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @return {String}\n */\n\n\nvar ClipboardActionCopy = function ClipboardActionCopy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n var selectedText = '';\n\n if (typeof target === 'string') {\n selectedText = fakeCopyAction(target, options);\n } else if (target instanceof HTMLInputElement && !['text', 'search', 'url', 'tel', 'password'].includes(target === null || target === void 0 ? void 0 : target.type)) {\n // If input type doesn't support `setSelectionRange`. Simulate it. https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange\n selectedText = fakeCopyAction(target.value, options);\n } else {\n selectedText = select_default()(target);\n command('copy');\n }\n\n return selectedText;\n};\n\n/* harmony default export */ var actions_copy = (ClipboardActionCopy);\n;// CONCATENATED MODULE: ./src/actions/default.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/**\n * Inner function which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n * @param {Object} options\n */\n\nvar ClipboardActionDefault = function ClipboardActionDefault() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n // Defines base properties passed from constructor.\n var _options$action = options.action,\n action = _options$action === void 0 ? 'copy' : _options$action,\n container = options.container,\n target = options.target,\n text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'.\n\n if (action !== 'copy' && action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n } // Sets the `target` property using an element that will be have its content copied.\n\n\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n } // Define selection strategy based on `text` property.\n\n\n if (text) {\n return actions_copy(text, {\n container: container\n });\n } // Defines which selection strategy based on `target` property.\n\n\n if (target) {\n return action === 'cut' ? actions_cut(target) : actions_copy(target, {\n container: container\n });\n }\n};\n\n/* harmony default export */ var actions_default = (ClipboardActionDefault);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n _classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n _createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n var action = this.action(trigger) || 'copy';\n var text = actions_default({\n action: action,\n container: this.container,\n target: this.target(trigger),\n text: this.text(trigger)\n }); // Fires an event based on the copy operation result.\n\n this.emit(text ? 'success' : 'error', {\n action: action,\n text: text,\n trigger: trigger,\n clearSelection: function clearSelection() {\n if (trigger) {\n trigger.focus();\n }\n\n window.getSelection().removeAllRanges();\n }\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Allow fire programmatically a copy action\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @returns Text copied.\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n }\n }], [{\n key: \"copy\",\n value: function copy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n return actions_copy(target, options);\n }\n /**\n * Allow fire programmatically a cut action\n * @param {String|HTMLElement} target\n * @returns Text cutted.\n */\n\n }, {\n key: \"cut\",\n value: function cut(target) {\n return actions_cut(target);\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(686);\n/******/ })()\n.default;\n});", "/*\n * Copyright (c) 2016-2025 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"focus-visible\"\n\nimport {\n EMPTY,\n NEVER,\n Observable,\n Subject,\n defer,\n delay,\n filter,\n map,\n merge,\n mergeWith,\n shareReplay,\n switchMap\n} from \"rxjs\"\n\nimport { configuration, feature } from \"./_\"\nimport {\n at,\n getActiveElement,\n getOptionalElement,\n requestJSON,\n setLocation,\n setToggle,\n watchDocument,\n watchKeyboard,\n watchLocation,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchScript,\n watchViewport\n} from \"./browser\"\nimport {\n getComponentElement,\n getComponentElements,\n mountAnnounce,\n mountBackToTop,\n mountConsent,\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountPalette,\n mountProgress,\n mountSearch,\n mountSearchHiglight,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n SearchIndex,\n setupClipboardJS,\n setupInstantNavigation,\n setupVersionSelector\n} from \"./integrations\"\nimport {\n patchEllipsis,\n patchIndeterminate,\n patchScrollfix,\n patchScrolllock\n} from \"./patches\"\nimport \"./polyfills\"\n\n/* ----------------------------------------------------------------------------\n * Functions - @todo refactor\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch search index\n *\n * @returns Search index observable\n */\nfunction fetchSearchIndex(): Observable {\n if (location.protocol === \"file:\") {\n return watchScript(\n `${new URL(\"search/search_index.js\", config.base)}`\n )\n .pipe(\n // @ts-ignore - @todo fix typings\n map(() => __index),\n shareReplay(1)\n )\n } else {\n return requestJSON(\n new URL(\"search/search_index.json\", config.base)\n )\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Application\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up navigation observables and subjects */\nconst document$ = watchDocument()\nconst location$ = watchLocation()\nconst target$ = watchLocationTarget(location$)\nconst keyboard$ = watchKeyboard()\n\n/* Set up media observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 60em)\")\nconst screen$ = watchMedia(\"(min-width: 76.25em)\")\nconst print$ = watchPrint()\n\n/* Retrieve search index, if search is enabled */\nconst config = configuration()\nconst index$ = document.forms.namedItem(\"search\")\n ? fetchSearchIndex()\n : NEVER\n\n/* Set up Clipboard.js integration */\nconst alert$ = new Subject()\nsetupClipboardJS({ alert$ })\n\n/* Set up progress indicator */\nconst progress$ = new Subject()\n\n/* Set up instant navigation, if enabled */\nif (feature(\"navigation.instant\"))\n setupInstantNavigation({ location$, viewport$, progress$ })\n .subscribe(document$)\n\n/* Set up version selector */\nif (config.version?.provider === \"mike\")\n setupVersionSelector({ document$ })\n\n/* Always close drawer and search on navigation */\nmerge(location$, target$)\n .pipe(\n delay(125)\n )\n .subscribe(() => {\n setToggle(\"drawer\", false)\n setToggle(\"search\", false)\n })\n\n/* Set up global keyboard handlers */\nkeyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Go to previous page */\n case \"p\":\n case \",\":\n const prev = getOptionalElement(\"link[rel=prev]\")\n if (typeof prev !== \"undefined\")\n setLocation(prev)\n break\n\n /* Go to next page */\n case \"n\":\n case \".\":\n const next = getOptionalElement(\"link[rel=next]\")\n if (typeof next !== \"undefined\")\n setLocation(next)\n break\n\n /* Expand navigation, see https://bit.ly/3ZjG5io */\n case \"Enter\":\n const active = getActiveElement()\n if (active instanceof HTMLLabelElement)\n active.click()\n }\n })\n\n/* Set up patches */\npatchEllipsis({ viewport$, document$ })\npatchIndeterminate({ document$, tablet$ })\npatchScrollfix({ document$ })\npatchScrolllock({ viewport$, tablet$ })\n\n/* Set up header and main area observable */\nconst header$ = watchHeader(getComponentElement(\"header\"), { viewport$ })\nconst main$ = document$\n .pipe(\n map(() => getComponentElement(\"main\")),\n switchMap(el => watchMain(el, { viewport$, header$ })),\n shareReplay(1)\n )\n\n/* Set up control component observables */\nconst control$ = merge(\n\n /* Consent */\n ...getComponentElements(\"consent\")\n .map(el => mountConsent(el, { target$ })),\n\n /* Dialog */\n ...getComponentElements(\"dialog\")\n .map(el => mountDialog(el, { alert$ })),\n\n /* Color palette */\n ...getComponentElements(\"palette\")\n .map(el => mountPalette(el)),\n\n /* Progress bar */\n ...getComponentElements(\"progress\")\n .map(el => mountProgress(el, { progress$ })),\n\n /* Search */\n ...getComponentElements(\"search\")\n .map(el => mountSearch(el, { index$, keyboard$ })),\n\n /* Repository information */\n ...getComponentElements(\"source\")\n .map(el => mountSource(el))\n)\n\n/* Set up content component observables */\nconst content$ = defer(() => merge(\n\n /* Announcement bar */\n ...getComponentElements(\"announce\")\n .map(el => mountAnnounce(el)),\n\n /* Content */\n ...getComponentElements(\"content\")\n .map(el => mountContent(el, { viewport$, target$, print$ })),\n\n /* Search highlighting */\n ...getComponentElements(\"content\")\n .map(el => feature(\"search.highlight\")\n ? mountSearchHiglight(el, { index$, location$ })\n : EMPTY\n ),\n\n /* Header */\n ...getComponentElements(\"header\")\n .map(el => mountHeader(el, { viewport$, header$, main$ })),\n\n /* Header title */\n ...getComponentElements(\"header-title\")\n .map(el => mountHeaderTitle(el, { viewport$, header$ })),\n\n /* Sidebar */\n ...getComponentElements(\"sidebar\")\n .map(el => el.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(el, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(el, { viewport$, header$, main$ }))\n ),\n\n /* Navigation tabs */\n ...getComponentElements(\"tabs\")\n .map(el => mountTabs(el, { viewport$, header$ })),\n\n /* Table of contents */\n ...getComponentElements(\"toc\")\n .map(el => mountTableOfContents(el, {\n viewport$, header$, main$, target$\n })),\n\n /* Back-to-top button */\n ...getComponentElements(\"top\")\n .map(el => mountBackToTop(el, { viewport$, header$, main$, target$ }))\n))\n\n/* Set up component observables */\nconst component$ = document$\n .pipe(\n switchMap(() => content$),\n mergeWith(control$),\n shareReplay(1)\n )\n\n/* Subscribe to all components */\ncomponent$.subscribe()\n\n/* ----------------------------------------------------------------------------\n * Exports\n * ------------------------------------------------------------------------- */\n\nwindow.document$ = document$ /* Document observable */\nwindow.location$ = location$ /* Location subject */\nwindow.target$ = target$ /* Location target observable */\nwindow.keyboard$ = keyboard$ /* Keyboard observable */\nwindow.viewport$ = viewport$ /* Viewport observable */\nwindow.tablet$ = tablet$ /* Media tablet observable */\nwindow.screen$ = screen$ /* Media screen observable */\nwindow.print$ = print$ /* Media print observable */\nwindow.alert$ = alert$ /* Alert subject */\nwindow.progress$ = progress$ /* Progress indicator subject */\nwindow.component$ = component$ /* Component observable */\n", "/******************************************************************************\nCopyright (c) Microsoft Corporation.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n***************************************************************************** */\n/* global Reflect, Promise, SuppressedError, Symbol, Iterator */\n\nvar extendStatics = function(d, b) {\n extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\n return extendStatics(d, b);\n};\n\nexport function __extends(d, b) {\n if (typeof b !== \"function\" && b !== null)\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n}\n\nexport var __assign = function() {\n __assign = Object.assign || function __assign(t) {\n for (var s, i = 1, n = arguments.length; i < n; i++) {\n s = arguments[i];\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n }\n return t;\n }\n return __assign.apply(this, arguments);\n}\n\nexport function __rest(s, e) {\n var t = {};\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\n t[p] = s[p];\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\n t[p[i]] = s[p[i]];\n }\n return t;\n}\n\nexport function __decorate(decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n}\n\nexport function __param(paramIndex, decorator) {\n return function (target, key) { decorator(target, key, paramIndex); }\n}\n\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\n var _, done = false;\n for (var i = decorators.length - 1; i >= 0; i--) {\n var context = {};\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\n if (kind === \"accessor\") {\n if (result === void 0) continue;\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\n if (_ = accept(result.get)) descriptor.get = _;\n if (_ = accept(result.set)) descriptor.set = _;\n if (_ = accept(result.init)) initializers.unshift(_);\n }\n else if (_ = accept(result)) {\n if (kind === \"field\") initializers.unshift(_);\n else descriptor[key] = _;\n }\n }\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\n done = true;\n};\n\nexport function __runInitializers(thisArg, initializers, value) {\n var useValue = arguments.length > 2;\n for (var i = 0; i < initializers.length; i++) {\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\n }\n return useValue ? value : void 0;\n};\n\nexport function __propKey(x) {\n return typeof x === \"symbol\" ? x : \"\".concat(x);\n};\n\nexport function __setFunctionName(f, name, prefix) {\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\n};\n\nexport function __metadata(metadataKey, metadataValue) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\n}\n\nexport function __awaiter(thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n}\n\nexport function __generator(thisArg, body) {\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === \"function\" ? Iterator : Object).prototype);\n return g.next = verb(0), g[\"throw\"] = verb(1), g[\"return\"] = verb(2), typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\n function verb(n) { return function (v) { return step([n, v]); }; }\n function step(op) {\n if (f) throw new TypeError(\"Generator is already executing.\");\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\n if (y = 0, t) op = [op[0] & 2, t.value];\n switch (op[0]) {\n case 0: case 1: t = op; break;\n case 4: _.label++; return { value: op[1], done: false };\n case 5: _.label++; y = op[1]; op = [0]; continue;\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\n default:\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\n if (t[2]) _.ops.pop();\n _.trys.pop(); continue;\n }\n op = body.call(thisArg, _);\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\n }\n}\n\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n var desc = Object.getOwnPropertyDescriptor(m, k);\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n desc = { enumerable: true, get: function() { return m[k]; } };\n }\n Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n});\n\nexport function __exportStar(m, o) {\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\n}\n\nexport function __values(o) {\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\n if (m) return m.call(o);\n if (o && typeof o.length === \"number\") return {\n next: function () {\n if (o && i >= o.length) o = void 0;\n return { value: o && o[i++], done: !o };\n }\n };\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\n}\n\nexport function __read(o, n) {\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\n if (!m) return o;\n var i = m.call(o), r, ar = [], e;\n try {\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\n }\n catch (error) { e = { error: error }; }\n finally {\n try {\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\n }\n finally { if (e) throw e.error; }\n }\n return ar;\n}\n\n/** @deprecated */\nexport function __spread() {\n for (var ar = [], i = 0; i < arguments.length; i++)\n ar = ar.concat(__read(arguments[i]));\n return ar;\n}\n\n/** @deprecated */\nexport function __spreadArrays() {\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\n r[k] = a[j];\n return r;\n}\n\nexport function __spreadArray(to, from, pack) {\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\n if (ar || !(i in from)) {\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\n ar[i] = from[i];\n }\n }\n return to.concat(ar || Array.prototype.slice.call(from));\n}\n\nexport function __await(v) {\n return this instanceof __await ? (this.v = v, this) : new __await(v);\n}\n\nexport function __asyncGenerator(thisArg, _arguments, generator) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\n return i = Object.create((typeof AsyncIterator === \"function\" ? AsyncIterator : Object).prototype), verb(\"next\"), verb(\"throw\"), verb(\"return\", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;\n function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }\n function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\n function fulfill(value) { resume(\"next\", value); }\n function reject(value) { resume(\"throw\", value); }\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\n}\n\nexport function __asyncDelegator(o) {\n var i, p;\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\n}\n\nexport function __asyncValues(o) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var m = o[Symbol.asyncIterator], i;\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\n}\n\nexport function __makeTemplateObject(cooked, raw) {\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\n return cooked;\n};\n\nvar __setModuleDefault = Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n};\n\nexport function __importStar(mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\n __setModuleDefault(result, mod);\n return result;\n}\n\nexport function __importDefault(mod) {\n return (mod && mod.__esModule) ? mod : { default: mod };\n}\n\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n}\n\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n}\n\nexport function __classPrivateFieldIn(state, receiver) {\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\n}\n\nexport function __addDisposableResource(env, value, async) {\n if (value !== null && value !== void 0) {\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\n var dispose, inner;\n if (async) {\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\n dispose = value[Symbol.asyncDispose];\n }\n if (dispose === void 0) {\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\n dispose = value[Symbol.dispose];\n if (async) inner = dispose;\n }\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\n if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };\n env.stack.push({ value: value, dispose: dispose, async: async });\n }\n else if (async) {\n env.stack.push({ async: true });\n }\n return value;\n}\n\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n var e = new Error(message);\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n};\n\nexport function __disposeResources(env) {\n function fail(e) {\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\n env.hasError = true;\n }\n var r, s = 0;\n function next() {\n while (r = env.stack.pop()) {\n try {\n if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);\n if (r.dispose) {\n var result = r.dispose.call(r.value);\n if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\n }\n else s |= 1;\n }\n catch (e) {\n fail(e);\n }\n }\n if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();\n if (env.hasError) throw env.error;\n }\n return next();\n}\n\nexport default {\n __extends,\n __assign,\n __rest,\n __decorate,\n __param,\n __metadata,\n __awaiter,\n __generator,\n __createBinding,\n __exportStar,\n __values,\n __read,\n __spread,\n __spreadArrays,\n __spreadArray,\n __await,\n __asyncGenerator,\n __asyncDelegator,\n __asyncValues,\n __makeTemplateObject,\n __importStar,\n __importDefault,\n __classPrivateFieldGet,\n __classPrivateFieldSet,\n __classPrivateFieldIn,\n __addDisposableResource,\n __disposeResources,\n};\n", "/**\n * Returns true if the object is a function.\n * @param value The value to check\n */\nexport function isFunction(value: any): value is (...args: any[]) => any {\n return typeof value === 'function';\n}\n", "/**\n * Used to create Error subclasses until the community moves away from ES5.\n *\n * This is because compiling from TypeScript down to ES5 has issues with subclassing Errors\n * as well as other built-in types: https://github.com/Microsoft/TypeScript/issues/12123\n *\n * @param createImpl A factory function to create the actual constructor implementation. The returned\n * function should be a named function that calls `_super` internally.\n */\nexport function createErrorClass(createImpl: (_super: any) => any): T {\n const _super = (instance: any) => {\n Error.call(instance);\n instance.stack = new Error().stack;\n };\n\n const ctorFunc = createImpl(_super);\n ctorFunc.prototype = Object.create(Error.prototype);\n ctorFunc.prototype.constructor = ctorFunc;\n return ctorFunc;\n}\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface UnsubscriptionError extends Error {\n readonly errors: any[];\n}\n\nexport interface UnsubscriptionErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (errors: any[]): UnsubscriptionError;\n}\n\n/**\n * An error thrown when one or more errors have occurred during the\n * `unsubscribe` of a {@link Subscription}.\n */\nexport const UnsubscriptionError: UnsubscriptionErrorCtor = createErrorClass(\n (_super) =>\n function UnsubscriptionErrorImpl(this: any, errors: (Error | string)[]) {\n _super(this);\n this.message = errors\n ? `${errors.length} errors occurred during unsubscription:\n${errors.map((err, i) => `${i + 1}) ${err.toString()}`).join('\\n ')}`\n : '';\n this.name = 'UnsubscriptionError';\n this.errors = errors;\n }\n);\n", "/**\n * Removes an item from an array, mutating it.\n * @param arr The array to remove the item from\n * @param item The item to remove\n */\nexport function arrRemove(arr: T[] | undefined | null, item: T) {\n if (arr) {\n const index = arr.indexOf(item);\n 0 <= index && arr.splice(index, 1);\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { UnsubscriptionError } from './util/UnsubscriptionError';\nimport { SubscriptionLike, TeardownLogic, Unsubscribable } from './types';\nimport { arrRemove } from './util/arrRemove';\n\n/**\n * Represents a disposable resource, such as the execution of an Observable. A\n * Subscription has one important method, `unsubscribe`, that takes no argument\n * and just disposes the resource held by the subscription.\n *\n * Additionally, subscriptions may be grouped together through the `add()`\n * method, which will attach a child Subscription to the current Subscription.\n * When a Subscription is unsubscribed, all its children (and its grandchildren)\n * will be unsubscribed as well.\n */\nexport class Subscription implements SubscriptionLike {\n public static EMPTY = (() => {\n const empty = new Subscription();\n empty.closed = true;\n return empty;\n })();\n\n /**\n * A flag to indicate whether this Subscription has already been unsubscribed.\n */\n public closed = false;\n\n private _parentage: Subscription[] | Subscription | null = null;\n\n /**\n * The list of registered finalizers to execute upon unsubscription. Adding and removing from this\n * list occurs in the {@link #add} and {@link #remove} methods.\n */\n private _finalizers: Exclude[] | null = null;\n\n /**\n * @param initialTeardown A function executed first as part of the finalization\n * process that is kicked off when {@link #unsubscribe} is called.\n */\n constructor(private initialTeardown?: () => void) {}\n\n /**\n * Disposes the resources held by the subscription. May, for instance, cancel\n * an ongoing Observable execution or cancel any other type of work that\n * started when the Subscription was created.\n */\n unsubscribe(): void {\n let errors: any[] | undefined;\n\n if (!this.closed) {\n this.closed = true;\n\n // Remove this from it's parents.\n const { _parentage } = this;\n if (_parentage) {\n this._parentage = null;\n if (Array.isArray(_parentage)) {\n for (const parent of _parentage) {\n parent.remove(this);\n }\n } else {\n _parentage.remove(this);\n }\n }\n\n const { initialTeardown: initialFinalizer } = this;\n if (isFunction(initialFinalizer)) {\n try {\n initialFinalizer();\n } catch (e) {\n errors = e instanceof UnsubscriptionError ? e.errors : [e];\n }\n }\n\n const { _finalizers } = this;\n if (_finalizers) {\n this._finalizers = null;\n for (const finalizer of _finalizers) {\n try {\n execFinalizer(finalizer);\n } catch (err) {\n errors = errors ?? [];\n if (err instanceof UnsubscriptionError) {\n errors = [...errors, ...err.errors];\n } else {\n errors.push(err);\n }\n }\n }\n }\n\n if (errors) {\n throw new UnsubscriptionError(errors);\n }\n }\n }\n\n /**\n * Adds a finalizer to this subscription, so that finalization will be unsubscribed/called\n * when this subscription is unsubscribed. If this subscription is already {@link #closed},\n * because it has already been unsubscribed, then whatever finalizer is passed to it\n * will automatically be executed (unless the finalizer itself is also a closed subscription).\n *\n * Closed Subscriptions cannot be added as finalizers to any subscription. Adding a closed\n * subscription to a any subscription will result in no operation. (A noop).\n *\n * Adding a subscription to itself, or adding `null` or `undefined` will not perform any\n * operation at all. (A noop).\n *\n * `Subscription` instances that are added to this instance will automatically remove themselves\n * if they are unsubscribed. Functions and {@link Unsubscribable} objects that you wish to remove\n * will need to be removed manually with {@link #remove}\n *\n * @param teardown The finalization logic to add to this subscription.\n */\n add(teardown: TeardownLogic): void {\n // Only add the finalizer if it's not undefined\n // and don't add a subscription to itself.\n if (teardown && teardown !== this) {\n if (this.closed) {\n // If this subscription is already closed,\n // execute whatever finalizer is handed to it automatically.\n execFinalizer(teardown);\n } else {\n if (teardown instanceof Subscription) {\n // We don't add closed subscriptions, and we don't add the same subscription\n // twice. Subscription unsubscribe is idempotent.\n if (teardown.closed || teardown._hasParent(this)) {\n return;\n }\n teardown._addParent(this);\n }\n (this._finalizers = this._finalizers ?? []).push(teardown);\n }\n }\n }\n\n /**\n * Checks to see if a this subscription already has a particular parent.\n * This will signal that this subscription has already been added to the parent in question.\n * @param parent the parent to check for\n */\n private _hasParent(parent: Subscription) {\n const { _parentage } = this;\n return _parentage === parent || (Array.isArray(_parentage) && _parentage.includes(parent));\n }\n\n /**\n * Adds a parent to this subscription so it can be removed from the parent if it\n * unsubscribes on it's own.\n *\n * NOTE: THIS ASSUMES THAT {@link _hasParent} HAS ALREADY BEEN CHECKED.\n * @param parent The parent subscription to add\n */\n private _addParent(parent: Subscription) {\n const { _parentage } = this;\n this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent;\n }\n\n /**\n * Called on a child when it is removed via {@link #remove}.\n * @param parent The parent to remove\n */\n private _removeParent(parent: Subscription) {\n const { _parentage } = this;\n if (_parentage === parent) {\n this._parentage = null;\n } else if (Array.isArray(_parentage)) {\n arrRemove(_parentage, parent);\n }\n }\n\n /**\n * Removes a finalizer from this subscription that was previously added with the {@link #add} method.\n *\n * Note that `Subscription` instances, when unsubscribed, will automatically remove themselves\n * from every other `Subscription` they have been added to. This means that using the `remove` method\n * is not a common thing and should be used thoughtfully.\n *\n * If you add the same finalizer instance of a function or an unsubscribable object to a `Subscription` instance\n * more than once, you will need to call `remove` the same number of times to remove all instances.\n *\n * All finalizer instances are removed to free up memory upon unsubscription.\n *\n * @param teardown The finalizer to remove from this subscription\n */\n remove(teardown: Exclude): void {\n const { _finalizers } = this;\n _finalizers && arrRemove(_finalizers, teardown);\n\n if (teardown instanceof Subscription) {\n teardown._removeParent(this);\n }\n }\n}\n\nexport const EMPTY_SUBSCRIPTION = Subscription.EMPTY;\n\nexport function isSubscription(value: any): value is Subscription {\n return (\n value instanceof Subscription ||\n (value && 'closed' in value && isFunction(value.remove) && isFunction(value.add) && isFunction(value.unsubscribe))\n );\n}\n\nfunction execFinalizer(finalizer: Unsubscribable | (() => void)) {\n if (isFunction(finalizer)) {\n finalizer();\n } else {\n finalizer.unsubscribe();\n }\n}\n", "import { Subscriber } from './Subscriber';\nimport { ObservableNotification } from './types';\n\n/**\n * The {@link GlobalConfig} object for RxJS. It is used to configure things\n * like how to react on unhandled errors.\n */\nexport const config: GlobalConfig = {\n onUnhandledError: null,\n onStoppedNotification: null,\n Promise: undefined,\n useDeprecatedSynchronousErrorHandling: false,\n useDeprecatedNextContext: false,\n};\n\n/**\n * The global configuration object for RxJS, used to configure things\n * like how to react on unhandled errors. Accessible via {@link config}\n * object.\n */\nexport interface GlobalConfig {\n /**\n * A registration point for unhandled errors from RxJS. These are errors that\n * cannot were not handled by consuming code in the usual subscription path. For\n * example, if you have this configured, and you subscribe to an observable without\n * providing an error handler, errors from that subscription will end up here. This\n * will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onUnhandledError: ((err: any) => void) | null;\n\n /**\n * A registration point for notifications that cannot be sent to subscribers because they\n * have completed, errored or have been explicitly unsubscribed. By default, next, complete\n * and error notifications sent to stopped subscribers are noops. However, sometimes callers\n * might want a different behavior. For example, with sources that attempt to report errors\n * to stopped subscribers, a caller can configure RxJS to throw an unhandled error instead.\n * This will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onStoppedNotification: ((notification: ObservableNotification, subscriber: Subscriber) => void) | null;\n\n /**\n * The promise constructor used by default for {@link Observable#toPromise toPromise} and {@link Observable#forEach forEach}\n * methods.\n *\n * @deprecated As of version 8, RxJS will no longer support this sort of injection of a\n * Promise constructor. If you need a Promise implementation other than native promises,\n * please polyfill/patch Promise as you see appropriate. Will be removed in v8.\n */\n Promise?: PromiseConstructorLike;\n\n /**\n * If true, turns on synchronous error rethrowing, which is a deprecated behavior\n * in v6 and higher. This behavior enables bad patterns like wrapping a subscribe\n * call in a try/catch block. It also enables producer interference, a nasty bug\n * where a multicast can be broken for all observers by a downstream consumer with\n * an unhandled error. DO NOT USE THIS FLAG UNLESS IT'S NEEDED TO BUY TIME\n * FOR MIGRATION REASONS.\n *\n * @deprecated As of version 8, RxJS will no longer support synchronous throwing\n * of unhandled errors. All errors will be thrown on a separate call stack to prevent bad\n * behaviors described above. Will be removed in v8.\n */\n useDeprecatedSynchronousErrorHandling: boolean;\n\n /**\n * If true, enables an as-of-yet undocumented feature from v5: The ability to access\n * `unsubscribe()` via `this` context in `next` functions created in observers passed\n * to `subscribe`.\n *\n * This is being removed because the performance was severely problematic, and it could also cause\n * issues when types other than POJOs are passed to subscribe as subscribers, as they will likely have\n * their `this` context overwritten.\n *\n * @deprecated As of version 8, RxJS will no longer support altering the\n * context of next functions provided as part of an observer to Subscribe. Instead,\n * you will have access to a subscription or a signal or token that will allow you to do things like\n * unsubscribe and test closed status. Will be removed in v8.\n */\n useDeprecatedNextContext: boolean;\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetTimeoutFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearTimeoutFunction = (handle: TimerHandle) => void;\n\ninterface TimeoutProvider {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n delegate:\n | {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n }\n | undefined;\n}\n\nexport const timeoutProvider: TimeoutProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setTimeout(handler: () => void, timeout?: number, ...args) {\n const { delegate } = timeoutProvider;\n if (delegate?.setTimeout) {\n return delegate.setTimeout(handler, timeout, ...args);\n }\n return setTimeout(handler, timeout, ...args);\n },\n clearTimeout(handle) {\n const { delegate } = timeoutProvider;\n return (delegate?.clearTimeout || clearTimeout)(handle as any);\n },\n delegate: undefined,\n};\n", "import { config } from '../config';\nimport { timeoutProvider } from '../scheduler/timeoutProvider';\n\n/**\n * Handles an error on another job either with the user-configured {@link onUnhandledError},\n * or by throwing it on that new job so it can be picked up by `window.onerror`, `process.on('error')`, etc.\n *\n * This should be called whenever there is an error that is out-of-band with the subscription\n * or when an error hits a terminal boundary of the subscription and no error handler was provided.\n *\n * @param err the error to report\n */\nexport function reportUnhandledError(err: any) {\n timeoutProvider.setTimeout(() => {\n const { onUnhandledError } = config;\n if (onUnhandledError) {\n // Execute the user-configured error handler.\n onUnhandledError(err);\n } else {\n // Throw so it is picked up by the runtime's uncaught error mechanism.\n throw err;\n }\n });\n}\n", "/* tslint:disable:no-empty */\nexport function noop() { }\n", "import { CompleteNotification, NextNotification, ErrorNotification } from './types';\n\n/**\n * A completion object optimized for memory use and created to be the\n * same \"shape\" as other notifications in v8.\n * @internal\n */\nexport const COMPLETE_NOTIFICATION = (() => createNotification('C', undefined, undefined) as CompleteNotification)();\n\n/**\n * Internal use only. Creates an optimized error notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function errorNotification(error: any): ErrorNotification {\n return createNotification('E', undefined, error) as any;\n}\n\n/**\n * Internal use only. Creates an optimized next notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function nextNotification(value: T) {\n return createNotification('N', value, undefined) as NextNotification;\n}\n\n/**\n * Ensures that all notifications created internally have the same \"shape\" in v8.\n *\n * TODO: This is only exported to support a crazy legacy test in `groupBy`.\n * @internal\n */\nexport function createNotification(kind: 'N' | 'E' | 'C', value: any, error: any) {\n return {\n kind,\n value,\n error,\n };\n}\n", "import { config } from '../config';\n\nlet context: { errorThrown: boolean; error: any } | null = null;\n\n/**\n * Handles dealing with errors for super-gross mode. Creates a context, in which\n * any synchronously thrown errors will be passed to {@link captureError}. Which\n * will record the error such that it will be rethrown after the call back is complete.\n * TODO: Remove in v8\n * @param cb An immediately executed function.\n */\nexport function errorContext(cb: () => void) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n const isRoot = !context;\n if (isRoot) {\n context = { errorThrown: false, error: null };\n }\n cb();\n if (isRoot) {\n const { errorThrown, error } = context!;\n context = null;\n if (errorThrown) {\n throw error;\n }\n }\n } else {\n // This is the general non-deprecated path for everyone that\n // isn't crazy enough to use super-gross mode (useDeprecatedSynchronousErrorHandling)\n cb();\n }\n}\n\n/**\n * Captures errors only in super-gross mode.\n * @param err the error to capture\n */\nexport function captureError(err: any) {\n if (config.useDeprecatedSynchronousErrorHandling && context) {\n context.errorThrown = true;\n context.error = err;\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { Observer, ObservableNotification } from './types';\nimport { isSubscription, Subscription } from './Subscription';\nimport { config } from './config';\nimport { reportUnhandledError } from './util/reportUnhandledError';\nimport { noop } from './util/noop';\nimport { nextNotification, errorNotification, COMPLETE_NOTIFICATION } from './NotificationFactories';\nimport { timeoutProvider } from './scheduler/timeoutProvider';\nimport { captureError } from './util/errorContext';\n\n/**\n * Implements the {@link Observer} interface and extends the\n * {@link Subscription} class. While the {@link Observer} is the public API for\n * consuming the values of an {@link Observable}, all Observers get converted to\n * a Subscriber, in order to provide Subscription-like capabilities such as\n * `unsubscribe`. Subscriber is a common type in RxJS, and crucial for\n * implementing operators, but it is rarely used as a public API.\n */\nexport class Subscriber extends Subscription implements Observer {\n /**\n * A static factory for a Subscriber, given a (potentially partial) definition\n * of an Observer.\n * @param next The `next` callback of an Observer.\n * @param error The `error` callback of an\n * Observer.\n * @param complete The `complete` callback of an\n * Observer.\n * @return A Subscriber wrapping the (partially defined)\n * Observer represented by the given arguments.\n * @deprecated Do not use. Will be removed in v8. There is no replacement for this\n * method, and there is no reason to be creating instances of `Subscriber` directly.\n * If you have a specific use case, please file an issue.\n */\n static create(next?: (x?: T) => void, error?: (e?: any) => void, complete?: () => void): Subscriber {\n return new SafeSubscriber(next, error, complete);\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected isStopped: boolean = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected destination: Subscriber | Observer; // this `any` is the escape hatch to erase extra type param (e.g. R)\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * There is no reason to directly create an instance of Subscriber. This type is exported for typings reasons.\n */\n constructor(destination?: Subscriber | Observer) {\n super();\n if (destination) {\n this.destination = destination;\n // Automatically chain subscriptions together here.\n // if destination is a Subscription, then it is a Subscriber.\n if (isSubscription(destination)) {\n destination.add(this);\n }\n } else {\n this.destination = EMPTY_OBSERVER;\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `next` from\n * the Observable, with a value. The Observable may call this method 0 or more\n * times.\n * @param value The `next` value.\n */\n next(value: T): void {\n if (this.isStopped) {\n handleStoppedNotification(nextNotification(value), this);\n } else {\n this._next(value!);\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `error` from\n * the Observable, with an attached `Error`. Notifies the Observer that\n * the Observable has experienced an error condition.\n * @param err The `error` exception.\n */\n error(err?: any): void {\n if (this.isStopped) {\n handleStoppedNotification(errorNotification(err), this);\n } else {\n this.isStopped = true;\n this._error(err);\n }\n }\n\n /**\n * The {@link Observer} callback to receive a valueless notification of type\n * `complete` from the Observable. Notifies the Observer that the Observable\n * has finished sending push-based notifications.\n */\n complete(): void {\n if (this.isStopped) {\n handleStoppedNotification(COMPLETE_NOTIFICATION, this);\n } else {\n this.isStopped = true;\n this._complete();\n }\n }\n\n unsubscribe(): void {\n if (!this.closed) {\n this.isStopped = true;\n super.unsubscribe();\n this.destination = null!;\n }\n }\n\n protected _next(value: T): void {\n this.destination.next(value);\n }\n\n protected _error(err: any): void {\n try {\n this.destination.error(err);\n } finally {\n this.unsubscribe();\n }\n }\n\n protected _complete(): void {\n try {\n this.destination.complete();\n } finally {\n this.unsubscribe();\n }\n }\n}\n\n/**\n * This bind is captured here because we want to be able to have\n * compatibility with monoid libraries that tend to use a method named\n * `bind`. In particular, a library called Monio requires this.\n */\nconst _bind = Function.prototype.bind;\n\nfunction bind any>(fn: Fn, thisArg: any): Fn {\n return _bind.call(fn, thisArg);\n}\n\n/**\n * Internal optimization only, DO NOT EXPOSE.\n * @internal\n */\nclass ConsumerObserver implements Observer {\n constructor(private partialObserver: Partial>) {}\n\n next(value: T): void {\n const { partialObserver } = this;\n if (partialObserver.next) {\n try {\n partialObserver.next(value);\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n\n error(err: any): void {\n const { partialObserver } = this;\n if (partialObserver.error) {\n try {\n partialObserver.error(err);\n } catch (error) {\n handleUnhandledError(error);\n }\n } else {\n handleUnhandledError(err);\n }\n }\n\n complete(): void {\n const { partialObserver } = this;\n if (partialObserver.complete) {\n try {\n partialObserver.complete();\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n}\n\nexport class SafeSubscriber extends Subscriber {\n constructor(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((e?: any) => void) | null,\n complete?: (() => void) | null\n ) {\n super();\n\n let partialObserver: Partial>;\n if (isFunction(observerOrNext) || !observerOrNext) {\n // The first argument is a function, not an observer. The next\n // two arguments *could* be observers, or they could be empty.\n partialObserver = {\n next: (observerOrNext ?? undefined) as ((value: T) => void) | undefined,\n error: error ?? undefined,\n complete: complete ?? undefined,\n };\n } else {\n // The first argument is a partial observer.\n let context: any;\n if (this && config.useDeprecatedNextContext) {\n // This is a deprecated path that made `this.unsubscribe()` available in\n // next handler functions passed to subscribe. This only exists behind a flag\n // now, as it is *very* slow.\n context = Object.create(observerOrNext);\n context.unsubscribe = () => this.unsubscribe();\n partialObserver = {\n next: observerOrNext.next && bind(observerOrNext.next, context),\n error: observerOrNext.error && bind(observerOrNext.error, context),\n complete: observerOrNext.complete && bind(observerOrNext.complete, context),\n };\n } else {\n // The \"normal\" path. Just use the partial observer directly.\n partialObserver = observerOrNext;\n }\n }\n\n // Wrap the partial observer to ensure it's a full observer, and\n // make sure proper error handling is accounted for.\n this.destination = new ConsumerObserver(partialObserver);\n }\n}\n\nfunction handleUnhandledError(error: any) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n captureError(error);\n } else {\n // Ideal path, we report this as an unhandled error,\n // which is thrown on a new call stack.\n reportUnhandledError(error);\n }\n}\n\n/**\n * An error handler used when no error handler was supplied\n * to the SafeSubscriber -- meaning no error handler was supplied\n * do the `subscribe` call on our observable.\n * @param err The error to handle\n */\nfunction defaultErrorHandler(err: any) {\n throw err;\n}\n\n/**\n * A handler for notifications that cannot be sent to a stopped subscriber.\n * @param notification The notification being sent.\n * @param subscriber The stopped subscriber.\n */\nfunction handleStoppedNotification(notification: ObservableNotification, subscriber: Subscriber) {\n const { onStoppedNotification } = config;\n onStoppedNotification && timeoutProvider.setTimeout(() => onStoppedNotification(notification, subscriber));\n}\n\n/**\n * The observer used as a stub for subscriptions where the user did not\n * pass any arguments to `subscribe`. Comes with the default error handling\n * behavior.\n */\nexport const EMPTY_OBSERVER: Readonly> & { closed: true } = {\n closed: true,\n next: noop,\n error: defaultErrorHandler,\n complete: noop,\n};\n", "/**\n * Symbol.observable or a string \"@@observable\". Used for interop\n *\n * @deprecated We will no longer be exporting this symbol in upcoming versions of RxJS.\n * Instead polyfill and use Symbol.observable directly *or* use https://www.npmjs.com/package/symbol-observable\n */\nexport const observable: string | symbol = (() => (typeof Symbol === 'function' && Symbol.observable) || '@@observable')();\n", "/**\n * This function takes one parameter and just returns it. Simply put,\n * this is like `(x: T): T => x`.\n *\n * ## Examples\n *\n * This is useful in some cases when using things like `mergeMap`\n *\n * ```ts\n * import { interval, take, map, range, mergeMap, identity } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(5));\n *\n * const result$ = source$.pipe(\n * map(i => range(i)),\n * mergeMap(identity) // same as mergeMap(x => x)\n * );\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * Or when you want to selectively apply an operator\n *\n * ```ts\n * import { interval, take, identity } from 'rxjs';\n *\n * const shouldLimit = () => Math.random() < 0.5;\n *\n * const source$ = interval(1000);\n *\n * const result$ = source$.pipe(shouldLimit() ? take(5) : identity);\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * @param x Any value that is returned by this function\n * @returns The value passed as the first parameter to this function\n */\nexport function identity(x: T): T {\n return x;\n}\n", "import { identity } from './identity';\nimport { UnaryFunction } from '../types';\n\nexport function pipe(): typeof identity;\nexport function pipe(fn1: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction,\n ...fns: UnaryFunction[]\n): UnaryFunction;\n\n/**\n * pipe() can be called on one or more functions, each of which can take one argument (\"UnaryFunction\")\n * and uses it to return a value.\n * It returns a function that takes one argument, passes it to the first UnaryFunction, and then\n * passes the result to the next one, passes that result to the next one, and so on. \n */\nexport function pipe(...fns: Array>): UnaryFunction {\n return pipeFromArray(fns);\n}\n\n/** @internal */\nexport function pipeFromArray(fns: Array>): UnaryFunction {\n if (fns.length === 0) {\n return identity as UnaryFunction;\n }\n\n if (fns.length === 1) {\n return fns[0];\n }\n\n return function piped(input: T): R {\n return fns.reduce((prev: any, fn: UnaryFunction) => fn(prev), input as any);\n };\n}\n", "import { Operator } from './Operator';\nimport { SafeSubscriber, Subscriber } from './Subscriber';\nimport { isSubscription, Subscription } from './Subscription';\nimport { TeardownLogic, OperatorFunction, Subscribable, Observer } from './types';\nimport { observable as Symbol_observable } from './symbol/observable';\nimport { pipeFromArray } from './util/pipe';\nimport { config } from './config';\nimport { isFunction } from './util/isFunction';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A representation of any set of values over any amount of time. This is the most basic building block\n * of RxJS.\n */\nexport class Observable implements Subscribable {\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n source: Observable | undefined;\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n operator: Operator | undefined;\n\n /**\n * @param subscribe The function that is called when the Observable is\n * initially subscribed to. This function is given a Subscriber, to which new values\n * can be `next`ed, or an `error` method can be called to raise an error, or\n * `complete` can be called to notify of a successful completion.\n */\n constructor(subscribe?: (this: Observable, subscriber: Subscriber) => TeardownLogic) {\n if (subscribe) {\n this._subscribe = subscribe;\n }\n }\n\n // HACK: Since TypeScript inherits static properties too, we have to\n // fight against TypeScript here so Subject can have a different static create signature\n /**\n * Creates a new Observable by calling the Observable constructor\n * @param subscribe the subscriber function to be passed to the Observable constructor\n * @return A new observable.\n * @deprecated Use `new Observable()` instead. Will be removed in v8.\n */\n static create: (...args: any[]) => any = (subscribe?: (subscriber: Subscriber) => TeardownLogic) => {\n return new Observable(subscribe);\n };\n\n /**\n * Creates a new Observable, with this Observable instance as the source, and the passed\n * operator defined as the new observable's operator.\n * @param operator the operator defining the operation to take on the observable\n * @return A new observable with the Operator applied.\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * If you have implemented an operator using `lift`, it is recommended that you create an\n * operator by simply returning `new Observable()` directly. See \"Creating new operators from\n * scratch\" section here: https://rxjs.dev/guide/operators\n */\n lift(operator?: Operator): Observable {\n const observable = new Observable();\n observable.source = this;\n observable.operator = operator;\n return observable;\n }\n\n subscribe(observerOrNext?: Partial> | ((value: T) => void)): Subscription;\n /** @deprecated Instead of passing separate callback arguments, use an observer argument. Signatures taking separate callback arguments will be removed in v8. Details: https://rxjs.dev/deprecations/subscribe-arguments */\n subscribe(next?: ((value: T) => void) | null, error?: ((error: any) => void) | null, complete?: (() => void) | null): Subscription;\n /**\n * Invokes an execution of an Observable and registers Observer handlers for notifications it will emit.\n *\n * Use it when you have all these Observables, but still nothing is happening.\n *\n * `subscribe` is not a regular operator, but a method that calls Observable's internal `subscribe` function. It\n * might be for example a function that you passed to Observable's constructor, but most of the time it is\n * a library implementation, which defines what will be emitted by an Observable, and when it be will emitted. This means\n * that calling `subscribe` is actually the moment when Observable starts its work, not when it is created, as it is often\n * the thought.\n *\n * Apart from starting the execution of an Observable, this method allows you to listen for values\n * that an Observable emits, as well as for when it completes or errors. You can achieve this in two\n * of the following ways.\n *\n * The first way is creating an object that implements {@link Observer} interface. It should have methods\n * defined by that interface, but note that it should be just a regular JavaScript object, which you can create\n * yourself in any way you want (ES6 class, classic function constructor, object literal etc.). In particular, do\n * not attempt to use any RxJS implementation details to create Observers - you don't need them. Remember also\n * that your object does not have to implement all methods. If you find yourself creating a method that doesn't\n * do anything, you can simply omit it. Note however, if the `error` method is not provided and an error happens,\n * it will be thrown asynchronously. Errors thrown asynchronously cannot be caught using `try`/`catch`. Instead,\n * use the {@link onUnhandledError} configuration option or use a runtime handler (like `window.onerror` or\n * `process.on('error)`) to be notified of unhandled errors. Because of this, it's recommended that you provide\n * an `error` method to avoid missing thrown errors.\n *\n * The second way is to give up on Observer object altogether and simply provide callback functions in place of its methods.\n * This means you can provide three functions as arguments to `subscribe`, where the first function is equivalent\n * of a `next` method, the second of an `error` method and the third of a `complete` method. Just as in case of an Observer,\n * if you do not need to listen for something, you can omit a function by passing `undefined` or `null`,\n * since `subscribe` recognizes these functions by where they were placed in function call. When it comes\n * to the `error` function, as with an Observer, if not provided, errors emitted by an Observable will be thrown asynchronously.\n *\n * You can, however, subscribe with no parameters at all. This may be the case where you're not interested in terminal events\n * and you also handled emissions internally by using operators (e.g. using `tap`).\n *\n * Whichever style of calling `subscribe` you use, in both cases it returns a Subscription object.\n * This object allows you to call `unsubscribe` on it, which in turn will stop the work that an Observable does and will clean\n * up all resources that an Observable used. Note that cancelling a subscription will not call `complete` callback\n * provided to `subscribe` function, which is reserved for a regular completion signal that comes from an Observable.\n *\n * Remember that callbacks provided to `subscribe` are not guaranteed to be called asynchronously.\n * It is an Observable itself that decides when these functions will be called. For example {@link of}\n * by default emits all its values synchronously. Always check documentation for how given Observable\n * will behave when subscribed and if its default behavior can be modified with a `scheduler`.\n *\n * #### Examples\n *\n * Subscribe with an {@link guide/observer Observer}\n *\n * ```ts\n * import { of } from 'rxjs';\n *\n * const sumObserver = {\n * sum: 0,\n * next(value) {\n * console.log('Adding: ' + value);\n * this.sum = this.sum + value;\n * },\n * error() {\n * // We actually could just remove this method,\n * // since we do not really care about errors right now.\n * },\n * complete() {\n * console.log('Sum equals: ' + this.sum);\n * }\n * };\n *\n * of(1, 2, 3) // Synchronously emits 1, 2, 3 and then completes.\n * .subscribe(sumObserver);\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Subscribe with functions ({@link deprecations/subscribe-arguments deprecated})\n *\n * ```ts\n * import { of } from 'rxjs'\n *\n * let sum = 0;\n *\n * of(1, 2, 3).subscribe(\n * value => {\n * console.log('Adding: ' + value);\n * sum = sum + value;\n * },\n * undefined,\n * () => console.log('Sum equals: ' + sum)\n * );\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Cancel a subscription\n *\n * ```ts\n * import { interval } from 'rxjs';\n *\n * const subscription = interval(1000).subscribe({\n * next(num) {\n * console.log(num)\n * },\n * complete() {\n * // Will not be called, even when cancelling subscription.\n * console.log('completed!');\n * }\n * });\n *\n * setTimeout(() => {\n * subscription.unsubscribe();\n * console.log('unsubscribed!');\n * }, 2500);\n *\n * // Logs:\n * // 0 after 1s\n * // 1 after 2s\n * // 'unsubscribed!' after 2.5s\n * ```\n *\n * @param observerOrNext Either an {@link Observer} with some or all callback methods,\n * or the `next` handler that is called for each value emitted from the subscribed Observable.\n * @param error A handler for a terminal event resulting from an error. If no error handler is provided,\n * the error will be thrown asynchronously as unhandled.\n * @param complete A handler for a terminal event resulting from successful completion.\n * @return A subscription reference to the registered handlers.\n */\n subscribe(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((error: any) => void) | null,\n complete?: (() => void) | null\n ): Subscription {\n const subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);\n\n errorContext(() => {\n const { operator, source } = this;\n subscriber.add(\n operator\n ? // We're dealing with a subscription in the\n // operator chain to one of our lifted operators.\n operator.call(subscriber, source)\n : source\n ? // If `source` has a value, but `operator` does not, something that\n // had intimate knowledge of our API, like our `Subject`, must have\n // set it. We're going to just call `_subscribe` directly.\n this._subscribe(subscriber)\n : // In all other cases, we're likely wrapping a user-provided initializer\n // function, so we need to catch errors and handle them appropriately.\n this._trySubscribe(subscriber)\n );\n });\n\n return subscriber;\n }\n\n /** @internal */\n protected _trySubscribe(sink: Subscriber): TeardownLogic {\n try {\n return this._subscribe(sink);\n } catch (err) {\n // We don't need to return anything in this case,\n // because it's just going to try to `add()` to a subscription\n // above.\n sink.error(err);\n }\n }\n\n /**\n * Used as a NON-CANCELLABLE means of subscribing to an observable, for use with\n * APIs that expect promises, like `async/await`. You cannot unsubscribe from this.\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * #### Example\n *\n * ```ts\n * import { interval, take } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(4));\n *\n * async function getTotal() {\n * let total = 0;\n *\n * await source$.forEach(value => {\n * total += value;\n * console.log('observable -> ' + value);\n * });\n *\n * return total;\n * }\n *\n * getTotal().then(\n * total => console.log('Total: ' + total)\n * );\n *\n * // Expected:\n * // 'observable -> 0'\n * // 'observable -> 1'\n * // 'observable -> 2'\n * // 'observable -> 3'\n * // 'Total: 6'\n * ```\n *\n * @param next A handler for each value emitted by the observable.\n * @return A promise that either resolves on observable completion or\n * rejects with the handled error.\n */\n forEach(next: (value: T) => void): Promise;\n\n /**\n * @param next a handler for each value emitted by the observable\n * @param promiseCtor a constructor function used to instantiate the Promise\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n * @deprecated Passing a Promise constructor will no longer be available\n * in upcoming versions of RxJS. This is because it adds weight to the library, for very\n * little benefit. If you need this functionality, it is recommended that you either\n * polyfill Promise, or you create an adapter to convert the returned native promise\n * to whatever promise implementation you wanted. Will be removed in v8.\n */\n forEach(next: (value: T) => void, promiseCtor: PromiseConstructorLike): Promise;\n\n forEach(next: (value: T) => void, promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n const subscriber = new SafeSubscriber({\n next: (value) => {\n try {\n next(value);\n } catch (err) {\n reject(err);\n subscriber.unsubscribe();\n }\n },\n error: reject,\n complete: resolve,\n });\n this.subscribe(subscriber);\n }) as Promise;\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): TeardownLogic {\n return this.source?.subscribe(subscriber);\n }\n\n /**\n * An interop point defined by the es7-observable spec https://github.com/zenparsing/es-observable\n * @return This instance of the observable.\n */\n [Symbol_observable]() {\n return this;\n }\n\n /* tslint:disable:max-line-length */\n pipe(): Observable;\n pipe(op1: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction,\n ...operations: OperatorFunction[]\n ): Observable;\n /* tslint:enable:max-line-length */\n\n /**\n * Used to stitch together functional operators into a chain.\n *\n * ## Example\n *\n * ```ts\n * import { interval, filter, map, scan } from 'rxjs';\n *\n * interval(1000)\n * .pipe(\n * filter(x => x % 2 === 0),\n * map(x => x + x),\n * scan((acc, x) => acc + x)\n * )\n * .subscribe(x => console.log(x));\n * ```\n *\n * @return The Observable result of all the operators having been called\n * in the order they were passed in.\n */\n pipe(...operations: OperatorFunction[]): Observable {\n return pipeFromArray(operations)(this);\n }\n\n /* tslint:disable:max-line-length */\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: typeof Promise): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: PromiseConstructorLike): Promise;\n /* tslint:enable:max-line-length */\n\n /**\n * Subscribe to this Observable and get a Promise resolving on\n * `complete` with the last emission (if any).\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * @param [promiseCtor] a constructor function used to instantiate\n * the Promise\n * @return A Promise that resolves with the last value emit, or\n * rejects on an error. If there were no emissions, Promise\n * resolves with undefined.\n * @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise\n */\n toPromise(promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n let value: T | undefined;\n this.subscribe(\n (x: T) => (value = x),\n (err: any) => reject(err),\n () => resolve(value)\n );\n }) as Promise;\n }\n}\n\n/**\n * Decides between a passed promise constructor from consuming code,\n * A default configured promise constructor, and the native promise\n * constructor and returns it. If nothing can be found, it will throw\n * an error.\n * @param promiseCtor The optional promise constructor to passed by consuming code\n */\nfunction getPromiseCtor(promiseCtor: PromiseConstructorLike | undefined) {\n return promiseCtor ?? config.Promise ?? Promise;\n}\n\nfunction isObserver