diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..e54afc6a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +version: 2 +updates: +- package-ecosystem: npm + directory: "/" + schedule: + interval: weekly + +- package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000..85777734 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,53 @@ +name: Deploy Hexo + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Check Out + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: pnpm/action-setup@v3 + with: + version: latest + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "pnpm" + + - name: Install Dependencies + run: | + pnpm install + + # https://github.com/zhullyb/zhullyb.github.io/blob/master/.github/workflows/deploy.yml + # 修复 hexo 生成的文件更新时间 为当前时间,实际应为提交时间 + - name: Fix File Updated Date + run: | + git ls-files "*.md" | while read filepath; do touch -d "$(git log -1 --format='@%ct' $filepath)" "$filepath" && echo "Fixed: $filepath"; done + + - name: Build Site + run: | + pnpm build + + - name: Move baidu_verify + run: | + cp asset/baidu_verify_codeva-GwRsL4VPtx.html.html public/ + cp asset/naver57322dd0ed14599dd3052c79c6892766.html public/ + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: public + force_orphan: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..40998f80 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +Thumbs.db +db.json +*.log +node_modules/ +public/ +.deploy*/ +_multiconfig.yml +.vscode/ +.idea/ diff --git a/LICENSE-APACHE-2.0 b/LICENSE-APACHE-2.0 new file mode 100644 index 00000000..7dc91c9a --- /dev/null +++ b/LICENSE-APACHE-2.0 @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2024 [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/LICENSE-CC-BY-4.0 b/LICENSE-CC-BY-4.0 new file mode 100644 index 00000000..10fabd90 --- /dev/null +++ b/LICENSE-CC-BY-4.0 @@ -0,0 +1,395 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public licenses. +Notwithstanding, Creative Commons may elect to apply one of its public +licenses to material it publishes and in those instances will be +considered the “Licensor.” The text of the Creative Commons public +licenses is dedicated to the public domain under the CC0 Public Domain +Dedication. Except for the limited purpose of indicating that material +is shared under a Creative Commons public license or as otherwise +permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the public +licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/README.md b/README.md new file mode 100644 index 00000000..55ff30a9 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +本仓库是我个人博客的源码,使用 `Hexo` 搭建,主题为 `Fluid`,欢迎访问我的博客:[漠北残月的博客](https://blog.ovvv.top) + +## 版权声明 +- 博客源代码采用 `APACHE 2.0` 许可证,请在遵循许可证的前提下使用代码。 +- 未经特殊说明,本博客的所有文章(source 目录下的 markdown 文件)均采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh-hans) 协议发布。**如果您转载或引用本站文章,请遵循协议,并注明作者和出处。** +- 本站文章中的部分代码、图片等资源来源于网络,版权归原作者所有,如有侵权,请联系我添加引用删除。 +- 本站使用的字体为 [LxgwWenKai](https://github.com/lxgw/LxgwWenKai),并遵循其开源协议。 diff --git a/_config.fluid.yml b/_config.fluid.yml new file mode 100644 index 00000000..5dbe3f36 --- /dev/null +++ b/_config.fluid.yml @@ -0,0 +1,1134 @@ +#--------------------------- +# Hexo Theme Fluid +# Author: Fluid-dev +# Github: https://github.com/fluid-dev/hexo-theme-fluid +# +# 配置指南: https://hexo.fluid-dev.com/docs/guide/ +# 你可以从指南中获得更详细的说明 +# +# Guide: https://hexo.fluid-dev.com/docs/en/guide/ +# You can get more detailed help from the guide +#--------------------------- + + +#--------------------------- +# 全局 +# Global +#--------------------------- + +# 用于浏览器标签的图标 +# Icon for browser tab +favicon: /images/favicon.jpg + +# 用于苹果设备的图标 +# Icon for Apple touch +apple_touch_icon: /images/favicon.jpg + +# 浏览器标签页中的标题分隔符,效果:文章名 - 站点名 +# Title separator in browser tab, eg: article - site +tab_title_separator: " - " + +# 强制所有链接升级为 HTTPS(适用于图片等资源出现 HTTP 混入报错) +# Force all links to be HTTPS (applicable to HTTP mixed error) +force_https: true + +# 代码块的增强配置 +# Enhancements to code blocks +code: + # 是否开启复制代码的按钮 + # Enable copy code button + copy_btn: true + + # 代码语言 + # Code language + language: + enable: true + default: "TEXT" + + # 代码高亮 + # Code highlight + highlight: + enable: true + + # 代码块是否显示行号 + # If true, the code block display line numbers + line_number: true + + # 实现高亮的库,对应下面的设置 + # Highlight library + # Options: highlightjs | prismjs + lib: "highlightjs" + + highlightjs: + # 在链接中挑选 style 填入 + # Select a style in the link + # See: https://highlightjs.org/static/demo/ + style: "github gist" + style_dark: "dark" + + prismjs: + # 在下方链接页面右侧的圆形按钮挑选 style 填入,也可以直接填入 css 链接 + # Select the style button on the right side of the link page, you can also set the CSS link + # See: https://prismjs.com/ + style: "default" + style_dark: "tomorrow night" + + # 设为 true 高亮将本地静态生成(但只支持部分 prismjs 插件),设为 false 高亮将在浏览器通过 js 生成 + # If true, it will be generated locally (but some prismjs plugins are not supported). If false, it will be generated via JS in the browser + preprocess: true + +# 一些好玩的功能 +# Some fun features +fun_features: + # 为 subtitle 添加打字机效果 + # Typing animation for subtitle + typing: + enable: true + + # 打印速度,数字越大越慢 + # Typing speed, the larger the number, the slower + typeSpeed: 70 + + # 游标字符 + # Cursor character + cursorChar: "_" + + # 是否循环播放效果 + # If true, loop animation + loop: false + + # 在指定页面开启,不填则在所有页面开启 + # Enable in specified page, all pages by default + # Options: home | post | tag | category | about | links | page | 404 + scope: [] + + # 为文章内容中的标题添加锚图标 + # Add an anchor icon to the title on the post page + anchorjs: + enable: true + element: h1,h2,h3,h4,h5,h6 + # Options: left | right + placement: left + # Options: hover | always | touch + visible: hover + # Options: § | # | ❡ + icon: "" + + # 加载进度条 + # Progress bar when loading + progressbar: + enable: true + height_px: 3 + color: "#29d" + # See: https://github.com/rstacruz/nprogress + options: { showSpinner: false, trickleSpeed: 100 } + +# 主题暗色模式,开启后菜单中会出现切换按钮,用户浏览器会存储切换选项,并且会遵循 prefers-color-scheme 自动切换 +# Theme dark mode. If enable, a switch button will appear on the menu, each of the visitor's browser will store his switch option +dark_mode: + enable: true + # 默认的选项(当用户手动切换后则不再按照默认模式),选择 `auto` 会优先遵循 prefers-color-scheme,其次按用户本地时间 18 点到次日 6 点之间进入暗色模式 + # Default option (when the visitor switches manually, the default mode is no longer followed), choosing `auto` will give priority to prefers-color-scheme, and then enter the dark mode from 18:00 to 6:00 in the visitor’s local time + # Options: auto | light | dark + default: auto + +# 主题颜色配置,其他不生效的地方请使用自定义 css 解决,配色可以在下方链接中获得启发 +# Theme color, please use custom CSS to solve other colors, color schema can be inspired by the links below +# See: https://www.webdesignrankings.com/resources/lolcolors/ +color: + # body 背景色 + # Color of body background + body_bg_color: "#eee" + # 暗色模式下的 body 背景色,下同 + # Color in dark mode, the same below + body_bg_color_dark: "#181c27" + + # 顶部菜单背景色 + # Color of navigation bar background + navbar_bg_color: "#2f4154" + navbar_bg_color_dark: "#1f3144" + + # 顶部菜单字体色 + # Color of navigation bar text + navbar_text_color: "#fff" + navbar_text_color_dark: "#d0d0d0" + + # 副标题字体色 + # Color of navigation bar text + subtitle_color: "#fff" + subtitle_color_dark: "#d0d0d0" + + # 全局字体色 + # Color of global text + text_color: "#3c4858" + text_color_dark: "#c4c6c9" + + # 全局次级字体色(摘要、简介等位置) + # Color of global secondary text (excerpt, introduction, etc.) + sec_text_color: "#718096" + sec_text_color_dark: "#a7a9ad" + + # 主面板背景色 + # Color of main board + board_color: "#fff" + board_color_dark: "#252d38" + + # 文章正文字体色 + # Color of post text + post_text_color: "#2c3e50" + post_text_color_dark: "#c4c6c9" + + # 文章正文字体色(h1 h2 h3...) + # Color of Article heading (h1 h2 h3...) + post_heading_color: "#1a202c" + post_heading_color_dark: "#c4c6c9" + + # 文章超链接字体色 + # Color of post link + post_link_color: "#0366d6" + post_link_color_dark: "#1589e9" + + # 超链接悬浮时字体色 + # Color of link when hovering + link_hover_color: "#30a9de" + link_hover_color_dark: "#30a9de" + + # 超链接悬浮背景色 + # Color of link background when hovering + link_hover_bg_color: "#f8f9fa" + link_hover_bg_color_dark: "#364151" + + # 分隔线和表格边线的颜色 + # Color of horizontal rule and table border + line_color: "#eaecef" + line_color_dark: "#435266" + + # 滚动条颜色 + # Color of scrollbar + scrollbar_color: "#c4c6c9" + scrollbar_color_dark: "#687582" + # 滚动条悬浮颜色 + # Color of scrollbar when hovering + scrollbar_hover_color: "#a6a6a6" + scrollbar_hover_color_dark: "#9da8b3" + + # 按钮背景色 + # Color of button + button_bg_color: "transparent" + button_bg_color_dark: "transparent" + # 按钮悬浮背景色 + # Color of button when hovering + button_hover_bg_color: "#f2f3f5" + button_hover_bg_color_dark: "#46647e" + +# 主题字体配置 +# Font +font: + font_size: 17px + font_family: "LXGW WenKai GB Screen" + letter_spacing: 0.02em + code_font_size: 85% + +# 指定自定义 .js 文件路径,支持列表;路径是相对 source 目录,如 /js/custom.js 对应存放目录 source/js/custom.js +# Specify the path of your custom js file, support list. The path is relative to the source directory, such as `/js/custom.js` corresponding to the directory `source/js/custom.js` +custom_js: + +# 指定自定义 .css 文件路径,用法和 custom_js 相同 +# The usage is the same as custom_js +custom_css: https://registry.npmmirror.com/lxgw-wenkai-screen-web/latest/files/lxgwwenkaigbscreen/result.min.css + +custom_head: '' + +# 网页访问统计 +# Analysis of website visitors +web_analytics: # 网页访问统计 + enable: false + + # 遵循访客浏览器"请勿追踪"的设置,如果开启则不统计其访问 + # Follow the "Do Not Track" setting of the visitor's browser + # See: https://www.w3.org/TR/tracking-dnt/ + follow_dnt: true + + # 百度统计的 Key,值需要获取下方链接中 `hm.js?` 后边的字符串 + # Baidu analytics, get the string behind `hm.js?` + # See: https://tongji.baidu.com/sc-web/10000033910/home/site/getjs?siteId=13751376 + baidu: + + # Google Analytics 4 的媒体资源 ID + # Google Analytics 4 MEASUREMENT_ID + # See: https://support.google.com/analytics/answer/9744165#zippy=%2Cin-this-article + google: + measurement_id: + + # 腾讯统计的 H5 App ID,开启高级功能才有 cid + # Tencent analytics, set APP ID + # See: https://mta.qq.com/h5/manage/ctr_app_manage + tencent: + sid: + cid: + + # 51.la 站点统计 ID + # 51.la analytics + # See: https://www.51.la/user/site/index + woyaola: # 51.la 站点统计 ID,参见 + + # 友盟/cnzz 站点统计 web_id + # cnzz analytics + # See: https://web.umeng.com/main.php?c=site&a=show + cnzz: + + # LeanCloud 计数统计,可用于 PV UV 展示,如果 `web_analytics: enable` 没有开启,PV UV 展示只会查询不会增加 + # LeanCloud count statistics, which can be used for PV UV display. If `web_analytics: enable` is false, PV UV display will only query and not increase + leancloud: + app_id: + app_key: + # REST API 服务器地址,国际版不填 + # Only the Chinese mainland users need to set + server_url: + # 统计页面时获取路径的属性 + # Get the attribute of the page path during statistics + path: window.location.pathname + # 开启后不统计本地路径 (localhost 与 127.0.0.1) + # If true, ignore localhost & 127.0.0.1 + ignore_local: false + +# 对页面中的图片和评论插件进行懒加载处理,可见范围外的元素不会提前加载 +# Lazy loading of images and comment plugin on the page +lazyload: + enable: true + + # 加载时的占位图片 + # The placeholder image when loading + loading_img: /img/loading.gif + + # 开启后懒加载仅在文章页生效,如果自定义页面需要使用,可以在 Front-matter 里指定 `lazyload: true` + # If true, only enable lazyload on the post page. For custom pages, you can set 'lazyload: true' in front-matter + onlypost: false + + # 触发加载的偏移倍数,基数是视窗高度,可根据部署环境的请求速度调节 + # The factor of viewport height that triggers loading + offset_factor: 2 + +# 图标库,包含了大量社交类图标,主题依赖的不包含在内,因此可自行修改,详见 https://hexo.fluid-dev.com/docs/icon/ +# Icon library, which includes many social icons, does not include those theme dependent, so your can modify link by yourself. See: https://hexo.fluid-dev.com/docs/en/icon/ +# iconfont: //at.alicdn.com/t/font_1736178_lbnruvf0jn.css + + +#--------------------------- +# 页头 +# Header +#--------------------------- + +# 导航栏的相关配置 +# Navigation bar +navbar: + # 导航栏左侧的标题,为空则按 hexo config 中 `title` 显示 + # The title on the left side of the navigation bar. If empty, it is based on `title` in hexo config + blog_title: "漠北残月的博客" + + # 导航栏毛玻璃特效,实验性功能,可能会造成页面滚动掉帧和抖动,部分浏览器不支持会自动不生效 + # Navigation bar frosted glass special animation. It is an experimental feature + ground_glass: + enable: true + + # 模糊像素,只能为数字,数字越大模糊度越高 + # Number of blurred pixel. the larger the number, the higher the blur + px: 3 + + # 不透明度,数字越大透明度越低,注意透明过度可能看不清菜单字体 + # Ratio of opacity, 1.0 is completely opaque + # available: 0 - 1.0 + alpha: 0.7 + + # 导航栏菜单,可自行增减,key 用来关联 languages/*.yml,如不存在关联则显示 key 本身的值;icon 是 css class,可以省略;增加 name 可以强制显示指定名称 + # Navigation bar menu. `key` is used to associate languages/*.yml. If there is no association, the value of `key` itself will be displayed; if `icon` is a css class, it can be omitted; adding `name` can force the display of the specified name + menu: + - { key: "home", link: "/", icon: "iconfont icon-home-fill" } + - { key: "archive", link: "/archives/", icon: "iconfont icon-archive-fill" } + # - { key: "category", link: "/categories/", icon: "iconfont icon-category-fill" } + - { key: "tag", link: "/tags/", icon: "iconfont icon-tags-fill" } + - { key: "RSS", link: "/atom.xml", icon: "iconfont icon-rss" } + - { key: "随机", link: "#", icon: "iconfont icon-code"} + - { key: "笔记", link: "/posts/fcd36967", icon: "iconfont icon-pen"} + #- { key: "links", link: "/links/", icon: "iconfont icon-link-fill" } + - { key: "about", link: "/about/", icon: "iconfont icon-user-fill" } + +# 搜索功能,基于 hexo-generator-search 插件,若已安装其他搜索插件请关闭此功能,以避免生成多余的索引文件 +# Search feature, based on hexo-generator-search. If you have installed other search plugins, please disable this feature to avoid generating redundant index files +search: + enable: true + + # 搜索索引文件的路径,可以是相对路径或外站的绝对路径 + # Path for search index file, it can be a relative path or an absolute path + path: /local-search.xml + + # 文件生成在本地的位置,必须是相对路径 + # The location where the index file is generated locally, it must be a relative location + generate_path: /local-search.xml + + # 搜索的范围 + # Search field + # Options: post | page | all + field: post + + # 搜索是否扫描正文 + # If true, search will scan the post content + content: true + +# 首屏图片的相关配置 +# Config of the big image on the first screen +banner: + # 视差滚动,图片与板块会随着屏幕滚动产生视差效果 + # Scrolling parallax + parallax: true + + # 图片最小的宽高比,以免图片两边被过度裁剪,适用于移动端竖屏时,如需关闭设为 0 + # Minimum ratio of width to height, applicable to the vertical screen of mobile device, if you need to close it, set it to 0 + width_height_ratio: 1.0 + +# 向下滚动的箭头 +# Scroll down arrow +scroll_down_arrow: + enable: true + + # 头图高度不小于指定比例,才显示箭头 + # Only the height of the banner image is greater than the ratio, the arrow is displayed + # Available: 0 - 100 + banner_height_limit: 80 + + # 翻页后自动滚动 + # Auto scroll after page turning + scroll_after_turning_page: true + +# 向顶部滚动的箭头 +# Scroll top arrow +scroll_top_arrow: + enable: true + +# Open Graph metadata +# See: https://hexo.io/docs/helpers.html#open-graph +open_graph: + enable: true + twitter_card: summary_large_image + twitter_id: + twitter_site: + google_plus: + fb_admins: + fb_app_id: + + +#--------------------------- +# 页脚 +# Footer +#--------------------------- +footer: + # 页脚第一行文字的 HTML,建议保留 Fluid 的链接,用于向更多人推广本主题 + # HTML of the first line of the footer, it is recommended to keep the Fluid link to promote this theme to more people + content: ' + Hexo + + Fluid + +
+ © 2023 | + + mobeicanyue +
+ +
+ 载入年份... + 载入天数... + 载入时分... +
+ + + + ' + + + # 展示网站的 PV、UV 统计数 + # Display website PV and UV statistics + statistics: + enable: false + + # 统计数据来源,使用 leancloud 需要设置 `web_analytics: leancloud` 中的参数;使用 busuanzi 不需要额外设置,但是有时不稳定,另外本地运行时 busuanzi 显示统计数据很大属于正常现象,部署后会正常 + # Data source. If use leancloud, you need to set the parameter in `web_analytics: leancloud` + # Options: busuanzi | leancloud + source: "busuanzi" + + # 国内大陆服务器的备案信息 + # For Chinese mainland website policy, other areas keep disable + beian: + enable: false + # ICP 证号 + icp_text: 京 ICP 证 123456 号 + # 公安备案号,不填则只显示 ICP + police_text: 京公网安备 12345678 号 + # 公安备案的编号,用于 URL 跳转查询 + police_code: 12345678 + # 公安备案的图片。为空时不显示备案图片 + police_icon: /img/police_beian.png + + +#--------------------------- +# 首页 +# Home Page +#--------------------------- +index: + # 首页 Banner 头图,可以是相对路径或绝对路径,以下相同 + # Path of Banner image, can be a relative path or an absolute path, the same on other pages + banner_img: https://www.yuanxiapi.cn/api/bing/ + + # 头图高度,屏幕百分比 + # Height ratio of banner image + # Available: 0 - 100 + banner_img_height: 100 + + # 头图黑色蒙版的不透明度,available: 0 - 1 . 0,1 是完全不透明 + # Opacity of the banner mask, 1.0 is completely opaque + # Available: 0 - 1.0 + banner_mask_alpha: 0.3 + + # 首页副标题的独立设置 + # Independent config of home page subtitle + slogan: + enable: true + + # 为空则按 hexo config.subtitle 显示 + # If empty, text based on `subtitle` in hexo config + text: "漠北残月的博客" + + # 通过 API 接口作为首页副标题的内容,必须返回的是 JSON 格式,如果请求失败则按 text 字段显示,该功能必须先开启 typing 打字机功能 + # Subtitle of the homepage through the API, must be returned a JSON. If the request fails, it will be displayed in `text` value. This feature must first enable the typing animation + api: + enable: true + + # 请求地址 + # Request url + url: "https://v1.hitokoto.cn/" + + # 请求方法 + # Request method + # Available: GET | POST | PUT + method: "GET" + + # 请求头 + # Request headers + headers: {} + + # 从请求结果获取字符串的取值字段,最终必须是一个字符串,例如返回结果为 {"data": {"author": "fluid", "content": "An elegant theme"}}, 则取值字段为 ['data', 'content'];如果返回是列表则自动选择第一项 + # The value field of the string obtained from the response. For example, the response content is {"data": {"author": "fluid", "content": "An elegant theme"}}, the expected `keys: ['data','content']`; if the return is a list, the first item is automatically selected + keys: ["hitokoto"] + + # 自动截取文章摘要 + # Auto extract post + auto_excerpt: + enable: true + + # 打开文章的标签方式 + # The browser tag to open the post + # Available: _blank | _self + post_url_target: _self + + # 是否显示文章信息(时间、分类、标签) + # Meta information of post + post_meta: + date: true + category: true + tag: true + + # 文章通过 sticky 排序后,在首页文章标题前显示图标 + # If the posts are sorted by `sticky`, an icon is displayed in front of the post title + post_sticky: + enable: true + icon: "iconfont icon-top" + + +#--------------------------- +# 文章页 +# Post Page +#--------------------------- +post: + banner_img: https://www.yuanxiapi.cn/api/bing/ + banner_img_height: 70 + banner_mask_alpha: 0.3 + + # 文章在首页的默认封面图,当没有指定 index_img 时会使用该图片,若两者都为空则不显示任何图片 + # Path of the default post cover when `index_img` is not set. If both are empty, no image will be displayed + default_index_img: + + # 文章标题下方的元信息 + # Meta information below title + meta: + # 作者,优先根据 front-matter 里 author 字段,其次是 hexo 配置中 author 值 + # Author, based on `author` field in front-matter, if not set, based on `author` value in hexo config + author: + enable: true + + # 文章日期,优先根据 front-matter 里 date 字段,其次是 md 文件日期 + # Post date, based on `date` field in front-matter, if not set, based on create date of .md file + date: + enable: true + # 格式参照 ISO-8601 日期格式化 + # ISO-8601 date format + # See: http://momentjs.cn/docs/#/parsing/string-format/ + format: "LL" + + # 字数统计 + # Word count + wordcount: + enable: true + + # 估计阅读全文需要的时长 + # Estimated reading time + min2read: + enable: true + # 每个字词的长度,建议:中文≈2,英文≈5,中英混合可自行调节 + # Average word length (chars count in word), ZH ≈ 2, EN ≈ 5 + awl: 2 + # 每分钟阅读字数,如果大部分是技术文章可适度调低 + # Words per minute + wpm: 50 + + # 浏览量计数 + # Number of visits + views: + enable: false + # 统计数据来源 + # Data Source + # Options: busuanzi | leancloud + source: "busuanzi" + + # 在文章开头显示文章更新时间,该时间默认是 md 文件更新时间,可通过 front-matter 中 `updated` 手动指定(和 date 一样格式) + # Update date is displayed at the beginning of the post. The default date is the update date of the md file, which can be manually specified by `updated` in front-matter (same format as date) + updated: + enable: true + + # 格式参照 ISO-8601 日期格式化 + # ISO-8601 date format + # See: http://momentjs.cn/docs/#/parsing/string-format/ + date_format: "LL HH:mm" + + # 是否使用相对时间表示,比如:"3 天前" + # If true, it will be a relative time, such as: "3 days ago" + relative: false + + # 提示标签类型 + # Note class + # Options: default | primary | info | success | warning | danger | light + note_class: info + + # 侧边栏展示当前分类下的文章 + # Sidebar of category + category_bar: + enable: true + + # 开启后,只有在文章 Front-matter 里指定 `category_bar: true` 才会展示分类,也可以通过 `category_bar: ["分类A"]` 来指定分类 + # If true, only set `category_bar: true` in Front-matter will enable sidebar of category, also set `category_bar: ["CategoryA"]` to specify categories + specific: true + + # 置于板块的左侧或右侧 + # place in the board + # Options: left | right + placement: left + + # 文章的排序字段,前面带减号是倒序,不带减号是正序 + # Sort field for posts, with a minus sign is reverse order + # Options: date | title | or other field of front-matter + post_order_by: "title" + + # 单个分类中折叠展示文章数的最大值,超过限制会显示 More,0 则不限制 + # The maximum number of posts in a single category. If the limit is exceeded, it will be displayed More. If 0 no limit + post_limit: 0 + + # 侧边栏展示文章目录 + # Table of contents (TOC) in the sidebar + toc: + enable: true + + # 置于板块的左侧或右侧 + # place in the board + # Options: left | right + placement: right + + # 目录会选择这些节点作为标题 + # TOC will select these nodes as headings + headingSelector: "h1,h2,h3,h4,h5,h6" + + # 层级的折叠深度,0 是全部折叠,大于 0 后如果存在下级标题则默认展开 + # Collapse depth. If 0, all headings collapsed. If greater than 0, it will be expanded by default if there are sub headings + collapseDepth: 0 + + # 版权声明,会显示在每篇文章的结尾 + # Copyright, will be displayed at the end of each post + copyright: + enable: true + + # CreativeCommons license + # Options: BY | BY-SA | BY-ND | BY-NC | BY-NC-SA | BY-NC-ND + license: 'BY-NC-SA' + + # 显示作者 + author: + enable: true + + # 显示发布日期 + # Show post date + post_date: + enable: true + format: "LL HH:mm" + + # 显示更新日期 + # Show update date + update_date: + enable: true + format: "LL HH:mm" + + # 文章底部上一篇下一篇功能 + # Link to previous/next post + prev_next: + enable: true + + # 文章图片标题 + # Image caption + image_caption: + enable: true + + # 文章图片可点击放大 + # Zoom feature of images + image_zoom: + enable: true + # 放大后图片链接替换规则,可用于将压缩图片链接替换为原图片链接,如 ['-slim', ''] 是将链接中 `-slim` 移除;如果想使用正则请使用 `re:` 前缀,如 ['re:\\d{3,4}\\/\\d{3,4}\\/', ''] + # The image url replacement when zooming, the feature can be used to replace the compressed image to the original image, eg: ['-slim', ''] removes `-slim` from the image url when zooming; if you want to use regular, use prefix `re:`, eg: ['re:\\d{3,4}\\/\\d{3,4}\\/',''] + img_url_replace: ['', ''] + + # 脚注语法,会在文章底部生成脚注,如果 Markdown 渲染器本身支持,则建议关闭,否则可能会冲突 + # Support footnote syntax, footnotes will be generated at the bottom of the post page. If the Markdown renderer itself supports it, please disable it, otherwise it may conflict + footnote: + enable: true + # 脚注的节标题,也可以在 front-matter 中通过 `footnote:

Reference

` 这种形式修改单独页面的 header + # The section title of the footnote, you can also modify the header of a single page in the form of `footnote:

Reference

` in front-matter + header: '' + + # 数学公式,开启之前需要更换 Markdown 渲染器,否则复杂公式会有兼容问题,具体请见:https://hexo.fluid-dev.com/docs/guide/##latex-数学公式 + # Mathematical formula. If enable, you need to change the Markdown renderer, see: https://hexo.fluid-dev.com/docs/en/guide/#math + math: + # 开启后文章默认可用,自定义页面如需使用,需在 Front-matter 中指定 `math: true` + # If you want to use math on the custom page, you need to set `math: true` in Front-matter + enable: false + + # 开启后,只有在文章 Front-matter 里指定 `math: true` 才会在文章页启动公式转换,以便在页面不包含公式时提高加载速度 + # If true, only set `math: true` in Front-matter will enable math, to load faster when the page does not contain math + specific: false + + # Options: mathjax | katex + engine: mathjax + + # 流程图,基于 mermaid-js,具体请见:https://hexo.fluid-dev.com/docs/guide/#mermaid-流程图 + # Flow chart, based on mermaid-js, see: https://hexo.fluid-dev.com/docs/en/guide/#mermaid + mermaid: + # 开启后文章默认可用,自定义页面如需使用,需在 Front-matter 中指定 `mermaid: true` + # If you want to use mermaid on the custom page, you need to set `mermaid: true` in Front-matter + enable: false + + # 开启后,只有在文章 Front-matter 里指定 `mermaid: true` 才会在文章页启动公式转换,以便在页面不包含公式时提高加载速度 + # If true, only set `mermaid: true` in Front-matter will enable mermaid, to load faster when the page does not contain mermaid + specific: false + + # See: http://mermaid-js.github.io/mermaid/ + options: { theme: 'default' } + + # 评论插件 + # Comment plugin + comments: + enable: true + # 指定的插件,需要同时设置对应插件的必要参数 + # The specified plugin needs to set the necessary parameters at the same time + # Options: utterances | disqus | gitalk | valine | waline | changyan | livere | remark42 | twikoo | cusdis | giscus | discuss + type: giscus + + +#--------------------------- +# 评论插件 +# Comment plugins +# +# 开启评论需要先设置上方 `post: comments: enable: true`,然后根据 `type` 设置下方对应的评论插件参数 +# Enable comments need to be set `post: comments: enable: true`, then set the corresponding comment plugin parameters below according to `type` +#--------------------------- + +# Utterances +# 基于 GitHub Issues +# Based on GitHub Issues +# See: https://utteranc.es +utterances: + repo: + issue_term: pathname + label: utterances + theme: github-light + theme_dark: github-dark + +# Disqus +# 基于第三方的服务,国内用户直接使用容易被墙,建议配合 Disqusjs +# Based on third-party service +# See: https://disqus.com +disqus: + shortname: + # 以下为 Disqusjs 支持,国内用户如果想使用 Disqus 建议配合使用 + # The following are Disqusjs configurations, please ignore if DisqusJS is not required + # See: https://github.com/SukkaW/DisqusJS + disqusjs: false + apikey: + +# Gitalk +# 基于 GitHub Issues +# Based on GitHub Issues +# See: https://github.com/gitalk/gitalk#options +gitalk: + clientID: + clientSecret: + repo: + owner: + admin: ['name'] + language: zh-CN + labels: ['Gitalk'] + perPage: 10 + pagerDirection: last + distractionFreeMode: false + createIssueManually: true + # 默认 proxy 可能会失效,解决方法请见下方链接 + # The default proxy may be invalid, refer to the links for solutions + # https://github.com/gitalk/gitalk/issues/429 + # https://github.com/Zibri/cloudflare-cors-anywhere + proxy: https://cors-anywhere.azm.workers.dev/https://github.com/login/oauth/access_token + +# Valine +# 基于 LeanCloud +# Based on LeanCloud +# See: https://valine.js.org/ +valine: + appId: + appKey: + path: window.location.pathname + placeholder: + avatar: 'retro' + meta: ['nick', 'mail', 'link'] + requiredFields: [] + pageSize: 10 + lang: 'zh-CN' + highlight: false + recordIP: false + serverURLs: '' + emojiCDN: + emojiMaps: + enableQQ: false + +# Waline +# 从 Valine 衍生而来,额外增加了服务端和多种功能 +# Derived from Valine, with self-hosted service and new features +# See: https://waline.js.org/ +waline: + serverURL: '' + path: window.location.pathname + meta: ['nick', 'mail', 'link'] + requiredMeta: ['nick'] + lang: 'zh-CN' + emoji: ['https://cdn.jsdelivr.net/gh/walinejs/emojis/weibo'] + dark: 'html[data-user-color-scheme="dark"]' + wordLimit: 0 + pageSize: 10 + +# 畅言 Changyan +# 基于第三方的服务 +# Based on third-party service, insufficient support for regions outside China +# http://changyan.kuaizhan.com +changyan: + appid: '' + appkey: '' + +# 来必力 Livere +# 基于第三方的服务 +# Based on third-party service +# See: https://www.livere.com +livere: + uid: '' + +# Remark42 +# 需要自托管服务端 +# Based on self-hosted service +# See: https://remark42.com +remark42: + host: + site_id: + max_shown_comments: 10 + locale: zh + components: ['embed'] + +# Twikoo +# 支持腾讯云、Vercel、Railway 等多种平台部署 +# Based on Tencent CloudBase +# See: https://twikoo.js.org +twikoo: + envId: + region: ap-shanghai + path: window.location.pathname + +# Cusdis +# 基于第三方服务或自托管服务 +# Based on third-party or self-hosted service +# See https://cusdis.com +cusdis: + host: + app_id: + lang: zh-cn + +# Giscus +# 基于 GitHub Discussions,类似于 Utterances +# Based on GitHub Discussions, similar to Utterances +# See: https://giscus.app/ +giscus: + repo: mobeicanyue/blog-comment + repo-id: R_kgDOLnLyGw + category: Announcements + category-id: DIC_kwDOLnLyG84CeUpm + theme-light: light + theme-dark: dark + mapping: pathname + reactions-enabled: 1 + emit-metadata: 1 + input-position: top + lang: zh-CN + +# Discuss +# 多平台、多数据库、自托管、免费开源评论系统 +# Self-hosted, small size, multi-platform, multi-database, free and open source commenting system +# See: https://discuss.js.org +discuss: + serverURLs: + path: window.location.pathname + + +#--------------------------- +# 归档页 +# Archive Page +#--------------------------- +archive: + banner_img: https://www.yuanxiapi.cn/api/bing/ + banner_img_height: 60 + banner_mask_alpha: 0.3 + + +#--------------------------- +# 分类页 +# Category Page +#--------------------------- +category: + enable: false + banner_img: https://www.yuanxiapi.cn/api/bing/ + banner_img_height: 60 + banner_mask_alpha: 0.3 + + # 分类的排序字段,前面带减号是倒序,不带减号是正序 + # Sort field for categories, with a minus sign is reverse order + # Options: length | name + order_by: "-length" + + # 层级的折叠深度,0 是全部折叠,大于 0 后如果存在子分类则默认展开 + # Collapse depth. If 0, all posts collapsed. If greater than 0, it will be expanded by default if there are subcategories + collapse_depth: 0 + + # 文章的排序字段,前面带减号是倒序,不带减号是正序 + # Sort field for posts, with a minus sign is reverse order + # Options: date | title | or other field of front-matter + post_order_by: "-date" + + # 单个分类中折叠展示文章数的最大值,超过限制会显示 More,0 则不限制 + # The maximum number of posts in a single category. If the limit is exceeded, it will be displayed More. If 0 no limit + post_limit: 10 + + +#--------------------------- +# 标签页 +# Tag Page +#--------------------------- +tag: + enable: true + banner_img: https://www.yuanxiapi.cn/api/bing/ + banner_img_height: 80 + banner_mask_alpha: 0.3 + tagcloud: + min_font: 15 + max_font: 30 + unit: px + start_color: "#BBBBEE" + end_color: "#337ab7" + + +#--------------------------- +# 关于页 +# About Page +#--------------------------- +about: + enable: true + banner_img: https://www.yuanxiapi.cn/api/bing/ + banner_img_height: 60 + banner_mask_alpha: 0.3 + avatar: /images/avatar.webp + name: "Fluid" + intro: "An Arch Linux user, GNU/Linux and FOSS enthusiast." + # 更多图标可从 https://hexo.fluid-dev.com/docs/icon/ 查找,`class` 代表图标的 css class,添加 `qrcode` 后,图标不再是链接而是悬浮二维码 + # More icons can be found from https://hexo.fluid-dev.com/docs/en/icon/ `class` is the css class of the icon. If adding `qrcode`, The icon is no longer a link, but a hovering QR code + icons: + - { class: "iconfont icon-home-fill", link: "https://www.ovvv.top" , tip: "主页" } + - { class: "iconfont icon-github-fill", link: "https://github.com/mobeicanyue", tip: "GitHub" } + - { class: "iconfont icon-copyright", link: "https://blog.csdn.net/m0_52559040", tip: "CSDN" } + - { class: "iconfont icon-mail", link: "mailto:mobeicanyue@outlook.com", tip: "email" } + + +#--------------------------- +# 自定义页 +# Custom Page +# +# 通过 hexo new page 命令创建的页面 +# Custom Page through `hexo new page` +#--------------------------- +page: + banner_img: https://www.yuanxiapi.cn/api/bing/ + banner_img_height: 60 + banner_mask_alpha: 0.3 + + +#--------------------------- +# 404 页 +# 404 Page +#--------------------------- +page404: + enable: true + banner_img: https://www.yuanxiapi.cn/api/bing/ + banner_img_height: 85 + banner_mask_alpha: 0.3 + # 重定向到首页的延迟(毫秒) + # Delay in redirecting to home page (milliseconds) + redirect_delay: 5000 + + +#--------------------------- +# 友链页 +# Links Page +#--------------------------- +links: + enable: false + banner_img: https://www.yuanxiapi.cn/api/bing/ + banner_img_height: 60 + banner_mask_alpha: 0.3 + # 友链的成员项 + # Member item of page + items: + - { + title: "Fluid Blog", + intro: "主题博客", + link: "https://hexo.fluid-dev.com/", + avatar: "/img/favicon.png" + } + - { + title: "Fluid Docs", + intro: "主题使用指南", + link: "https://hexo.fluid-dev.com/docs/", + avatar: "/img/favicon.png" + } + - { + title: "Fluid Repo", + intro: "主题 GitHub 仓库", + link: "https://github.com/fluid-dev/hexo-theme-fluid", + avatar: "/img/favicon.png" + } + + # 当成员头像加载失败时,替换为指定图片 + # When the member avatar fails to load, replace the specified image + onerror_avatar: /img/avatar.png + + # 友链下方自定义区域,支持 HTML,可插入例如申请友链的文字 + # Custom content at the bottom of the links + custom: + enable: false + content: '

在下方留言申请加入我的友链,按如下格式提供信息:

' + + # 评论插件 + # Comment plugin + comments: + enable: true + # 指定的插件,需要同时设置对应插件的必要参数 + # The specified plugin needs to set the necessary parameters at the same time + # Options: utterances | disqus | gitalk | valine | waline | changyan | livere | remark42 | twikoo | cusdis | giscus | discuss + type: giscus + + +#--------------------------- +# 以下是配置 JS CSS 等静态资源的 URL 前缀,可以自定义成 CDN 地址, +# 如果需要修改,最好使用与默认配置相同的版本,以避免潜在的问题, +# ** 如果你不知道如何设置,请不要做任何改动 ** +# +# Here is the url prefix to configure the static assets. Set CDN addresses you want to customize. +# Be aware that you would better use the same version as default ones to avoid potential problems. +# DO NOT EDIT THE FOLLOWING SETTINGS UNLESS YOU KNOW WHAT YOU ARE DOING +#--------------------------- + +static_prefix: + # 内部静态 + # Internal static + internal_js: /js + internal_css: /css + internal_img: /img + + anchor: https://lib.baomitu.com/anchor-js/4.3.1/ + + github_markdown: https://lib.baomitu.com/github-markdown-css/4.0.0/ + + jquery: https://lib.baomitu.com/jquery/3.6.4/ + + bootstrap: https://lib.baomitu.com/twitter-bootstrap/4.6.1/ + + prismjs: https://lib.baomitu.com/prism/1.29.0/ + + tocbot: https://lib.baomitu.com/tocbot/4.20.1/ + + typed: https://lib.baomitu.com/typed.js/2.0.12/ + + fancybox: https://lib.baomitu.com/fancybox/3.5.7/ + + nprogress: https://lib.baomitu.com/nprogress/0.2.0/ + + mathjax: https://lib.baomitu.com/mathjax/3.2.2/ + + katex: https://lib.baomitu.com/KaTeX/0.16.2/ + + busuanzi: https://busuanzi.ibruce.info/busuanzi/2.3/ + + clipboard: https://lib.baomitu.com/clipboard.js/2.0.11/ + + mermaid: https://lib.baomitu.com/mermaid/8.14.0/ + + valine: https://lib.baomitu.com/valine/1.5.1/ + + waline: https://cdn.staticfile.org/waline/2.15.5/ + + gitalk: https://lib.baomitu.com/gitalk/1.8.0/ + + disqusjs: https://lib.baomitu.com/disqusjs/1.3.0/ + + twikoo: https://lib.baomitu.com/twikoo/1.6.8/ + + discuss: https://lib.baomitu.com/discuss/1.2.1/ + + hint: https://lib.baomitu.com/hint.css/2.7.0/ + + moment: https://lib.baomitu.com/moment.js/2.29.4/ diff --git a/_config.yml b/_config.yml new file mode 100644 index 00000000..8ec25204 --- /dev/null +++ b/_config.yml @@ -0,0 +1,168 @@ +# Hexo Configuration +## Docs: https://hexo.io/docs/configuration.html +## Source: https://github.com/hexojs/hexo/ + +# Site +title: 漠北残月的博客 +subtitle: '漠北残月,江南垂柳' +description: '生命如同寓言,其价值不在于长短,而在于内容。欢迎来到漠北残月的博客,这是一个分享技术与记录生活的地方。' +keywords: 漠北残月, 博客, mobeicanyue, technology, daily, share +author: mobeicanyue +language: zh-CN +timezone: 'Asia/Shanghai' + +# URL +## Set your site url here. For example, if you use GitHub Page, set url as 'https://username.github.io/project' +url: https://blog.ovvv.top +permalink: posts/:abbrlink/ +# abbrlink config +abbrlink: + alg: crc32 #support crc16(default) and crc32 + rep: hex #support dec(default) and hex + drafts: false #(true)Process draft,(false)Do not process draft. false(default) + # Generate categories from directory-tree + # depth: the max_depth of directory-tree you want to generate, should > 0 + auto_category: + enable: true #true(default) + depth: #3(default) + over_write: false + auto_title: false #enable auto title, it can auto fill the title by path + auto_date: false #enable auto date, it can auto fill the date by time today + force: false # 启用强制模式,在此模式下,插件将忽略缓存,并计算每篇文章的 abbrlink,即使它已经有了 abbrlink。这只会更新 abbrlink,而不会更新其他前置变量。 + +permalink_defaults: +pretty_urls: + trailing_index: false # Set to false to remove trailing 'index.html' from permalinks + trailing_html: false # Set to false to remove trailing '.html' from permalinks + +# Directory +source_dir: source +public_dir: public +tag_dir: tags +archive_dir: archives +category_dir: categories +code_dir: downloads/code +i18n_dir: :lang +skip_render: + +# Writing +new_post_name: :title.md # File name of new posts +default_layout: post +titlecase: false # Transform title into titlecase +external_link: + enable: true # Open external links in new tab + field: site # Apply to the whole site + exclude: '' +filename_case: 0 +render_drafts: true + +# post_asset_folder: true +# 可以使用正常的 markdown 语法引用图片而不再使用 hexo 的 {% asset_path slug %} 语法 +marked: + prependRoot: true + postAsset: true + +relative_link: false +future: true +syntax_highlighter: highlight.js +highlight: + line_number: true + auto_detect: false + tab_replace: '' + wrap: true + hljs: false +prismjs: + preprocess: true + line_number: true + tab_replace: '' + +# Home page setting +# path: Root path for your blogs index page. (default = '') +# per_page: Posts displayed per page. (0 = disable pagination) +# order_by: Posts order. (Order by date descending by default) +index_generator: + path: '' + per_page: 10 + order_by: -date + +# Category & Tag +default_category: uncategorized +category_map: +tag_map: + +# Metadata elements +## https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta +meta_generator: true + +# Date / Time format +## Hexo uses Moment.js to parse and display date +## You can customize the date format as defined in +## http://momentjs.com/docs/#/displaying/format/ +date_format: YYYY-MM-DD +time_format: HH:mm:ss +## updated_option supports 'mtime', 'date', 'empty' +updated_option: 'mtime' + +# Pagination +## Set per_page to 0 to disable pagination +per_page: 10 +pagination_dir: page + +# Include / Exclude file(s) +## include:/exclude: options only apply to the 'source/' folder +include: +exclude: +ignore: + +# Extensions +## Plugins: https://hexo.io/plugins/ +## Themes: https://hexo.io/themes/ +theme: fluid + + +sitemap: + rel: true + tags: false + categories: false + +# RSS +feed: + type: atom + path: atom.xml + limit: 20 + hub: + content: + content_limit: 140 + content_limit_delim: ' ' + icon: /images/rss.svg + +# 压缩文件 +minify: + enable: true + html: + enable: true + exclude: + css: + enable: true + exclude: + - '*.min.css' + js: + enable: true + exclude: + - '*.min.js' + svg: + enable: true + include: + - '*.svg' + gzip: + enable: false + brotli: + enable: false + xml: + enable: true + include: + - '*.xml' + json: + enable: true + include: + - '*.json' diff --git a/asset/baidu_verify_codeva-GwRsL4VPtx.html.html b/asset/baidu_verify_codeva-GwRsL4VPtx.html.html new file mode 100644 index 00000000..fd305eb9 --- /dev/null +++ b/asset/baidu_verify_codeva-GwRsL4VPtx.html.html @@ -0,0 +1 @@ +24ce2b41c5249810d1cf755966fbf70a \ No newline at end of file diff --git a/asset/naver57322dd0ed14599dd3052c79c6892766.html b/asset/naver57322dd0ed14599dd3052c79c6892766.html new file mode 100644 index 00000000..d0c3457d --- /dev/null +++ b/asset/naver57322dd0ed14599dd3052c79c6892766.html @@ -0,0 +1 @@ +naver-site-verification: naver57322dd0ed14599dd3052c79c6892766.html \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 00000000..8c557258 --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "hexo-site", + "homepage": "https://blog.ovvv.top", + "license": "Apache-2.0", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "hexo generate", + "clean": "hexo clean", + "deploy": "hexo deploy", + "server": "hexo server" + }, + "hexo": { + "version": "7.2.0" + }, + "dependencies": { + "hexo": "^7.2.0", + "hexo-abbrlink": "^2.2.1", + "hexo-generator-archive": "^2.0.0", + "hexo-generator-category": "^2.0.0", + "hexo-generator-feed": "^3.0.0", + "hexo-generator-index": "^3.0.0", + "hexo-generator-sitemap": "^3.0.1", + "hexo-generator-tag": "^2.0.0", + "hexo-renderer-ejs": "^2.0.0", + "hexo-renderer-marked": "^6.3.0", + "hexo-renderer-stylus": "^3.0.1", + "hexo-server": "^3.0.0", + "hexo-theme-fluid": "^1.9.7", + "hexo-yam": "^8.0.0" + } +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 00000000..0c4e47b9 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,2381 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + hexo: + specifier: ^7.2.0 + version: 7.2.0 + hexo-abbrlink: + specifier: ^2.2.1 + version: 2.2.1 + hexo-generator-archive: + specifier: ^2.0.0 + version: 2.0.0 + hexo-generator-category: + specifier: ^2.0.0 + version: 2.0.0 + hexo-generator-feed: + specifier: ^3.0.0 + version: 3.0.0 + hexo-generator-index: + specifier: ^3.0.0 + version: 3.0.0 + hexo-generator-sitemap: + specifier: ^3.0.1 + version: 3.0.1 + hexo-generator-tag: + specifier: ^2.0.0 + version: 2.0.0 + hexo-renderer-ejs: + specifier: ^2.0.0 + version: 2.0.0 + hexo-renderer-marked: + specifier: ^6.3.0 + version: 6.3.0 + hexo-renderer-stylus: + specifier: ^3.0.1 + version: 3.0.1 + hexo-server: + specifier: ^3.0.0 + version: 3.0.0 + hexo-theme-fluid: + specifier: ^1.9.7 + version: 1.9.7(nunjucks@3.2.4) + hexo-yam: + specifier: ^8.0.0 + version: 8.0.0 + +packages: + + /@adobe/css-tools@4.3.3: + resolution: {integrity: sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==} + dev: false + + /@babel/code-frame@7.24.2: + resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.24.2 + picocolors: 1.0.0 + dev: false + + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/highlight@7.24.2: + resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.0 + dev: false + + /@jridgewell/gen-mapping@0.3.5: + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.25 + dev: false + + /@jridgewell/resolve-uri@3.1.2: + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + dev: false + + /@jridgewell/set-array@1.2.1: + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + dev: false + + /@jridgewell/source-map@0.3.6: + resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + dev: false + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: false + + /@jridgewell/trace-mapping@0.3.25: + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: false + + /@tootallnate/once@2.0.0: + resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + engines: {node: '>= 10'} + dev: false + + /@trysound/sax@0.2.0: + resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} + engines: {node: '>=10.13.0'} + dev: false + + /@types/minimist@1.2.5: + resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} + dev: false + + /@types/normalize-package-data@2.4.4: + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + dev: false + + /a-sync-waterfall@1.0.1: + resolution: {integrity: sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==} + dev: false + + /abab@2.0.6: + resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + deprecated: Use your platform's native atob() and btoa() methods instead + dev: false + + /abbrev@2.0.0: + resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: false + + /accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + dev: false + + /acorn-globals@7.0.1: + resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} + dependencies: + acorn: 8.11.3 + acorn-walk: 8.3.2 + dev: false + + /acorn-walk@8.3.2: + resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + engines: {node: '>=0.4.0'} + dev: false + + /acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: false + + /agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: false + + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: false + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: false + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: false + + /archy@1.0.0: + resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} + dev: false + + /argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + dev: false + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: false + + /arrify@1.0.1: + resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} + engines: {node: '>=0.10.0'} + dev: false + + /asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + dev: false + + /async@3.2.5: + resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} + dev: false + + /asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: false + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: false + + /basic-auth@2.0.1: + resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==} + engines: {node: '>= 0.8'} + dependencies: + safe-buffer: 5.1.2 + dev: false + + /binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + dev: false + + /bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + dev: false + + /boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: false + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: false + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: false + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: false + + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: false + + /bytes@3.0.0: + resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} + engines: {node: '>= 0.8'} + dev: false + + /camel-case@3.0.0: + resolution: {integrity: sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==} + dependencies: + no-case: 2.3.2 + upper-case: 1.1.3 + dev: false + + /camel-case@4.1.2: + resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} + dependencies: + pascal-case: 3.1.2 + tslib: 2.6.2 + dev: false + + /camelcase-keys@6.2.2: + resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} + engines: {node: '>=8'} + dependencies: + camelcase: 5.3.1 + map-obj: 4.3.0 + quick-lru: 4.0.1 + dev: false + + /camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + dev: false + + /camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + dev: false + + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: false + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: false + + /chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: false + + /clean-css@4.2.4: + resolution: {integrity: sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==} + engines: {node: '>= 4.0'} + dependencies: + source-map: 0.6.1 + dev: false + + /clean-css@5.3.3: + resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} + engines: {node: '>= 10.0'} + dependencies: + source-map: 0.6.1 + dev: false + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: false + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: false + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: false + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: false + + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: false + + /command-exists@1.2.9: + resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} + dev: false + + /commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + dev: false + + /commander@5.1.0: + resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} + engines: {node: '>= 6'} + dev: false + + /commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + dev: false + + /compressible@2.0.18: + resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + + /compression@1.7.4: + resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==} + engines: {node: '>= 0.8.0'} + dependencies: + accepts: 1.3.8 + bytes: 3.0.0 + compressible: 2.0.18 + debug: 2.6.9 + on-headers: 1.0.2 + safe-buffer: 5.1.2 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + dev: false + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: false + + /connect@3.7.0: + resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} + engines: {node: '>= 0.10.0'} + dependencies: + debug: 2.6.9 + finalhandler: 1.1.2 + parseurl: 1.3.3 + utils-merge: 1.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + dev: false + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: false + + /css-select@5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.1.0 + nth-check: 2.1.1 + dev: false + + /css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.0 + dev: false + + /css-tree@2.3.1: + resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + dependencies: + mdn-data: 2.0.30 + source-map-js: 1.2.0 + dev: false + + /css-what@6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + dev: false + + /csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + dependencies: + css-tree: 2.2.1 + dev: false + + /cssom@0.3.8: + resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} + dev: false + + /cssom@0.5.0: + resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} + dev: false + + /cssstyle@2.3.0: + resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} + engines: {node: '>=8'} + dependencies: + cssom: 0.3.8 + dev: false + + /cuid@2.1.8: + resolution: {integrity: sha512-xiEMER6E7TlTPnDxrM4eRiC6TRgjNX9xzEZ5U/Se2YJKr7Mq4pJn/2XEHjl3STcSh96GmkHPcBXLES8M29wyyg==} + deprecated: Cuid and other k-sortable and non-cryptographic ids (Ulid, ObjectId, KSUID, all UUIDs) are all insecure. Use @paralleldrive/cuid2 instead. + dev: false + + /data-urls@3.0.2: + resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} + engines: {node: '>=12'} + dependencies: + abab: 2.0.6 + whatwg-mimetype: 3.0.0 + whatwg-url: 11.0.0 + dev: false + + /debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.0.0 + dev: false + + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: false + + /decamelize-keys@1.1.1: + resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} + engines: {node: '>=0.10.0'} + dependencies: + decamelize: 1.2.0 + map-obj: 1.0.1 + dev: false + + /decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + dev: false + + /decimal.js@10.4.3: + resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} + dev: false + + /deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + dev: false + + /define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + dev: false + + /delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: false + + /depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dev: false + + /destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dev: false + + /dom-serializer@1.4.1: + resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + entities: 2.2.0 + dev: false + + /dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + dev: false + + /domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: false + + /domexception@4.0.0: + resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} + engines: {node: '>=12'} + deprecated: Use your platform's native DOMException instead + dependencies: + webidl-conversions: 7.0.0 + dev: false + + /domhandler@4.3.1: + resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: false + + /domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: false + + /dompurify@3.1.1: + resolution: {integrity: sha512-tVP8C/GJwnABOn/7cx/ymx/hXpmBfWIPihC1aOEvS8GbMqy3pgeYtJk1HXN3CO7tu+8bpY18f6isjR5Cymj0TQ==} + dev: false + + /domutils@2.8.0: + resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + dependencies: + dom-serializer: 1.4.1 + domelementtype: 2.3.0 + domhandler: 4.3.1 + dev: false + + /domutils@3.1.0: + resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dev: false + + /duplexify@4.1.3: + resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} + dependencies: + end-of-stream: 1.4.4 + inherits: 2.0.4 + readable-stream: 3.6.2 + stream-shift: 1.0.3 + dev: false + + /ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + dev: false + + /ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + jake: 10.8.7 + dev: false + + /encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + dev: false + + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: false + + /entities@2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + dev: false + + /entities@3.0.1: + resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==} + engines: {node: '>=0.12'} + dev: false + + /entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + dev: false + + /error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: false + + /escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + dev: false + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: false + + /escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + dev: false + + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: false + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: false + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: false + + /etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + dev: false + + /fast-equals@3.0.3: + resolution: {integrity: sha512-NCe8qxnZFARSHGztGMZOO/PC1qa5MIFB5Hp66WdzbCRAz8U8US3bx1UTgLS49efBQPcUtO9gf5oVEY8o7y/7Kg==} + dev: false + + /filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + dependencies: + minimatch: 5.1.6 + dev: false + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: false + + /finalhandler@1.1.2: + resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} + engines: {node: '>= 0.8'} + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.3.0 + parseurl: 1.3.3 + statuses: 1.5.0 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: false + + /find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + dev: false + + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + + /fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + dev: false + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: false + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: false + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: false + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: false + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: false + + /hard-rejection@2.1.0: + resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} + engines: {node: '>=6'} + dev: false + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + dev: false + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: false + + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: false + + /he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + dev: false + + /hexo-abbrlink@2.2.1: + resolution: {integrity: sha512-yvazN7bbrIb7p8QU3nJ/8fbDmir1mFroYvUYcJz5xpc6DtszKggschmqZg6WNUdjhDBFyDwksrIUfwQnw0OOuA==} + dependencies: + hexo-front-matter: 1.0.0 + hexo-fs: 3.1.0 + dev: false + + /hexo-cli@4.3.2: + resolution: {integrity: sha512-druJeBgLpG9ncDS5AhBHdAXk0G4CFj8Qes09pApyZ6bR+nJW1JYiDMuilhudaKDdq+1l49jWXVTidkcb7p0Jbw==} + engines: {node: '>=14'} + hasBin: true + dependencies: + abbrev: 2.0.0 + bluebird: 3.7.2 + command-exists: 1.2.9 + hexo-fs: 4.1.3 + hexo-log: 4.1.0 + hexo-util: 3.3.0 + minimist: 1.2.8 + picocolors: 1.0.0 + resolve: 1.22.8 + tildify: 2.0.0 + dev: false + + /hexo-front-matter@1.0.0: + resolution: {integrity: sha512-Hn8IIzgWWnxYTekrjnA0rxwWMoQHifyrxKMqVibmFaRKf4AQ2V6Xo13Jiso6CDwYfS+OdA41QS5DG1Y+QXA5gw==} + engines: {node: '>=8.6.0'} + dependencies: + js-yaml: 3.14.1 + dev: false + + /hexo-front-matter@4.2.1: + resolution: {integrity: sha512-sJJI0GNmejYiwBvgnGRKn5V3sbODB4dNPr8jyw2Qp0PRHr4Uuyv8iyxw6WfK3+T7yvzYvJOh+tZ7jnwr2BYARA==} + engines: {node: '>=14'} + dependencies: + js-yaml: 4.1.0 + dev: false + + /hexo-fs@3.1.0: + resolution: {integrity: sha512-SfoDH7zlU9Iop+bAfEONXezbNIkpVX1QqjNCBYpapilZR+xVOCfTEdlNixanrKBbLGPb2fXqrdDBFgrKuiVGQQ==} + engines: {node: '>=10.13.0'} + dependencies: + bluebird: 3.7.2 + chokidar: 3.6.0 + graceful-fs: 4.2.11 + hexo-util: 2.7.0 + dev: false + + /hexo-fs@4.1.3: + resolution: {integrity: sha512-Q92zQ5PlVDouvSWFLXQoFSTLIUIODikUJs2BfAXQglyOEjN1dOQn1Z5Nimk/7GHof17R5h/uObCQLnZAjzI2tg==} + engines: {node: '>=14'} + dependencies: + bluebird: 3.7.2 + chokidar: 3.6.0 + graceful-fs: 4.2.11 + hexo-util: 3.3.0 + dev: false + + /hexo-generator-archive@2.0.0: + resolution: {integrity: sha512-KikJk7dGFbtNHOgqtLFGf5T/S8n1paGp+Gy0KfVDz+HKYhGbXOouyiZkmc3O9KrYt6ja14rmkMhq7KKGtvfehw==} + engines: {node: '>=14'} + dependencies: + hexo-pagination: 3.0.0 + dev: false + + /hexo-generator-category@2.0.0: + resolution: {integrity: sha512-9OduRBf3WeRDa4BR0kAfRjOVHur7v3fm0NKAwbjUiqULigAdNZVZPO3cHKW2MlBbl/lI5PuWdhQ9zZ99CCCAgQ==} + engines: {node: '>=14'} + dependencies: + hexo-pagination: 3.0.0 + dev: false + + /hexo-generator-feed@3.0.0: + resolution: {integrity: sha512-Jo35VSRSNeMitS2JmjCq3OHAXXYU4+JIODujHtubdG/NRj2++b3Tgyz9pwTmROx6Yxr2php/hC8og5AGZHh8UQ==} + engines: {node: '>=10.13.0'} + dependencies: + hexo-util: 2.7.0 + nunjucks: 3.2.4 + transitivePeerDependencies: + - chokidar + dev: false + + /hexo-generator-index@3.0.0: + resolution: {integrity: sha512-83AuNN4cWdLVi//3ugR8E3kR6rrOwhXZt+hOCm1IjtIGj353/GlrtpMHpqZHU5kqipzj4miy9dweVdukXglVWw==} + engines: {node: '>=14'} + dependencies: + hexo-pagination: 3.0.0 + dev: false + + /hexo-generator-sitemap@3.0.1: + resolution: {integrity: sha512-n+0KLNmq6TLbiZPTQF6NY5MbEem/O+DFx0lgQZNQcU4tdjXIZRrQJs+KRKeT66NTkdlYTqb4WwCxswLqQz0crA==} + engines: {node: '>=12.13.0'} + dependencies: + hexo-util: 2.7.0 + micromatch: 4.0.5 + nunjucks: 3.2.4 + transitivePeerDependencies: + - chokidar + dev: false + + /hexo-generator-tag@2.0.0: + resolution: {integrity: sha512-1px/hF3veEohWDN8jjzchQhaiz+uOStUvvMaBJC9vWOlALh30UFcapL8IrvAwwJZjFRVA+WqGgDRqoQ8+yaaFw==} + engines: {node: '>=14'} + dependencies: + hexo-pagination: 3.0.0 + dev: false + + /hexo-i18n@2.0.0: + resolution: {integrity: sha512-dkUXecEtChaQMdTHN4WR13c8GwKqjbSOZPJS9qDqV6Ebnb77Wa/nQzWFckhP0dCps3a9lUQBd8hYGOMbOosiQQ==} + engines: {node: '>=14'} + dependencies: + sprintf-js: 1.1.3 + dev: false + + /hexo-log@4.1.0: + resolution: {integrity: sha512-i2Sgxk8Cgx5viSjq5qW5N/rBFfwoCKQcH8qnnW1fawCapcdEAhIsq+Y3vbrs9bssyDlyU6Vqm4oQmosREaNI7Q==} + engines: {node: '>=14'} + dependencies: + picocolors: 1.0.0 + dev: false + + /hexo-pagination@3.0.0: + resolution: {integrity: sha512-8oo1iozloZo7TojPVYg4IxL3SJKCBdSJ908fTlIxIK7TWJIKdYnQlW31+12DBJ0NhVZA/lZisPObGF08wT8fKw==} + engines: {node: '>=14'} + dev: false + + /hexo-renderer-ejs@2.0.0: + resolution: {integrity: sha512-qCjE1IdwgDgv65qyb0KMVCwCdSVAkH0vwAe9XihjvaKWkmb9dtt8DgErOdqCXn0HReSyWiEVP2BrLRj3gyHwOQ==} + engines: {node: '>=12'} + dependencies: + ejs: 3.1.10 + dev: false + + /hexo-renderer-marked@6.3.0: + resolution: {integrity: sha512-V/ATcJ+tZHkTJSbScPzzHKmrwVMohU8i9MfuX9jp07Un/NpPtaTP821unP3JPu+O1nNLWMi+3xRbFRdm+8vajw==} + engines: {node: '>=14'} + dependencies: + dompurify: 3.1.1 + hexo-util: 3.3.0 + jsdom: 20.0.3 + marked: 4.3.0 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - utf-8-validate + dev: false + + /hexo-renderer-stylus@3.0.1: + resolution: {integrity: sha512-cFm8ZwShBBeFcQwOXc8EK7lIZnSYVD6OJykdL4GBw99hxc4eD5Hlsi32nRzE8sgKv00jhX1s9Da3GVVFMPAVQg==} + engines: {node: '>=14'} + dependencies: + nib: 1.2.0(stylus@0.62.0) + stylus: 0.62.0 + transitivePeerDependencies: + - supports-color + dev: false + + /hexo-server@3.0.0: + resolution: {integrity: sha512-u4s0ty9Aew6jV+a9oMrXBwhrRpUQ0U8PWM/88a5aHgDru58VY81mVrxOFxs788NAsWQ8OvsJtF5m7mnXoRnSIA==} + engines: {node: '>=12.13.0'} + dependencies: + bluebird: 3.7.2 + compression: 1.7.4 + connect: 3.7.0 + mime: 3.0.0 + morgan: 1.10.0 + open: 8.4.2 + picocolors: 1.0.0 + serve-static: 1.15.0 + transitivePeerDependencies: + - supports-color + dev: false + + /hexo-theme-fluid@1.9.7(nunjucks@3.2.4): + resolution: {integrity: sha512-rLpUNcs8XhAQZ9Iq8nZ27XbMDtbJs/y35kkpPmebUqV9hV+j3/Yy3tf3zKJW3nzZhTO/8bXYrtNDvmoj1TRmBQ==} + engines: {node: '>=8.10.0'} + peerDependencies: + nunjucks: ^3.0.0 + dependencies: + nunjucks: 3.2.4 + dev: false + + /hexo-util@2.7.0: + resolution: {integrity: sha512-hQM3h34nhDg0bSe/Tg1lnpODvNkz7h2u0+lZGzlKL0Oufp+5KCAEUX9wal7/xC7ax3/cwEn8IuoU75kNpZLpJQ==} + engines: {node: '>=12.4.0'} + dependencies: + bluebird: 3.7.2 + camel-case: 4.1.2 + cross-spawn: 7.0.3 + deepmerge: 4.3.1 + highlight.js: 11.9.0 + htmlparser2: 7.2.0 + prismjs: 1.29.0 + strip-indent: 3.0.0 + dev: false + + /hexo-util@3.3.0: + resolution: {integrity: sha512-YvGngXijE2muEh5L/VI4Fmjqb+/yAkmY+VuyhWVoRwQu1X7bmWodsfYRXX7CUYhi5LqsvH8FAe/yBW1+f6ZX4Q==} + engines: {node: '>=14'} + requiresBuild: true + dependencies: + camel-case: 4.1.2 + cross-spawn: 7.0.3 + deepmerge: 4.3.1 + highlight.js: 11.9.0 + htmlparser2: 9.1.0 + prismjs: 1.29.0 + strip-indent: 3.0.0 + dev: false + + /hexo-yam@8.0.0: + resolution: {integrity: sha512-V8w6J3n0ClFAos7S+abCSALdOD4YZsqTRSOL3WkFsaBVWqIX0yY4WYhc1ZDZPIh3nPJM8m6KmLgRuyvAaRUMRQ==} + engines: {node: '>= 14.15.0'} + dependencies: + clean-css: 5.3.3 + html-minifier: 4.0.0 + micromatch: 4.0.5 + minify-xml: 3.5.0 + svgo: 3.2.0 + terser: 5.30.4 + dev: false + + /hexo@7.2.0: + resolution: {integrity: sha512-RYIzl7jfG0i2jH/k5IZg4C1anyHfmKHNUsBKIn9LU0V3iQ0WQrwuOLFDJwaZDenqmzHYJhAVCGAkrBDfF/IlVg==} + engines: {node: '>=14'} + hasBin: true + dependencies: + abbrev: 2.0.0 + archy: 1.0.0 + bluebird: 3.7.2 + hexo-cli: 4.3.2 + hexo-front-matter: 4.2.1 + hexo-fs: 4.1.3 + hexo-i18n: 2.0.0 + hexo-log: 4.1.0 + hexo-util: 3.3.0 + js-yaml: 4.1.0 + js-yaml-js-types: 1.0.1(js-yaml@4.1.0) + micromatch: 4.0.5 + moize: 6.1.6 + moment: 2.30.1 + moment-timezone: 0.5.45 + nunjucks: 3.2.4 + picocolors: 1.0.0 + pretty-hrtime: 1.0.3 + resolve: 1.22.8 + strip-ansi: 6.0.1 + text-table: 0.2.0 + tildify: 2.0.0 + titlecase: 1.1.3 + warehouse: 5.0.1 + transitivePeerDependencies: + - chokidar + dev: false + + /highlight.js@11.9.0: + resolution: {integrity: sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==} + engines: {node: '>=12.0.0'} + dev: false + + /hosted-git-info@2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + dev: false + + /hosted-git-info@4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + dependencies: + lru-cache: 6.0.0 + dev: false + + /html-encoding-sniffer@3.0.0: + resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} + engines: {node: '>=12'} + dependencies: + whatwg-encoding: 2.0.0 + dev: false + + /html-minifier@4.0.0: + resolution: {integrity: sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==} + engines: {node: '>=6'} + hasBin: true + dependencies: + camel-case: 3.0.0 + clean-css: 4.2.4 + commander: 2.20.3 + he: 1.2.0 + param-case: 2.1.1 + relateurl: 0.2.7 + uglify-js: 3.17.4 + dev: false + + /htmlparser2@7.2.0: + resolution: {integrity: sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==} + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + domutils: 2.8.0 + entities: 3.0.1 + dev: false + + /htmlparser2@9.1.0: + resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.1.0 + entities: 4.5.0 + dev: false + + /http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + dev: false + + /http-proxy-agent@5.0.0: + resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} + engines: {node: '>= 6'} + dependencies: + '@tootallnate/once': 2.0.0 + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: false + + /indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + dev: false + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: false + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: false + + /is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: false + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.3.0 + dev: false + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.2 + dev: false + + /is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + dev: false + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: false + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: false + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: false + + /is-plain-obj@1.1.0: + resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} + engines: {node: '>=0.10.0'} + dev: false + + /is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + dev: false + + /is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + dev: false + + /is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + dependencies: + is-docker: 2.2.1 + dev: false + + /isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + dev: false + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: false + + /jake@10.8.7: + resolution: {integrity: sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==} + engines: {node: '>=10'} + hasBin: true + dependencies: + async: 3.2.5 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + dev: false + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: false + + /js-yaml-js-types@1.0.1(js-yaml@4.1.0): + resolution: {integrity: sha512-5tpfyORs8OQ43alNERbWfYRCtWgykvzYgY46fUhrQi2+kS7N0NuuFYLZ/IrfmVm5muLTndeMublgraXiFRjEPw==} + peerDependencies: + js-yaml: 4.x + dependencies: + esprima: 4.0.1 + js-yaml: 4.1.0 + dev: false + + /js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + dev: false + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: false + + /jsdom@20.0.3: + resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==} + engines: {node: '>=14'} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + dependencies: + abab: 2.0.6 + acorn: 8.11.3 + acorn-globals: 7.0.1 + cssom: 0.5.0 + cssstyle: 2.3.0 + data-urls: 3.0.2 + decimal.js: 10.4.3 + domexception: 4.0.0 + escodegen: 2.1.0 + form-data: 4.0.0 + html-encoding-sniffer: 3.0.0 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.9 + parse5: 7.1.2 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 4.1.3 + w3c-xmlserializer: 4.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 2.0.0 + whatwg-mimetype: 3.0.0 + whatwg-url: 11.0.0 + ws: 8.16.0 + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + + /json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: false + + /jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + dev: false + + /kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + dev: false + + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: false + + /locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + dependencies: + p-locate: 4.1.0 + dev: false + + /lower-case@1.1.4: + resolution: {integrity: sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==} + dev: false + + /lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + dependencies: + tslib: 2.6.2 + dev: false + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: false + + /map-obj@1.0.1: + resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} + engines: {node: '>=0.10.0'} + dev: false + + /map-obj@4.3.0: + resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} + engines: {node: '>=8'} + dev: false + + /marked@4.3.0: + resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==} + engines: {node: '>= 12'} + hasBin: true + dev: false + + /mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + dev: false + + /mdn-data@2.0.30: + resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + dev: false + + /meow@9.0.0: + resolution: {integrity: sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==} + engines: {node: '>=10'} + dependencies: + '@types/minimist': 1.2.5 + camelcase-keys: 6.2.2 + decamelize: 1.2.0 + decamelize-keys: 1.1.1 + hard-rejection: 2.1.0 + minimist-options: 4.1.0 + normalize-package-data: 3.0.3 + read-pkg-up: 7.0.1 + redent: 3.0.0 + trim-newlines: 3.0.1 + type-fest: 0.18.1 + yargs-parser: 20.2.9 + dev: false + + /micro-memoize@4.1.2: + resolution: {integrity: sha512-+HzcV2H+rbSJzApgkj0NdTakkC+bnyeiUxgT6/m7mjcz1CmM22KYFKp+EVj1sWe4UYcnriJr5uqHQD/gMHLD+g==} + dev: false + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: false + + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + + /mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + dev: false + + /mime@3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + dev: false + + /min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + dev: false + + /minify-xml@3.5.0: + resolution: {integrity: sha512-s03n6GC4tEDdU+JpNNAmKIoNMhN+aic3PS1Z9sROnlxJkHvIsmT1NcNnNVKYbETx6jEbGV3rVCuvqqNk2waErQ==} + engines: {node: '>=12'} + hasBin: true + dependencies: + camelcase: 6.3.0 + meow: 9.0.0 + progress: 2.0.3 + pumpify: 2.0.1 + replacestream: 4.0.3 + dev: false + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: false + + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: false + + /minimist-options@4.1.0: + resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} + engines: {node: '>= 6'} + dependencies: + arrify: 1.0.1 + is-plain-obj: 1.1.0 + kind-of: 6.0.3 + dev: false + + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: false + + /moize@6.1.6: + resolution: {integrity: sha512-vSKdIUO61iCmTqhdoIDrqyrtp87nWZUmBPniNjO0fX49wEYmyDO4lvlnFXiGcaH1JLE/s/9HbiK4LSHsbiUY6Q==} + dependencies: + fast-equals: 3.0.3 + micro-memoize: 4.1.2 + dev: false + + /moment-timezone@0.5.45: + resolution: {integrity: sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==} + dependencies: + moment: 2.30.1 + dev: false + + /moment@2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + dev: false + + /morgan@1.10.0: + resolution: {integrity: sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==} + engines: {node: '>= 0.8.0'} + dependencies: + basic-auth: 2.0.1 + debug: 2.6.9 + depd: 2.0.0 + on-finished: 2.3.0 + on-headers: 1.0.2 + transitivePeerDependencies: + - supports-color + dev: false + + /ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + dev: false + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: false + + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: false + + /negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + dev: false + + /nib@1.2.0(stylus@0.62.0): + resolution: {integrity: sha512-7HgrnMl/3yOmWykueO8/D0q+0iWwe7Z+CK2Eaq/xQV8w1hK80WN1oReRQkfkrztbAAnp/nTHkUSl5EcVkor6JQ==} + peerDependencies: + stylus: '*' + dependencies: + stylus: 0.62.0 + dev: false + + /no-case@2.3.2: + resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==} + dependencies: + lower-case: 1.1.4 + dev: false + + /no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + dependencies: + lower-case: 2.0.2 + tslib: 2.6.2 + dev: false + + /normalize-package-data@2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.8 + semver: 5.7.2 + validate-npm-package-license: 3.0.4 + dev: false + + /normalize-package-data@3.0.3: + resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} + engines: {node: '>=10'} + dependencies: + hosted-git-info: 4.1.0 + is-core-module: 2.13.1 + semver: 7.6.0 + validate-npm-package-license: 3.0.4 + dev: false + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: false + + /nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + dependencies: + boolbase: 1.0.0 + dev: false + + /nunjucks@3.2.4: + resolution: {integrity: sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==} + engines: {node: '>= 6.9.0'} + hasBin: true + peerDependencies: + chokidar: ^3.3.0 + peerDependenciesMeta: + chokidar: + optional: true + dependencies: + a-sync-waterfall: 1.0.1 + asap: 2.0.6 + commander: 5.1.0 + dev: false + + /nwsapi@2.2.9: + resolution: {integrity: sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==} + dev: false + + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: false + + /on-finished@2.3.0: + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} + engines: {node: '>= 0.8'} + dependencies: + ee-first: 1.1.1 + dev: false + + /on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + dependencies: + ee-first: 1.1.1 + dev: false + + /on-headers@1.0.2: + resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} + engines: {node: '>= 0.8'} + dev: false + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: false + + /open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + dev: false + + /p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + dependencies: + p-try: 2.2.0 + dev: false + + /p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + dependencies: + p-limit: 2.3.0 + dev: false + + /p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + dev: false + + /param-case@2.1.1: + resolution: {integrity: sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==} + dependencies: + no-case: 2.3.2 + dev: false + + /parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.24.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: false + + /parse5@7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + dependencies: + entities: 4.5.0 + dev: false + + /parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + dev: false + + /pascal-case@3.1.2: + resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} + dependencies: + no-case: 3.0.4 + tslib: 2.6.2 + dev: false + + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: false + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: false + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: false + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: false + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: false + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: false + + /pretty-hrtime@1.0.3: + resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} + engines: {node: '>= 0.8'} + dev: false + + /prismjs@1.29.0: + resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} + engines: {node: '>=6'} + dev: false + + /process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + dev: false + + /progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + dev: false + + /psl@1.9.0: + resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + dev: false + + /pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: false + + /pumpify@2.0.1: + resolution: {integrity: sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==} + dependencies: + duplexify: 4.1.3 + inherits: 2.0.4 + pump: 3.0.0 + dev: false + + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: false + + /querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + dev: false + + /quick-lru@4.0.1: + resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} + engines: {node: '>=8'} + dev: false + + /range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + dev: false + + /read-pkg-up@7.0.1: + resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} + engines: {node: '>=8'} + dependencies: + find-up: 4.1.0 + read-pkg: 5.2.0 + type-fest: 0.8.1 + dev: false + + /read-pkg@5.2.0: + resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} + engines: {node: '>=8'} + dependencies: + '@types/normalize-package-data': 2.4.4 + normalize-package-data: 2.5.0 + parse-json: 5.2.0 + type-fest: 0.6.0 + dev: false + + /readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: false + + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: false + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: false + + /redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + dev: false + + /relateurl@0.2.7: + resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==} + engines: {node: '>= 0.10'} + dev: false + + /replacestream@4.0.3: + resolution: {integrity: sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==} + dependencies: + escape-string-regexp: 1.0.5 + object-assign: 4.1.1 + readable-stream: 2.3.8 + dev: false + + /requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + dev: false + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: false + + /rfdc@1.3.1: + resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==} + dev: false + + /safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + dev: false + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false + + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: false + + /sax@1.3.0: + resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==} + dev: false + + /saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + dependencies: + xmlchars: 2.2.0 + dev: false + + /semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + dev: false + + /semver@7.6.0: + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: false + + /send@0.18.0: + resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} + engines: {node: '>= 0.8.0'} + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /serve-static@1.15.0: + resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} + engines: {node: '>= 0.8.0'} + dependencies: + encodeurl: 1.0.2 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.18.0 + transitivePeerDependencies: + - supports-color + dev: false + + /setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + dev: false + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: false + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: false + + /source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + engines: {node: '>=0.10.0'} + dev: false + + /source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: false + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: false + + /source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + dev: false + + /spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.17 + dev: false + + /spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + dev: false + + /spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.17 + dev: false + + /spdx-license-ids@3.0.17: + resolution: {integrity: sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==} + dev: false + + /sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + dev: false + + /sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + dev: false + + /statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + dev: false + + /statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + dev: false + + /stream-shift@1.0.3: + resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} + dev: false + + /string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + dependencies: + safe-buffer: 5.1.2 + dev: false + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: false + + /strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + dependencies: + min-indent: 1.0.1 + dev: false + + /stylus@0.62.0: + resolution: {integrity: sha512-v3YCf31atbwJQIMtPNX8hcQ+okD4NQaTuKGUWfII8eaqn+3otrbttGL1zSMZAAtiPsBztQnujVBugg/cXFUpyg==} + hasBin: true + dependencies: + '@adobe/css-tools': 4.3.3 + debug: 4.3.4 + glob: 7.2.3 + sax: 1.3.0 + source-map: 0.7.4 + transitivePeerDependencies: + - supports-color + dev: false + + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + dev: false + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: false + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: false + + /svgo@3.2.0: + resolution: {integrity: sha512-4PP6CMW/V7l/GmKRKzsLR8xxjdHTV4IMvhTnpuHwwBazSIlw5W/5SmPjN8Dwyt7lKbSJrRDgp4t9ph0HgChFBQ==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + '@trysound/sax': 0.2.0 + commander: 7.2.0 + css-select: 5.1.0 + css-tree: 2.3.1 + css-what: 6.1.0 + csso: 5.0.5 + picocolors: 1.0.0 + dev: false + + /symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + dev: false + + /terser@5.30.4: + resolution: {integrity: sha512-xRdd0v64a8mFK9bnsKVdoNP9GQIKUAaJPTaqEQDL4w/J8WaW4sWXXoMZ+6SimPkfT5bElreXf8m9HnmPc3E1BQ==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.6 + acorn: 8.11.3 + commander: 2.20.3 + source-map-support: 0.5.21 + dev: false + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: false + + /through2@4.0.2: + resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} + dependencies: + readable-stream: 3.6.2 + dev: false + + /tildify@2.0.0: + resolution: {integrity: sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==} + engines: {node: '>=8'} + dev: false + + /titlecase@1.1.3: + resolution: {integrity: sha512-pQX4oiemzjBEELPqgK4WE+q0yhAqjp/yzusGtlSJsOuiDys0RQxggepYmo0BuegIDppYS3b3cpdegRwkpyN3hw==} + hasBin: true + dev: false + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: false + + /toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + dev: false + + /tough-cookie@4.1.3: + resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} + engines: {node: '>=6'} + dependencies: + psl: 1.9.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + dev: false + + /tr46@3.0.0: + resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} + engines: {node: '>=12'} + dependencies: + punycode: 2.3.1 + dev: false + + /trim-newlines@3.0.1: + resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} + engines: {node: '>=8'} + dev: false + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + dev: false + + /type-fest@0.18.1: + resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==} + engines: {node: '>=10'} + dev: false + + /type-fest@0.6.0: + resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} + engines: {node: '>=8'} + dev: false + + /type-fest@0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + dev: false + + /uglify-js@3.17.4: + resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} + engines: {node: '>=0.8.0'} + hasBin: true + dev: false + + /universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + dev: false + + /unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + dev: false + + /upper-case@1.1.3: + resolution: {integrity: sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==} + dev: false + + /url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + dev: false + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: false + + /utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + dev: false + + /validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + dev: false + + /vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + dev: false + + /w3c-xmlserializer@4.0.0: + resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} + engines: {node: '>=14'} + dependencies: + xml-name-validator: 4.0.0 + dev: false + + /warehouse@5.0.1: + resolution: {integrity: sha512-5BQEQP56bPY+cqocTho4syazuGgSoyKd0y3PsS2j8tGN10HH+CEfJSIY+KUw9D0k4jaVEFMXLz0KqCiUzTYb8A==} + engines: {node: '>=14'} + dependencies: + bluebird: 3.7.2 + cuid: 2.1.8 + graceful-fs: 4.2.11 + hexo-log: 4.1.0 + is-plain-object: 5.0.0 + jsonparse: 1.3.1 + rfdc: 1.3.1 + through2: 4.0.2 + dev: false + + /webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + dev: false + + /whatwg-encoding@2.0.0: + resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} + engines: {node: '>=12'} + dependencies: + iconv-lite: 0.6.3 + dev: false + + /whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + dev: false + + /whatwg-url@11.0.0: + resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} + engines: {node: '>=12'} + dependencies: + tr46: 3.0.0 + webidl-conversions: 7.0.0 + dev: false + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: false + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: false + + /ws@8.16.0: + resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + + /xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + dev: false + + /xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + dev: false + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: false + + /yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + dev: false diff --git a/scaffolds/draft.md b/scaffolds/draft.md new file mode 100644 index 00000000..498e95ba --- /dev/null +++ b/scaffolds/draft.md @@ -0,0 +1,4 @@ +--- +title: {{ title }} +tags: +--- diff --git a/scaffolds/page.md b/scaffolds/page.md new file mode 100644 index 00000000..f01ba3cd --- /dev/null +++ b/scaffolds/page.md @@ -0,0 +1,4 @@ +--- +title: {{ title }} +date: {{ date }} +--- diff --git a/scaffolds/post.md b/scaffolds/post.md new file mode 100644 index 00000000..1f9b9a46 --- /dev/null +++ b/scaffolds/post.md @@ -0,0 +1,5 @@ +--- +title: {{ title }} +date: {{ date }} +tags: +--- diff --git a/source/_posts/1panel-installation-and-usage-tutorial.md b/source/_posts/1panel-installation-and-usage-tutorial.md new file mode 100644 index 00000000..ae843cec --- /dev/null +++ b/source/_posts/1panel-installation-and-usage-tutorial.md @@ -0,0 +1,102 @@ +--- +title: 1Panel 安装配置教程 +tags: + - 1Panel + - 运维 + - 服务器 + - 部署 +abbrlink: 15c02856 +date: 2023-12-28 15:54:04 +--- + +{% note primary %} +本文旨在介绍 `1Panel` 的安装和基本使用,以及一些常用的功能和技巧。 +{% endnote %} + +## 1. 什么是 `1Panel`,为什么要使用它? + + +![1panel 的官网简介](https://pic4.zhimg.com/80/v2-d303c292b709c8702e3537ed161009d7_1440w.webp) + +
+ +[1Panel](https://github.com/1Panel-dev/1Panel) 是一个现代化、开源的 **服务器管理面板**,封装了很多常用的操作,比如安装软件、配置反向代理、申请 SSL 证书等等。UI 界面好看,操作也很简单。是宝塔面板的一个很好的替代品。 + +1Panel 在线体验:[https://demo.1panel.cn](https://demo.1panel.cn) + +## 2. 安装 `1Panel` + +开始之前先确保你的服务器安装了 `curl` + +### 2.1 执行安装脚本 + +ssh 连接到你的服务器,执行下面的命令,安装 1panel。过程会输出很多日志信息,等待安装完成即可。 +```bash +curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh +``` +### 2.2 安装配置 +命令行提示输入 安装目录,敲回车,默认安装路径为 `/opt/1panel`. +![安装目录](https://pic4.zhimg.com/80/v2-eb429def76fbfb36e4f687b775943eeb_1440w.webp) + +命令行提示输入 端口,用户名,密码。这里可以自定义,也可以直接回车使用默认值。 +![输入信息](https://pic2.zhimg.com/80/v2-5b8e8453a01ec99e11d39690bfb4b469_1440w.webp) + +### 2.3 安装完成 +记住 1panel 面板生成的 **`端口号`** 和 **`账号密码`** +注意,如果你的服务器供应商有防火墙,记得开放 1panel 的端口。 + +如果没有什么报错的话,那么恭喜你,1panel 已经安装成功了。 + +### 2.4 登陆 1panel 面板 +我们可以从命令行输出的信息中找到 `外网地址`,如下图所示。 +![登陆信息](https://pic2.zhimg.com/80/v2-1a55a84f560aac043c1e43623cf08739_1440w.webp) + +使用浏览器访问 命令行输出的 `外网地址` 就可以登陆 1panel 面板了。 +![登陆界面](https://pic4.zhimg.com/80/v2-8805f288fd97f192d0ac30e389079043_1440w.webp) + +输入账号密码 登陆以后我们可以看到 1panel 的界面。 +![1panel 首页](https://pic1.zhimg.com/80/v2-b9b93ab5e5ec5c6a7fecade5b617dec4_1440w.webp) + +首页显示的是`服务器的基本信息`,我们可以看到服务器的内存、cpu、硬盘、负载、系统的发行版本、内核、主机名等信息。 + +点击应用商店,这里有 1panel 社区维护的一些应用,我们可以直接安装使用。 +应用商店包括了一些很热门的应用和开源项目 如:`AList` `MySQL` `Bitwarden` `WordPress` `Umami` `Uptime Kuma` `Jenkins` `Redis` `MongoDB` `PostgreSQL` 等等。都是运行在 docker 容器中的,安装和卸载都很方便。 +![应用商店](https://pic2.zhimg.com/80/v2-23de72dbdaaccb84c8b6e40b83c6a159_1440w.webp) + +## 3. 安装 `openresty` 应用 + +我们选择安装 `openresty`,`安装` -> `确认` 即可。`openresty` 是 nginx 的开源 fork,支持 lua 脚本,安装了它才能在 1panel 编辑网页、配置反向代理。 + +![openresty](https://pic1.zhimg.com/80/v2-3ec6423285e4bf9ec5c94c948aea4bb8_1440w.webp) +不要修改配置!直接点确定即可。 + +## 4. 设置域名解析 +域名服务商设置域名解析,将 `域名` 解析到服务器的 `IP` 上。 +![域名解析](https://pic3.zhimg.com/80/v2-319ce2637512c2c64b7f64136d60b8ca_1440w.webp) + +## 5. 配置反向代理 +点击网页左侧的 `网站`,然后点击 `创建网站`,选择反向代理,填入主域名和代理地址,点击确认。 + +![反向代理](https://pic3.zhimg.com/80/v2-fb495404d4641ff7a789dec2c45225c2_1440w.webp) + +配置好后,就可以使用域名访问 1panel 面板了。 + +## 6. 配置域名 SSL 证书 + +### 6.1 创建 ACME 账户 + +`网站` -> `证书` -> `ACME 账户` -> `创建账户`,填入邮箱地址,点击确认。 + +![创建 ACME 账户](https://pic3.zhimg.com/80/v2-0eddfef77e614c09f57ca8e9b32992c6_1440w.webp) + +### 6.2 申请证书 + +`网站` -> `证书` -> `申请证书`,填入主域名,选择 ACME 账户,验证方式选择 `HTTP`,勾选 `自动续签`,点击确认。你就可以在 `证书` 页面看到你的证书了。 + +![申请证书](https://pic4.zhimg.com/80/v2-a41668e2d037b4d107e2cf7c3912ccd3_1440w.webp) + +### 6.3 配置证书 + +`网站` -> 找到你的网站,点击 `编辑`,点击 `HTTPS` 并启用,选择你的证书,点击保存。 + +![配置证书](https://pic1.zhimg.com/80/v2-bdcaa006f53c65672ad3358285e13f74_1440w.webp) diff --git a/source/_posts/2024-happy-new-year.md b/source/_posts/2024-happy-new-year.md new file mode 100644 index 00000000..a64456ff --- /dev/null +++ b/source/_posts/2024-happy-new-year.md @@ -0,0 +1,12 @@ +--- +title: '2024, Happy New Year!' +tags: + - 日常 +abbrlink: 1c0214de +date: 2024-01-01 00:19:00 +--- + +祝大家元旦快乐!!! +虽然今年并不一帆风顺,但新的一年还是要开心啊! +![2024](https://pic1.zhimg.com/80/v2-9b61bc53f9b1d5709685d6c91909f5d0_1440w.webp) +![bing-wallpaper-fireworks](https://pic4.zhimg.com/80/v2-d4fccb20b739c6b799f25d9d63e14c03_1440w.webp) \ No newline at end of file diff --git a/source/_posts/Baidu-show-308-jump-in-Cloudflare-page.md b/source/_posts/Baidu-show-308-jump-in-Cloudflare-page.md new file mode 100644 index 00000000..64590993 --- /dev/null +++ b/source/_posts/Baidu-show-308-jump-in-Cloudflare-page.md @@ -0,0 +1,54 @@ +--- +title: 百度收录 Cloudflare Page 显示 308 报错 +tags: + - Cloudflare-Page + - Baidu + - SEO +abbrlink: e7163e6b +date: 2024-03-10 16:06:57 +--- + +{% note success %} +我前阵子决定将博客迁移到 Cloudflare Page 上,但在使用 Cloudflare Page 遇到了一个问题,就是百度收录使用 `.html 验证网站所有权` 会显示网页 308 跳转报错。我一开始还以为是百度的问题,千方百计地设法解决但是都徒劳无功,后来才发现是 Cloudflare Page 的问题。 + +Google 和 百度都没有发现这个解决办法,所以自己写一篇文章来记录一下。 +{% endnote %} + +## 1. 问题描述 + +百度验证所有权有两种方式: +1. 文件验证:下载百度提供的 `.html` 验证文件,放置在网站根目录下。 +2. HTML 标签验证:在网站首页的 `` 标签中添加一个特定的 meta 标签,内容由百度提供。 + +问题出在 `文件验证` 上: +**Cloudflare Page 会将 `.html 文件请求` 重定向到 `去掉 .html 后缀的地址` 。导致百度收录网站时显示网页 308 跳转。** + +![百度报错 308](https://pic4.zhimg.com/80/v2-9b2591438a5d35d8ee4ca6e0da4d4f8f_1440w.webp) + +如 `https://www.ovvv.top/baidu_verify_codeva-xxx.html` 会自动重定向到 `https://www.ovvv.top/baidu_verify_codeva-xxx`。 + +![重定向,没有 .html 后缀](https://pic1.zhimg.com/80/v2-d1aad73842196ad68566de57ef0b75e8_1440w.webp) + +直接点击浏览器访问 `https://www.ovvv.top/xxx.html` 是看不出问题的,因为浏览器会自动重定向到 `https://www.ovvv.top/xxx`。但是百度收录使用 .html 验证网站所有权时,会显示网页 308 跳转。 + + +## 2. 解决办法 + +在 `Cloudflare Community` 暂时没有找到`完美的解决办法`,工作人员表示这是 Cloudflare Page 的特性,`暂时还不会提供开关`。 + +文档描述:https://developers.cloudflare.com/pages/configuration/serving-pages/#route-matching + + +解决办法(workaround): + +1. 在文件后面加上 `.html` 后缀,两层 `.html` 嵌套,Cloudflare Page 重定向后就会显示 一层 `.html`。 +如 Cloudflare Page 文件链接为 `https://www.ovvv.top/xxx.html.html`。这样访问后重定向后就会显示 `https://www.ovvv.top/xxx.html`。符合百度验证的要求。 + + ![加后缀显示](https://pic3.zhimg.com/80/v2-1ca3f5b3bec86e96558b00e51c8aed12_1440w.webp) + +2. 使用 `HTML标签验证` 网站所有权。(但是不够优雅,因为每个网页都要加上) + + ![标签验证](https://pic4.zhimg.com/80/v2-6f78f82328de1e68d8537e00143b3b63_1440w.webp) + +验证成功 +![成功](https://pic3.zhimg.com/80/v2-a39791cb2b2b2858e403801fb71af9b6_1440w.webp) diff --git a/source/_posts/Blog-seo-optimization.md b/source/_posts/Blog-seo-optimization.md new file mode 100644 index 00000000..0d335348 --- /dev/null +++ b/source/_posts/Blog-seo-optimization.md @@ -0,0 +1,134 @@ +--- +title: 博客 SEO 优化 +abbrlink: d6d74ca +date: 2024-01-28 12:56:50 +tags: + - SEO +--- + +> 写博客的目的是为了记录自己的学习过程与分享日常。 +> 而想要让更多的人看到自己的博客,就需要做一些 SEO 优化,提升自己的博客在搜索引擎上的排名。 + +## 0. 提升文章内容质量 + +SEO 优化的第一步就是提升你的文章内容质量。**搜索引擎会根据你的文章内容来判断你的网站的质量,优质的文章内容可以提升你的网站在搜索引擎中的排名**。如果你的文章内容质量不高或者同质化严重,那么你的网站在搜索引擎中的排名就会很低,甚至根本不会被搜索引擎收录。 + +所以,**文章优化是 SEO 优化的重中之重!!!** + +## 1. 网页关键词和描述 + +在你的博客中,你需要一些 `关键词` 和 `描述` 来帮助搜索引擎索引你的网页,比如你的博客是关于前端的,那么你的`关键词`可以是 `前端`、`JavaScript`、`Vue`、`React` 等等。`描述` 会在搜索引擎中显示,所以你需要一个简洁明了的描述来吸引用户点击。 + +在 Hexo 的 `_config.yml` 文件中,你可以配置你的关键词和描述。 + +```yml +# Site +title: 漠北残月的博客 +subtitle: '技术与生活' +description: '这是一个前端博客,分享前端开发经验' +keywords: '前端, JavaScript, Vue, React' +``` + +
+ +如果你的博客不是 Hexo,请参考你所使用的博客框架的文档,找到你的关键词和描述的配置文件。否则,你也可以手动在你的网页的 `` 标签中添加关键词和描述。 + +```html + + +``` + +## 2. 生成 sitemap.xml + +`sitemap.xml` 是存储网站所有页面链接的文件,搜索引擎可以通过这个文件来爬取你的网站。有助于搜索引擎更好的了解你的网站结构,提高你的网站在搜索引擎中的排名。生成 `sitemap.xml` 文件也是 SEO 优化的一个重要步骤。 + +如果你的博客是 Hexo,那么你可以使用 `hexo-generator-sitemap` 插件来生成 `sitemap.xml` 文件: + +```bash +npm install hexo-generator-sitemap --save +``` + +然后执行 + +```bash +hexo clean && hexo generate +``` + +就可以在 public 目录下看到 sitemap.xml 文件了。 + +## 3. 配置 robots.txt + +`robots.txt` 是一个文本文件,它告诉搜索引擎爬虫哪些页面可以爬取,哪些页面不可以爬取。 + +在 `source` 目录下新建 `robots.txt` 文件,内容如下: + +```txt +User-agent: * +Disallow: + +Sitemap: https://example.com/sitemap.xml +``` + +User-agent: `*` 表示允许所有的搜索引擎爬取你的网站。 +Disallow: 为空 表示 `不限制` 爬取。如果你想限制搜索引擎爬取某些页面,可以在 Disallow 后面添加你不想让搜索引擎爬取的页面,比如 `Disallow: /admin` 表示不让搜索引擎爬取你的 admin 页面。 +Sitemap: 后面的链接是你的 sitemap.xml 文件的链接,这样搜索引擎就可以通过 sitemap.xml 文件来爬取你的网站了。 + +## 4. 搜索引擎提交 +搜索引擎提交可以帮助你的网站更快的被搜索引擎收录,一般来说,搜索引擎会自己爬取你的网站,但是你可以手动提交你的网站,这样可以更快的被收录。 + +进平台验证一下域名所有权即可 + +### 4.1 百度 +百度搜索资源平台:https://ziyuan.baidu.com/site/index +![百度搜索资源平台](https://pic1.zhimg.com/80/v2-be8824f3d8967c9e5ede5f3e99a29c30_1440w.webp) + +百度收录特别慢,可能需要几天到几个月,不要着急,耐心等待。 + +### 4.2 Google +不出意外,谷歌是会自己爬取你的网站的,但是你可以通过谷歌搜索控制台来查看你的网站的爬取情况、优化你的网站内容、提交站点地图等等。 + +谷歌搜索控制台:https://search.google.com/search-console?hl=zh-CN +建议不要添加整个域名,而是添加你的网站的子域名,比如 `blog.example.com`,这样你可以更好的管理你的网站。如果你添加了整个域名,那么一些你并不想让谷歌爬取的子域名网页也会被收录。 +![添加域名](https://pic4.zhimg.com/80/v2-8a507fbbea8eaaa4addb820bd8b98d77_1440w.webp) +![谷歌搜索控制台](https://pic4.zhimg.com/80/v2-ab27f59a037d0b8dd0b90004786cc317_1440w.webp) + +### 4.3 Bing +不出意外,必应也会自己爬取你的网站。 + +必应站长平台:https://www.bing.com/webmasters + +必应添加域名可以选择 `从谷歌搜索控制台导入` 或者 `手动添加` +![添加域名](https://pic2.zhimg.com/80/v2-3df1cb8e39277613c8d7cb25ef008911_1440w.webp) +![从谷歌控制台导入](https://pic2.zhimg.com/80/v2-436a8e937842698429e0ad6a33c5d0b1_1440w.webp) +![必应站长平台](https://pic4.zhimg.com/80/v2-7428d71d65c2a7b10547f140353170ef_1440w.webp) + +### 4.4 Naver +Naver 是韩国本土的搜索引擎,类似于国内的百度,不会像 Google, Bing 那样自动收录你的网站。如果有需要,可以注册一个 Naver 账号,然后提交你的网站。 + +站长平台:https://searchadvisor.naver.com/console/board +![验证所有权](https://pic4.zhimg.com/80/v2-bfc7629a38b62d8b3cf20d4246961ea7_1440w.webp) +建议使用 `在根目录添加 html` 来验证所有权 + +接下来就是提交站点地图了,点击你添加成功的网站,提交站点地图,步骤和前面的谷歌必应差不多。 +![提交站点地图](https://pic1.zhimg.com/80/v2-013f0170ff14a43711fdd8c20bcda004_1440w.webp) + + +### 4.5 其他搜索引擎 + +Yandex、DuckDuckGo、Yahoo 等搜索引擎会自动爬取你的网站,不需要去站长手动提交(不主流,没啥必要)。 + +## 5. 优化性能 + +性能优化是 SEO 优化的重要一环,一个网站的性能好坏直接影响到用户体验,也会影响到搜索引擎对你网站的评价。 + +访问 https://pagespeed.web.dev/ 输入你的网站地址,就可以看到你的网站的性能了。根据提示来优化你的网站。当然,这只是一个参考,你可以根据自己的需求来优化你的网站。 + +比如说你的博客主要针对国内用户,那么你可能会用国内的静态资源 CDN 来加速你的网站,比如七牛、BootCDN、baomitu、字节 等等。这种对于用户体验是有帮助的。但是这些 CDN 往往没有优化国外节点,`PageSpeed Insights` 是谷歌的检测网页用户体验工具,可能就不会给你很高的分数。所以,分数只是一个参考,你可以根据自己的需求来优化你的网站。 + +## 6. 外链与反链 + +外链(Outbound Links)指的是从你的网站指向其他网站的链接。这些链接可以是指向其他网页、博客、文章或任何在线资源的链接。外链对于提高你的网站在搜索引擎中的排名以及增加网站的可信度和权威性都非常重要。 + +反链(Backlinks)则是指其他网站指向你的网站的链接。这些链接也被称为入站链接,它们对于搜索引擎优化(SEO)来说非常重要,因为搜索引擎认为其他网站指向你的网站意味着你的网站有价值和权威性。有更多的反链通常意味着你的网站在搜索引擎结果中的排名会更高。 + +在博客和网站的运营中,外链和反链都是重要的考虑因素。通过外链可以引导读者到其他有用的资源,提供更丰富的内容体验;而反链则是其他网站认可你网站内容的一种方式,有助于提高你的网站在搜索引擎中的排名和曝光度。 diff --git a/source/_posts/Caddy-installation-and-usage-tutorial.md b/source/_posts/Caddy-installation-and-usage-tutorial.md new file mode 100644 index 00000000..e189975c --- /dev/null +++ b/source/_posts/Caddy-installation-and-usage-tutorial.md @@ -0,0 +1,238 @@ +--- +title: Caddy 安装与使用教程 +tags: + - Caddy + - 部署 + - 运维 +abbrlink: f3ac7ef6 +date: 2024-03-04 04:56:00 +--- +![caddy](https://pic4.zhimg.com/80/v2-653b9bf7506493ee27ff68e6107aeff7_1440w.webp) + +{% note secondary %} +Caddy 是一个现代化的 Web 服务器,具有自动 HTTPS、HTTP/3、反向代理、负载均衡、静态文件服务等功能。Caddy 的设计理念是简单易用,它的配置文件采用 Caddyfile 格式,非常直观和易懂。Caddy 采用 Go 语言编写,性能优异,占用资源少,适合用于各种 Web 服务的搭建。 +{% endnote %} + +Nginx 是一个被广泛使用的 Web 服务器,但是它的配置相对 Caddy 更复杂,自动申请和更新 HTTPS 证书也是痛点,需要借助 Certbot 等工具来实现。而 Caddy 则内置了自动 HTTPS 功能,只需要简单的三行配置就可以实现 HTTPS 访问。 + +本文将介绍 Caddy 的安装和基本配置,以及一些常用的功能和技巧。以 Debian12 为例,其他 Linux 发行版的安装方法类似。假设你已经拥有一个域名和一台能联网的服务器。 + + +## 1. 安装 Caddy + +输入以下命令安装 Caddy: +```bash +sudo apt update +sudo apt install caddy -y +``` + +安装完成后,可以使用以下命令检查 Caddy 的版本: +```bash +caddy version +``` +当前教程演示的 Caddy 版本是 `2.6.2`。 + + +## 2. 启动 Caddy + +安装完成后,Caddy 会自动启动。可以使用以下命令检查 Caddy 服务的状态: +```bash +sudo systemctl status caddy +``` +如果输出中显示 `Active: active (running)`,则表示 Caddy 已成功启动。 + +如果 Caddy 未启动,可以根据报错信息排查问题,解决后尝试手动启动 Caddy: +```bash +sudo systemctl start caddy +``` + +现在,可以在浏览器中输入服务器的 IP 地址或域名,就会看到 Caddy 的默认欢迎页面。 +![Caddy 欢迎页](https://pic4.zhimg.com/80/v2-dc5e989ddde90bfd11122d6f74f2ccaf_1440w.webp) + + +## 3. 了解 Caddy + +### 3.1 Caddy 的配置文件 +Caddy 有两种配置方式,一种是使用 `Caddyfile`,另一种是使用 JSON 配置文件。Caddyfile 是为 Caddy 设计的配置文件,它的语法简单易懂,适合快速上手。JSON 配置文件则更加灵活,适合复杂的配置需求。 + +![Caddyfile vs json](https://pic3.zhimg.com/80/v2-13bdf74fced58067242e3c776eb5dcfe_1440w.webp) + +Caddyfile 默认位置是 `/etc/caddy/Caddyfile`。但也可以使用 `-conf` 参数指定配置文件的位置: +```bash +caddy run -conf /path/to/Caddyfile +``` + + +### 3.2 Caddy 常用命令 +Caddy 提供了一些常用的命令,可以用来管理 Caddy 服务。以下是一些常用的命令: +- `caddy start`:在后台启动 Caddy 进程,然后返回 +- `caddy stop`:优雅地停止已启动的 Caddy 进程 +- `caddy run`:在前台启动 Caddy 进程,然后阻塞 +- `caddy reload`:更改运行中的 Caddy 实例的配置 +- `caddy validate`:测试配置文件是否有效 +- `caddy version`:显示 Caddy 的版本信息 +- `caddy reverse-proxy`:反向代理 +- `caddy file-server`:启动一个生产就绪的文件服务器 +- `caddy respond`:用于开发和测试的简单、硬编码 HTTP 响应 + + +## 4. 配置网站 + +我们现在演示如何配置 `example.com`,使得访问 `example.com` 就会显示 `Hello World !` 页面。 + +假设你的域名为 `example.com`,且在域名供应商域名解析处已经将 `example.com` 解析到服务器的 IP 地址。 + + +### 4.1 创建网站根目录 + +`/var/www` 目录通常用于存放网站文件,我们可以在这个目录下创建一个目录,用于存放 `example.com` 的网站文件。 + +```bash +sudo mkdir -p /var/www/example.com +``` +并在其中创建一个 `index.html` 文件: +```bash +sudo vim /var/www/example.com/index.html +``` + +将以下内容粘贴到 `index.html` 文件中: +{% fold info @html 代码 %} +```html + + + + + + 漠北残月 + + +

Hello World !

+ + +``` +{% endfold %} +保存并退出编辑器。 + + +### 4.2 编辑 Caddyfile + +Caddyfile 默认位置是 `/etc/caddy/Caddyfile`,可以使用以下命令编辑 Caddyfile: +```bash +sudo vim /etc/caddy/Caddyfile +``` + +将以下内容粘贴到文件中: +```Caddyfile +example.com { + root * /var/www/example.com + file_server +} +``` +保存并退出编辑器。 + +- `example.com`:域名 +- `root * /var/www/example.com`:文档根目录 +- `file_server`:文件服务器 + +这样,Caddy 就会监听 `example.com` 的请求,并返回 `/var/www/example.com` 目录下的文件。 + +注意:如果你的地址包含主机名或 IP 地址,则 Caddy 会启用自动 HTTPS。不过,这种行为是隐式的,因此不会覆盖任何显式配置。 +例如,如果网站地址是 [http://example.com](http://example.com),自动 HTTPS 将不会激活,因为该方案是明确的 http://。 + + +### 4.3 重新加载 Caddy 配置 + +编辑完成 Caddyfile 后,需要重新加载 Caddy 配置: +```bash +sudo systemctl reload caddy +``` + +现在,可以在浏览器中输入 `example.com`,就会看到 `Hello World !` 页面。 +![Hello World](https://pic1.zhimg.com/80/v2-9f1df44eb736c0f0f0e852a6f8aeac98_1440w.webp) + +我们可以注意到,浏览器访问了 `https://example.com`,Caddy **自动为网站申请了 HTTPS 证书!**,并且**自动重定向到了 HTTPS**。这是 Caddy 的自动 HTTPS 功能,非常简单方便!!! + + +## 5. 配置反向代理 + +![反向代理](https://pic4.zhimg.com/80/v2-23767a77ae76b8280a695bb3ff45f3eb_1440w.webp) + +Caddy 的反向代理是我们常用到的功能,它可以隐藏真实服务器地址,提高安全性,还可以实现负载均衡和缓存等功能。 + +假设你的域名为 `website.com`,并且你的服务器上有一个运行在 8080 端口的应用程序,你希望用户通过 `website.com` 访问这个应用程序,而不是通过 `website.com:8080` 直接访问。 +![没反向代理的网站](https://pic2.zhimg.com/80/v2-8daac8f8ba3b016f1eeb570f4c092af1_1440w.webp) +![反向代理过的网站](https://pic4.zhimg.com/80/v2-336d8da792bb9f774abb3c42a18fd2a3_1440w.webp) + +那么,可以在 Caddyfile 中添加以下内容: +```Caddyfile +website.com { + reverse_proxy localhost:8080 +} +``` +保存并退出编辑器。 + +- `website.com`:域名 +- `reverse_proxy localhost:8080`:将请求转发给 127.0.0.1:8080 端口来处理 + +重新加载 Caddy 配置: +```bash +sudo systemctl reload caddy +``` + +现在,可以在浏览器中输入 `website.com`,就会访问到运行在 8080 端口的应用程序。 + +![反向代理](https://pic4.zhimg.com/80/v2-336d8da792bb9f774abb3c42a18fd2a3_1440w.webp) + +由此可见,Caddy 的配置非常简单,而且功能强大,适合用于各种 Web 服务的搭建。比 Nginx 简单了太多。 + +比如这是两个 Nginx 的反向代理配置文件: +```nginx +server { + listen 80; + server_name app1.website.com; + + location / { + proxy_pass http://127.0.0.1:8081; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} + +server { + listen 80; + server_name app2.website.com; + + location / { + proxy_pass http://127.0.0.1:8082; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + +这个是 Caddy 的配置: +```Caddyfile +app1.website.com { + reverse_proxy http://127.0.0.1:8081 { + header_up Host {host} + header_up X-Real-IP {remote} + header_up X-Forwarded-For {remote} + header_up X-Forwarded-Proto {scheme} + } +} + +app2.website.com { + reverse_proxy http://127.0.0.1:8082 { + header_up Host {host} + header_up X-Real-IP {remote} + header_up X-Forwarded-For {remote} + header_up X-Forwarded-Proto {scheme} + } +} +``` + +更多 Caddy 的配置和功能,可以参考官方文档:[Caddy Documentation](https://caddyserver.com/docs) diff --git a/source/_posts/Deploy-a-springboot-project-to-server.md b/source/_posts/Deploy-a-springboot-project-to-server.md new file mode 100644 index 00000000..19ac9864 --- /dev/null +++ b/source/_posts/Deploy-a-springboot-project-to-server.md @@ -0,0 +1,196 @@ +--- +title: 记录一次服务器部署 SpringBoot 项目的过程 +tags: + - Java + - SpringBoot + - MariaDB + - 部署 + - 运维 +abbrlink: e9bc4027 +date: 2024-04-15 15:08:16 +--- + +我毕业设计做的是 `SpringBoot` 前后端结合项目,项目开发完成后,需要将项目部署到服务器上,以便在公网访问。我想尝试一下真正的项目部署流程,即使毕设并没有要求我部署到服务器上。 + +{% note info %} +不同于以往相对严谨的科普教程,本文偏向于整理一个大概的 SpringBoot 项目部署流程框架,内容也会轻松随意些。如有谬误之处,欢迎指正。 +{% endnote %} + +## 1. 准备工作 + +### 1.1 开发环境梳理 + +检查一下各个开发环境的版本,以便在服务器上安装环境时参考: + +开发系统:`Archlinux` +服务器系统:`Debian-12.5` + +**开发工具:** +开发软件:`IntelliJ IDEA 2024.1` +图形化数据库管理工具:`Beekeeper-studio v4.2.9` + +**开发框架:** +Java 环境:`OpenJDK version 21.0.2` +Springboot 版本:`3.2.4` +MariaDB 数据库:`11.3.2` + +### 1.2 备份数据库 +这里我直接将开发时使用的数据库备份导入到服务器上,方便省事。 +MariaDB 数据库备份命令: +```bash +mariadb-dump -u root -p database_name > bak.sql +``` +上述命令执行完毕,我们就可以在目录下找到备份好的 `bak.sql` 文件了。 + +### 1.3 打包图片资源 + +项目需要使用一些图片资源,要打包上传到服务器上。 + +执行以下命令: +```bash +tar -caf images.tar.zst images +``` +这里我使用了 `zstd` 压缩算法,是一种压缩效率很高、压缩速度也很快的算法。压缩后的文件名为 `compress.tar.zst`。 + +- `-caf` 压缩指定文件或文件夹,自动选择压缩算法 +- `images` 要压缩的文件夹 +- `images.tar.zst` 压缩后的文件名 + +## 2. 打包 SpringBoot 项目 + +在 `IntelliJ IDEA` 中,点击右侧栏的 `Maven` 展开找到 `Lifecycle`,先双击执行 `clean`,再执行 `package` 进行打包。 +当然,你也可以在终端中执行 `mvn clean package` 命令来打包,这和在 `IDEA` 中执行的效果是一样的。 + +![构建 jar 包](https://pic1.zhimg.com/80/v2-014016435bdec1ee44f103ced9db2dd0_1440w.webp) + +执行完毕后我们就可以在项目的 `target` 目录下找到打包好的 `jar` 包了。 + +![找到 jar 包](https://pic2.zhimg.com/80/v2-8a1ec89db3eee3c40a435a524c86ffc9_1440w.webp) + +## 3. 上传到服务器 + +现在开始把 数据库备份文件、`jar` 包、图片资源压缩包 上传到服务器上。我是通过 `1Panel` 面板上传的。 + +你也可以通过 `scp` 命令上传文件到服务器上。 + +```bash +scp -P 22 /path/to/local/file username@server:/path/to/remote/file +``` +- `-P` 指定端口 +- `/path/to/local/file` 本地文件路径 +- `username` 服务器用户名 +- `server` 服务器地址 +- `/path/to/remote/file` 服务器文件路径 + +## 4. 服务器配置 + +既然要在服务器上运行项目,那么服务器就要安装并配置和本地开发环境一样的运行环境。 + +### 4.1 安装 Java 环境 + +值得一提的是 `OpenJDK 21` 正式版于 `2023/09/19` 发布[^1],距今(`2024/04/17`)已经半年多了。但 Debian 这个老顽固 `stable` 源迟迟未能更新至 `OpenJDK 21`,至今还在 `testing` 源中测试。`stable` 源目前仅提供 `OpenJDK 17`。 + +![openjdk21 的计划表](https://pic3.zhimg.com/80/v2-f5959e59c01a9a22098ed2861d0e6cf2_1440w.webp) + +![仍位于 testing 源的 openjdk21](https://pic4.zhimg.com/80/v2-376f2c6779b47f9127ceb781d4868257_1440w.webp) + +不禁想起一个笑话:`Debian stable = Debian stale`.[^2] + +
+ +为了项目运行,我只能开启 `testing` 源来安装 `OpenJDK 21`. +输入以下命令,修改 `/etc/apt/sources.list` 文件,将 `testing` 加到源中: +```bash +sudo vim /etc/apt/sources.list +``` + +我们会看到 `bookworm`, `bookworm-security`, `bookworm-updates` 三个源,但只需要修改 `bookworm` 源即可,`bookworm` 是 Debian 12 的开发代号,你可以根据你的系统版本修改。 + +找到 +```bash +deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware +deb-src http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware +``` + +在 `bookworm` 前面加上 `testing`,变成: +```bash +deb http://deb.debian.org/debian testing bookworm main contrib non-free non-free-firmware +deb-src http://deb.debian.org/debian testing bookworm main contrib non-free non-free-firmware +``` + +### 4.2 安装 MariaDB 数据库 + +一开始项目启动时我甚至还忘记装 `mariadb`。一看报错:无法连接数据库数据库,我才想起来。 +所以切记要先安装数据库再启动项目。 + +输入以下命令安装 `mariadb` 数据库: +```bash +sudo apt install mariadb-server -y +``` + +### 4.3 配置数据库 + +输入以下命令配置数据库: +```bash +sudo mariadb-secure-installation +``` +这里的具体配置参考我往期文章:[在 Archlinux 上安装使用 MariaDB](https://blog.ovvv.top/posts/53c8336d/#4-%E9%85%8D%E7%BD%AE-MariaDB). + +数据库密码注意要修改为 Springboot 项目配置 `application.yml` 中对应的密码。 + +### 4.3 导入数据库 + +输入以下命令连接数据库: +```bash +mariadb -u root -p +``` + +创建数据库,这里的 `database_name` 要和 `application.yml` 中配置的数据库名一致: +```sql +CREATE DATABASE database_name; +``` + +导入数据库: +```mariadb +use database_name; +source /path/to/bak.sql; +``` + +### 4.4 解压图片资源 + +解压我们上传的图片资源到 `application.yml` 配置的路径下: + +```bash +tar -xf images.tar.zst -C /path/to/images +``` +- `-xf` 解压文件 +- `images.tar.zst` 压缩包 +- `-C` 指定解压路径 + +## 5. 启动项目 + +Springboot 打包好后可以通过 `java -jar xxx.jar` 命令启动项目。但是这样启动的项目会随着终端关闭而停止,所以我们可以通过 `nohup` 命令让项目在后台运行。 + +输入以下命令启动项目: +```bash +nohup java -jar xxx.jar >> nohup.out 2>&1 & +``` + +- `nohup` 命令可以让程序在后台运行,不占用当前终端,不会因为终端关闭而停止。 +- `>> nohup.out 2>&1` 将输出重定向到 `nohup.out` 文件中,这样我们可以查看项目的输出日志。 + +## 6. 反向代理与 SSL 证书申请 + +我用了 `1Panel` 比较方便地配置了反向代理和申请了 SSL 证书。这里就不过多赘述了。感兴趣的可以看我往期文章:{% post_link 1panel-installation-and-usage-tutorial '1Panel 安装配置教程' %} + +反向代理与 SSL 证书申请 配置好后,我们就可以通过域名访问我们的项目了,整个部署流程就结束了。过程虽然不难,但有很多细节需要注意,一不小心就会出错。 + +## 7. 测试项目 + +在项目进行本地开发阶段时,务必进行全面的测试,确保各项功能稳定可靠。当项目部署完成后,亦不可掉以轻心,仍需进行相应的测试,以防因环境配置不当(特别是数据库部分)而引发报错。一切准备就绪后,项目就可以正式上线了。 + +

+ +参考资料: +[^1]: https://openjdk.org/projects/jdk/21/#Schedule +[^2]: https://linux.cn/article-13746-1.html diff --git a/source/_posts/Deploying-a-Web-Disk-of-Your-Own.md b/source/_posts/Deploying-a-Web-Disk-of-Your-Own.md new file mode 100644 index 00000000..8490c0a0 --- /dev/null +++ b/source/_posts/Deploying-a-Web-Disk-of-Your-Own.md @@ -0,0 +1,167 @@ +--- +title: 部署自己的网盘 — AList 安装配置教程 +tags: + - 部署 + - AList +abbrlink: 9c18a796 +date: 2024-01-17 20:50:59 +--- + +{% note secondary %} +本文档为 Alist 部署教程,主要介绍 Alist 的配置及使用,参考了官网的教程来编写。更多信息请参照官网 https://alist.nn.ci/zh/guide +{% endnote %} + +## 1. 安装 Alist + +{% fold info @1Panel 一键安装 %} +打开 `1Panel` 面板,点击 `应用商店`,搜索 `Alist`,点击 `安装` 即可。 + +{% post_link 1panel-installation-and-usage-tutorial '1Panel 安装配置教程' %} +{% endfold %} + +{% fold info @一键脚本安装 %} +仅适用于 Linux amd64/arm64 平台 +打开命令行输入 + +```bash +curl -fsSL "https://alist.nn.ci/v3.sh" | bash -s install +``` + +alist 默认安装在 `/opt/alist` 中 + +可以通过以下命令来启动、关闭、重启、查看状态: +启动: `systemctl start alist` +关闭: `systemctl stop alist` +状态: `systemctl status alist` +重启: `systemctl restart alist` +{% endfold %} + +{% fold info @docker-compose 安装 %} + +docker-compose 的相关知识就不在这里赘述了,如果不了解可以自行搜索。 + +
+ +创建一个目录用于存放 `docker-compose.yml` +```bash +mkdir /etc/alist && cd /etc/alist +``` +
+ +下载 `docker-compose.yml` 文件 +```bash +wget https://alist.nn.ci/docker-compose.yml +``` + +
+运行容器 +```bash +docker-compose up -d +``` + +
+ +注意 docker-compose.yml 文件中的 `volumes` 配置,后面要用到: + +```yml +volumes: + - '/etc/alist:/opt/alist/data' +``` + +{% endfold %} + +{% fold @手动安装(适合 Windows) %} +打开 AList Release 下载待部署系统对应的文件。下载后解压,赋予文件执行权限后运行即可。Windows 推荐使用该方式安装。 +参照 https://alist.nn.ci/zh/guide/install/manual.html +{% endfold %} + +## 2. 获取 Alist 密码 + +Alist 默认情况下需要 `随机生成` 或者 `手动设置` 密码,才能使用密码登陆。 + +通过 **一键脚本安装** 的,可以在安装路径下执行如下命令: + +- 随机生成一个密码 +```bash +./alist admin random +``` + +- 手动设置一个密码,`NEW_PASSWORD`是指你需要设置的密码 +```bash +./alist admin set NEW_PASSWORD +``` + +
+ +通过 **doekcer compose** 安装的,可执行如下命令。注意,如果你的容器名称不是 `alist`,需要将其更换为你的对应容器名称: + +- 随机生成一个密码 +```bash +docker exec -it alist ./alist admin random +``` + +- 手动设置一个密码,`NEW_PASSWORD`是指你需要设置的密码 +```bash +docker exec -it alist ./alist admin set NEW_PASSWORD +``` + +## 3. 配置 Alist + +默认情况下,应用程序将在 http://localhost:5244 上启动。 + +浏览器访问上述链接,输入用户名 `admin` 和上一步获取的 `密码`。 +点击登陆。 + +### 3.1 添加本地存储 + +1. 在你 `安装 alist 的路径` 手动创建一个目录 `files` 用于存储网盘文件。一键脚本路径为 `/opt/alist/files`;docker-compose 路径为 `etc/alist/files`。 + +2. 添加存储: +左边栏点击 `存储`,然后点击`添加`,驱动选择 `本机存储`,点击`添加` + +3. `挂载路径`填写 `/`,意味着这次添加的存储为 `网盘根目录`。往下滑,找到 `根文件夹路径`,也就是文件的存储路径。 +如果你是 **一键脚本安装** 的,就填写 `/opt/alist/files`; +如果你是 **docker-compose 安装** 的,就填 `/opt/alist/data/files`。(注意,这个是容器内的映射路径,不是宿主机的路径,参考前文的 `volumes` 配置) + +也就是 `根文件夹路径(/opt/alist/files)` --> `挂载路径(/)`,这样就可以把 `/opt/alist/files` 映射到 `/`,也就是网盘根目录。 + +最下面点击 `保存` + +### 3.2 启用游客访问 +左边栏点击 `用户` +编辑 `guest` 用户,将 `停用` 取消勾选,点击保存 + + +### 3.3 启用索引 + +按照以下步骤开启搜索: + +1. 转到索引页,选择一个搜索索引,并单击保存; +2. 保存索引后,单击构建索引来构建索引; +3. 现在你可以通过点击页面右上角的搜索块或使用快捷键 Ctrl + K 来搜索文件。 + +## 4. 更新 Alist + +### 4.1 `1Panel` 一键安装 + +打开 `1Panel` 面板,点击 `应用商店`,点击 `可升级`,找到 `Alist`,点击 `升级` 即可。 + +### 4.2 一键脚本安装 + +```bash +curl -fsSL "https://alist.nn.ci/v3.sh" | bash -s update +``` + +### 4.3 docker-compose 安装 + +```bash +docker-compose pull +docker-compose up -d +``` + +### 4.4 手动安装 + +下载最新版本的 Alist,解压后替换原有文件即可。 + +## 5. 高级配置 +更多高级配置请参照官网 https://alist.nn.ci/zh/guide/ diff --git a/source/_posts/Enable-blog-comment.md b/source/_posts/Enable-blog-comment.md new file mode 100644 index 00000000..6c4644d1 --- /dev/null +++ b/source/_posts/Enable-blog-comment.md @@ -0,0 +1,126 @@ +--- +title: 启用博客评论 Giscus +abbrlink: 7671c28e +date: 2023-12-29 16:39:46 +tags: + - Giscus +--- + +{% note secondary %} +我认为评论功能是一个博客不可或缺的组成部分,作者可以通过评论获得读者反馈,比如说我文章哪里写错了或者哪里需要更新,而读者也可以通过评论与作者交流。 + +又由于我 Hexo 部署的是 GitHub Pages 静态博客网页,依靠后端的评论系统不现实。所以我考虑依靠 Github 自带的 Issues 或者 Discussions 评论系统来实现评论功能。 +{% endnote %} + + +## 1. 配置 Giscus + +[Giscus 配置页](https://giscus.app/zh-CN) + +往下滑动,来到仓库这个选项,填入你的 GitHub 仓库地址。 +![填入你的仓库 url](https://pic4.zhimg.com/80/v2-63ad66bdd73fa2abe329b96135f89923_1440w.webp) + +可以看到报错了,这是因为我们还没有满足开启 Giscus 的条件 + +``` +选择 giscus 连接到的仓库。请确保: + +1. 该仓库是公开的,否则访客将无法查看 discussion。 +2. giscus app 已安装,否则访客将无法评论和回应。 +3. Discussions 功能已在你的仓库中启用。 +``` + +### 1.1 仓库公开 + +先确保你的仓库是公开的,如果不是,可以在仓库的 Settings 里面修改。或者创建一个新的公开仓库,用来存放博客的评论。 +![修改仓库为公开](https://pic1.zhimg.com/80/v2-f6a7d078b2bba550b711d0842a50a510_1440w.webp) + +### 1.2 安装 giscus app + +安装 giscus app,点击 [giscus app](https://github.com/apps/giscus) 按钮,跳转到 GitHub 的安装页面,点击 `Install` 按钮,选择你的仓库,安装成功后,会跳转回 Giscus 配置页面。 +![安装 giscus app](https://pic1.zhimg.com/80/v2-48fbbe27f37257b728b6a51c18582e18_1440w.webp) +![选择仓库](https://pic4.zhimg.com/80/v2-e1175a1a8532fad2e0e65e0a1728ed1b_1440w.webp) +![安装成功](https://pic4.zhimg.com/80/v2-9ff4af2af602fe3d8b26b9e9e1b46b47_1440w.webp) + +### 1.3 启用 Discussions 功能 + +启用 Discussions 功能,点击仓库的 `Settings`,在 `Features` 选项卡下,勾选 `Discussions`. + +现在我们就满足他的要求了 +![配置成功](https://pic2.zhimg.com/80/v2-87f6a97a98bd253ff8fd78b89115aa0d_1440w.webp) + + +### 1.4 配置 Giscus 参数 + +下面我们来配置 Giscus 的参数。 +![配置 giscus 参数](https://pic3.zhimg.com/80/v2-3ab1980b9fe5b4569f9c4a83ee39854a_1440w.webp) +![配置 giscus 参数](https://pic2.zhimg.com/80/v2-2d04b343bbeac93921c736e6c040f5d9_1440w.webp) + +配置完毕之后滑到下面,这个 `script` 标签会显示你相应的参数。 +![参数列表](https://pic3.zhimg.com/80/v2-f130a5c4da97dbd1704254cb5098471a_1440w.webp) + +## 2. 配置 comment 参数 + +{% fold @手动配置 Giscus %} +在你想让评论出现的位置添加上图的 `script` 标签。 + +但如果已经存在带有 giscus 类的元素,则评论会被放在那里。你可以在嵌入的页面中使用 .giscus 和 .giscus-frame 选择器来自定义容器布局。 +{% endfold %} + +{% fold @ 主题配置 Giscus %} +如果你的博客主题支持 Giscus,那么直接在主题配置中配置 Giscus 即可。建议参照主题的文档,找到对应的配置项,进行配置。 + +下面我以 Fluid 主题为例,配置 Giscus。 + +来到 giscus: 标签下,对照着 script 标签,填入相应的参数 + +```yml +giscus: + repo: 你的 repo + repo-id: 你的 repo-id + category: 你的 category + category-id: 你的 category-id + theme-light: light + theme-dark: dark + mapping: pathname + reactions-enabled: 1 + emit-metadata: 0 + input-position: top + lang: zh-CN +``` + +检查无误后,清除一下缓存 `hexo clean` 再部署 Hexo 就可以看到评论功能了。 + +![ok](https://pic3.zhimg.com/80/v2-5958c4ce55d4ea0210a551e7fe10501e_1440w.webp) + +如果没有看见评论功能,注意检查一下你的参数配置是否正确。 +{% endfold %} + +在配置完成后,`giscus` 加载时,会使用 GitHub Discussions 搜索 API 根据选定的映射方式(如 URL、pathname、title 等)来查找与当前页面关联的 discussion。如果找不到匹配的 discussion,giscus bot 就会在第一次有人留下评论或回应时自动创建一个 discussion。这样你的博客读者 登陆 Github 即可对文章评论了。 + +## 3. 进阶配置 + +进阶配置可通过在 仓库根目录下 创建一个 `giscus.json` 文件来完成。 +如设置 **限制允许评论的域名**,**评论的默认排序**等。 + +示例如下: + +```json +{ + "origins": [ + "https://giscus.app", + "https://giscus.vercel.app", + "https://giscus-component.vercel.app" + ], + "originsRegex": [ + "https://giscus-git-([A-z0-9]|-)*giscus\\.vercel\\.app", + "https://giscus-component-git-([A-z0-9]|-)*giscus\\.vercel\\.app", + "http://selfhost:[0-9]+" + ], + "defaultCommentOrder": "oldest" +} +``` + +- 你可以使用 `origins` 键限制可以加载 giscus 以及 存储库 Discussion 的域名。 `origins` 键接受一个字符串列表,将与 加载 giscus 的页面的 `window.origin` 进行校验。 +- `originsRegex` 键使用正则表达式来校验 `origin`。 +- `defaultCommentOrder` 键用于设置评论的默认排序方式。可选值为 `oldest` 或 `newest`。默认是 `oldest`。 diff --git a/source/_posts/Fail2ban-installation-and-usage-tutorial.md b/source/_posts/Fail2ban-installation-and-usage-tutorial.md new file mode 100644 index 00000000..6c44455c --- /dev/null +++ b/source/_posts/Fail2ban-installation-and-usage-tutorial.md @@ -0,0 +1,106 @@ +--- +title: Fail2ban 安装使用教程 +abbrlink: 1acd162e +date: 2024-02-19 12:06:33 +tags: + - 运维 + - 服务器 + - 部署 + - Fail2ban + - 安全 +--- + +![Fail2ban](https://pic4.zhimg.com/80/v2-3e60fbb2f9b8a948d82344a200fee833_1440w.webp) + +> Fail2Ban 是一个入侵检测系统框架,它可以监控服务器的日志文件,当发现有暴力破解行为时,会自动封禁攻击者的 IP 地址。可以保护电脑服务器免受暴力破解。它用 Python 编写。能够在具有本地安装的数据包控制系统或防火墙(如 iptables)接口的 POSIX 系统上运行。 + +## 1. 安装 Fail2ban + +以 Debian/Ubuntu 为例,使用以下命令安装 Fail2ban: +```bash +sudo apt update +sudo apt install fail2ban -y +``` + +需要特别注意的是,Debian 12 及以上的版本需要手动安装 `rsyslog` 来保证其正常运行: +```bash +sudo apt install rsyslog -y +``` +原因见:[Github Issue](https://github.com/fail2ban/fail2ban/issues/3292) + +## 2. 启动并设置 Fail2ban 开机自启 + +```bash +sudo systemctl enable --now fail2ban +``` + +## 4. 查看 Fail2ban 状态 + +```bash +sudo systemctl status fail2ban +``` + +## 5. 配置 Fail2ban + +编辑 /etc/fail2ban/jail.local 文件: +```bash +sudo vim /etc/fail2ban/jail.local +``` + +在文件中输入以下内容: +``` +[DEFAULT] +bantime = 600 +findtime = 300 +maxretry = 3 + +[sshd] +ignoreip = 127.0.0.1/8 +enabled = true +filter = sshd +bantime = 600 +findtime = 300 +maxretry = 2 +port = 22 +logpath = /var/log/auth.log +``` + +[DEFAULT] 部分是全局配置,[sshd] 部分是针对 SSH 服务的配置,可以根据自己的需求进行修改。 +其中: +- `bantime`:封禁时间,单位为秒。-1 表示永久封禁。 +- `findtime`:检测时间,单位为秒。如果在这个时间内有超过 `maxretry` 次的尝试,就会被封禁,如 300 秒内有 5 次尝试失败就会被封禁。 +- `maxretry`:最大尝试次数。 +- `ignoreip`:不会被封禁的 IP 地址列表。 +- `filter`:指定用于匹配日志的过滤器,这里使用了 sshd 过滤器,用于匹配 SSH 登录日志。 + +修改完成后 保存并退出编辑器,重启 Fail2ban 服务: +```bash +sudo systemctl restart fail2ban +``` + +## 6. 常用命令 + +- 查看 sshd 所有被封禁的 IP 地址: +```bash +sudo fail2ban-client status sshd +``` + +- 手动封禁 IP 地址: +```bash +sudo fail2ban-client set sshd banip 6.6.6.6 +``` + +- 手动解封 IP 地址: +```bash +sudo fail2ban-client set sshd unbanip 6.6.6.6 +``` + + +

+ + +参考文章: +- https://1panel.cn/docs/user_manual/toolbox/fail2ban/ +- https://its.pku.edu.cn/faq_fail2ban.jsp +- https://aws.amazon.com/cn/blogs/china/open-source-tool-to-protect-ec2-instances-fail2ban/ +- https://www.myfreax.com/install-configure-fail2ban-on-ubuntu-20-04/ diff --git a/source/_posts/Fluid-theme-installation.md b/source/_posts/Fluid-theme-installation.md new file mode 100644 index 00000000..89b52d35 --- /dev/null +++ b/source/_posts/Fluid-theme-installation.md @@ -0,0 +1,116 @@ +--- +title: Hexo 安装 Fluid 主题 +tags: + - Hexo + - Fluid + - 部署 +abbrlink: 5eba38dc +date: 2023-12-27 02:09:48 +--- + +[官方文档](https://hexo.fluid-dev.com/docs/start)其实挺详细的了。 +记录一下我自己的操作。 + +## 1. 安装主题 +进入博客目录执行命令: +```bash +npm install --save hexo-theme-fluid +``` +然后在博客目录下创建 _config.fluid.yml,将官方仓库的主题配置 [_config.yml](https://github.com/fluid-dev/hexo-theme-fluid/blob/master/_config.yml) 内容复制过去。 + +现在目录下有这三个 yml 文件: +![yml-files](https://pic2.zhimg.com/80/v2-052fdc56939475513bf83af1bd6b1bb5_1440w.webp) + +可删除 `_config.landscape.yml` , 它是 hexo 默认的主题文件。 + +## 2. 修改 hexo 配置 + +修改 Hexo 博客目录中的 `_config.yml`,将 `theme` 属性改为 `fluid`, `language` 属性改为 `zh-CN`: +```yml +theme: fluid + +language: zh-CN +``` + +## 3. 创建「关于页」 + +Fluid 默认不会创建「关于页」,需要手动创建。 + +执行以下命令: +```bash +hexo new page about +``` + +创建成功后修改 `/source/about/index.md`,添加 `layout` 属性: +``` +--- +title: about +date: 2023-12-26 22:43:21 +layout: about +--- +这里写关于页的正文,支持 Markdown, HTML +``` +不出意外你就可以看到关于页了。 + +执行以下命令: +```bash +hexo clean && hexo g && hexo s -o +``` + +后访问 `http://localhost:4000/about/` 即可看到效果。 + +![关于页](https://pic2.zhimg.com/80/v2-c807849599bc8439c765cf501ca36419_1440w.webp) + +PS: 可以跟着文档把关于页面的几个 icon 一起改了。 + +## 4. 修改主题配置 + +[官方文档](https://hexo.fluid-dev.com/docs/guide/) 比较完善,耐心看完即可,有详细的配置说明。 + +## 5. 修改网站图标 +`修改网站图标` 文档好像没提到,我这里写一下 +首先把你的图标放到 `/source/images/` 目录下,然后 +打开 `_config.fluid.yml` 找到这个配置: +```yml +# 用于浏览器标签的图标 +# Icon for browser tab +favicon: images/favicon.png + +# 用于苹果设备的图标 +# Icon for Apple touch +apple_touch_icon: images/favicon.png +``` +将 `favicon.png` 改为你的图标路径即可。 + +## 6. 修改 slogan 为 api 语录 +效果如图所示: +![语录](https://pic4.zhimg.com/80/v2-de40d65e16c881935c1acc00eb51ab0f_1440w.webp) + +在主题配置 `_config.fluid.yml` 中开启: +```yml +index: + slogan: + enable: true + text: 这是一条 Slogan + api: + enable: true + url: "https://v1.hitokoto.cn/" + method: "GET" + headers: {} + keys: ["hitokoto"] +``` +把 `url` 改为你想要的 api 地址,`keys` 改为你想要的字段。具体参数可以看[官方文档](https://hexo.fluid-dev.com/docs/guide/#slogan-%E6%89%93%E5%AD%97%E6%9C%BA) + +## 7. 修改背景图片 为 api 图片 +既然可以改 slogan 为 api 语录,那么背景图片当然也可以改为 api 图片 笑)。 + +效果如图所示: +![api 图片](https://pic4.zhimg.com/80/v2-6a515a3f1baedebcec5499c1d20eb467_1440w.webp) + +在主题配置 `_config.fluid.yml` 中搜索 +```yml +/img/default.png +``` +将其改为你想要的 api 地址即可。 +我使用的是 [Bing 每日图片](https://api.vvhan.com/api/bing) +感谢接口提供者!!! \ No newline at end of file diff --git a/source/_posts/Hexo-blog-deployment-tutorial.md b/source/_posts/Hexo-blog-deployment-tutorial.md new file mode 100644 index 00000000..9caea5c8 --- /dev/null +++ b/source/_posts/Hexo-blog-deployment-tutorial.md @@ -0,0 +1,197 @@ +--- +title: Hexo 博客部署教程 +tags: + - Hexo + - Github + - Github-Pages + - Github-Actions + - 部署 +abbrlink: 7a862802 +date: 2023-12-26 23:18:38 +--- +> Hexo 是一个快速、简洁且高效的博客框架。本文旨在记录 Hexo 博客部署到 Github Pages 的过程,以及 Github Actions 自动部署的过程。 + +本文环境: + +> Nodejs 20 +> Git 2.44 + +本文最终实现成果:一个项目仓库,`main` 分支存放源代码,`gh-pages` 存放生成后的网页代码。每当我们 push 代码到 `main` 分支的时候,Github Actions 会自动构建并将代码发布到 `gh-pages` 分支,Github Pages 会自动加载 `gh-pages` 分支的代码,这样就实现了博客自动化部署。 + +注意:本文会用 `用户名` 来指代 Github 用户名,你需要将 `用户名` 替换为你的 Github 用户名。如 `用户名.github.io` 替换为 `zhangsan.github.io`。 + + +## 0. 开发环境准备 + +### 0.1 开发工具 + +在开始之前,你需要安装好 Nodejs 和 Git。 + +如果你是 Linux / Mac 用户,那么通过发行版的 **包管理器** 即可安装。 + +如果你是 Windows 用户,那么可以通过 [Nodejs 官网](https://nodejs.org/en/download) 下载安装 Nodejs,Git 可以通过 [Git 官网](https://git-scm.com/downloads) 下载安装,并配置好对应的 Nodejs 环境变量。 + + +安装完毕后,输入以下命令检验是否安装成功: +```bash +node -v +npm -v +git --version +``` + +### 0.2 配置 Git + +如果你是第一次使用 Git,那么你可能需要配置用户名和邮箱: +```bash +git config --global user.name "用户名" +git config --global user.email 邮箱 +git config --global init.defaultBranch main +``` + +执行以下命令检验是否配置成功: +```bash +git config --global --list +``` + +### 0.3 配置 Github SSH + +#### 生成 SSH 密钥 + +输入以下命令来生成 SSH 密钥,将示例中使用的电子邮件替换为 GitHub 电子邮件地址: +```bash +ssh-keygen -t ed25519 -C "your_email@example.com" +``` +遇到提示信息可以一路回车。 + +现在你已经生成了 SSH 密钥对,你可以在 `~/.ssh` 目录或者你指定的目录下找到你的密钥对。 + +#### 将 SSH 密钥添加到 Github + +浏览器打开 Github,点击个人头像 --> 点击 `设置` --> 点击左边导航栏的 `SSH and GPG keys` --> 点击靠近右上角的 `New SSH key`。 + +`Key type` 选择 `Authentication Key`,随便起一个 Tittle,复制你刚刚生成的 `id_ed25519.pub` 内容到 `Key` 中,点击 `Add SSH key` 保存。 + +![将 SSH 密钥添加到 Github](https://pic3.zhimg.com/80/v2-4b9ba3553dc717bd9723afb9ee43a7fe_1440w.webp) + + +## 1. 安装 Hexo + +打开系统终端,输入以下命令安装 Hexo: +```bash +npm install hexo-cli -g +``` +Linux 可能需要 sudo 权限来执行上述命令,Windows 可能需要管理员权限来执行上述命令。 + +安装完毕后,输入以下命令检验是否安装成功: +```bash +hexo -v +``` + +## 2. 新建 Github 仓库 + +点击 Github 首页左导航栏的 `New` 按钮,新建一个仓库,仓库名建议为 `用户名.github.io`。将 `用户名` 替换为你的 Github 用户名。 + +![新建仓库](https://pic1.zhimg.com/80/v2-ca65acc37e795a863ce23f2282ec6e1c_1440w.webp) + +然后点击 `Create repository` 按钮,完成仓库的创建。 + +## 3. 初始化 Hexo 博客目录 + +找一个空目录,执行以下命令。将 `用户名` 替换为你的 Github 用户名: +```bash +hexo init 用户名.github.io && cd 用户名.github.io +``` + +## 4. 将 Git 项目初始化并推送到 Github + +我们首先初始化 Git 仓库并创建 `gh-pages` 分支: +```bash +git init +git add . +git commit -m "Initial commit" +git branch gh-pages +``` + +将本地仓库与 Github 仓库关联并推送到 Github: +```bash +git remote add origin git@github.com:用户名/用户名.github.io.git +git push -u origin main gh-pages +``` +此时,我们访问我们的 Github 仓库可以发现代码已经成功上传到 Github 了。 + + +## 5. 配置 Github Pages + +点击仓库的 `Settings`,点击左边导航栏的 `Pages`。选择 `Branch` 的 `gh-pages` 分支,点击 `Save` 保存。 +![选择部署分支](https://pic1.zhimg.com/80/v2-f3c82ba51458689af83e72d8228eaae8_1440w.webp) + +## 6. 编写 Github Actions 配置文件 + +在本地已有的项目下 新建一个目录为 `.github/workflows/deploy.yml` 的文件。 + +`deploy.yml` 文件内容如下: +```yml +name: Deploy Hexo + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Check Out + uses: actions/checkout@v4 + with: + fetch-depth: 0 # 用于获取提交记录,获取文件更新时间 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install Dependencies + run: | + npm install + + # https://github.com/zhullyb/zhullyb.github.io/blob/master/.github/workflows/deploy.yml + # 修复 hexo 生成的文件更新时间 为当前时间,实际应为提交时间 + - name: Fix File Updated Date + run: | + git ls-files | while read filepath; do touch -d "$(git log -1 --format='@%ct' $filepath)" "$filepath" && echo "Fixed: $filepath"; done + + - name: Build Site + run: | + export TZ='Asia/Shanghai' + npm run clean + npm run build + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: public +``` + +然后将其推送到 Github: +```bash +git add . +git commit -m "Add deploy.yml" +git push +``` + +耐心等待 Github Actions 的构建 + +## 7. 查看博客 + +浏览器访问 [https://用户名.github.io/](https://用户名.github.io/) + +即可查看到你的博客 + +![博客首页](https://pic1.zhimg.com/80/v2-313dd9a390364bf21812010b4dcc77dc_1440w.webp) + diff --git a/source/_posts/How-to-Deploy-a-new-server.md b/source/_posts/How-to-Deploy-a-new-server.md new file mode 100644 index 00000000..3e4b591b --- /dev/null +++ b/source/_posts/How-to-Deploy-a-new-server.md @@ -0,0 +1,436 @@ +--- +title: 从零开始部署服务器和网站 +sticky: 102 +tags: + - 部署 + - 运维 + - 服务器 + - Linux + - SSH + - ufw + - Fail2ban + - 安全 +abbrlink: 4cde56ee +date: 2024-03-01 22:25:20 +--- + +{% note secondary %} +我自己部署了不少服务器,现在有了一定的经验,写下本文来记录一下自己在部署服务器时的一些操作及注意事项来备忘。 + +我曾经也是一个新手,在部署服务器的时候遇到很多问题,不管屏幕前的你是出于何种目的:比如有业务搭建的需要;还是初入运维的小白;或者只是单纯的想折腾。我希望这篇文章大部分人看完后都能有所收获。 + +本文将会介绍如何部署一台新的服务器。本文 4~7 节内容是关于服务器的安全配置,如果你只是想要部署一个简单的网站,阅读前 3 节即可。**文末还有一键脚本,可以帮助你快速部署服务器,详情跳到最后一节。** +{% endnote %} + +## 0. 基础的 Web 知识 + +在开始之前,我们得先了解一些基础的 Web 知识。有了这些知识,我们才能更好地理解服务器的操作及其使用。如果你已经了解了这些知识,可以直接跳到下一节。 + +### 0.1 什么是服务器? + +在开始使用之前,我们得先搞懂什么是服务器。 + +**服务器是一种专门为网络服务而设计的专用计算机,其主要功能是为用户提供计算或应用服务。**如网站、数据库、电子邮件、文件存储等等。 + +而服务器分为 `独立服务器` 和 `虚拟服务器`,它们是有区别的。 + +- `独立服务器` 是指一台物理服务器只提供给一个用户使用,核数多、性能高、稳定性好。但是 `价格往往相当昂贵`,适合大企业使用,如果我们只是搭建一个小型网站就相当不划算。 + +- `虚拟服务器` 是指一台物理服务器上划分出多个虚拟服务器,每个虚拟服务器都有自己的操作系统、磁盘、内存、CPU 等资源,但是它们共享物理服务器的资源。但是 `价格也相对便宜`,适合个人或小型企业使用。 + +本文所说的服务器就是指 `虚拟服务器`,也就是我们常说的云服务器、云主机,属于 IaaS(基础设施即服务)。我们如果要部署一个网站,就需要一个云服务器。 + +而云服务器提供商有很多,比如阿里云、腾讯云、华为云、亚马逊云等等。 + +![阿里云的 ECS 简介](https://pic4.zhimg.com/80/v2-7c0b3970795ca4710d6ed4c50a3e5383_1440w.webp) + +而其价格根据配置、地区、带宽等也有所不同,我们可以根据自己的需求来选择。 + +![腾讯轻量云活动](https://pic1.zhimg.com/80/v2-451ed34fbe3762fc35d33d51a5bef524_1440w.webp) + +需要特别注意的是,如果你购买的服务器在中国内地(大陆),必须完成 ICP 备案才可对外提供服务。备案是什么以及如何备案,就不在本文讨论范围内了。 + +#### 0.1.1 如何选择服务器系统? + +可选的服务器系统,主要有 `Windows` 和 `Linux` 两种。 + +我们一般选择 Linux 作为服务器系统,因为 Linux 有很多优点,比如稳定、安全、开源、免费等等,最重要的是高度可自定义,不会给你塞一些不想要的牛皮癣功能。 + +而在 Linux 中,又有很多发行版,比如 Ubuntu、CentOS(近几年争议较多 不建议选择)、Debian、Fedora 等等。本文选择 **`Debian`** 作为演示,它是是最受欢迎的 Linux 发行版之一 Ubuntu 的上游,是一个非常稳定和可靠的操作系统,也通常被认为比 Ubuntu 更轻量级,因为它不包含太多附加的软件。 + +一般服务器提供商都会提供多种系统,你可以根据自己的需求来选择。 + +### 0.2 什么是域名及 DNS? + +购买了一台服务器之后,服务器供应商 会提供给我们服务器的 IP 地址如 `8.8.8.8`,我们可以通过这个 IP 地址来访问我们的服务器。 + +但是 IP 地址是一串数字,不方便记忆,并且后期如果更换服务器,IP 地址也会随之变化,这就会导致我们的网站无法访问。所以我们需要一个域名替代 IP 地址来访问我们的服务器,让用户更方便地访问我们的网站。 + +域名就是我们常说的网址,比如 `qq.com`、`baidu.com`、`google.com` 等等。 + +> 域名是由一串用点分隔的字符组成的互联网上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位。域名可以说是一个 IP 地址的代称,目的是为了便于记忆后者。—— wikipedia + +而 DNS(Domain Name System)是一个分布式数据库,用于存储域名和 IP 地址之间的映射关系。当我们在浏览器中输入一个域名时,浏览器会向 DNS 服务器查询域名对应的 IP 地址,然后再通过这个 IP 地址来访问服务器。 + +![DNS 查询过程](https://pic2.zhimg.com/80/v2-361795da46a8bea1a7a279ec2bcd2729_1440w.webp) + +**将我们的域名解析到服务器的 IP 地址,就可以通过域名来访问我们的服务器了。**域名注册商一般都会提供 DNS 服务,我们可以在域名注册商的控制台中进行域名解析。 + +![域名解析](https://pic2.zhimg.com/80/v2-bbecd6cb7f4141ad2a583dc2430843dd_1440w.webp) + +你可以选择国内外的知名域名注册商,比如阿里云、腾讯云、GoDaddy、Namecheap、Dynadot 等等。不推荐使用白嫖的域名 —— 因为你的域名所有权得不到保障。 + + +## 1. 连接服务器 + +现在假设你已经在服务器提供商那里购买了一台服务器,那么它会给你提供服务器的 `IP 地址` 以及 `root 用户密码`。接下来我们开始连接服务器。 + +### 1.1 使用 SSH 连接服务器 + +> SSH(Secure Shell)是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境。Win10/11 和 Linux 发行版,应该都有预装 openssh,如果没有可以搜一下安装教程 + +我们可以使用 SSH 客户端连接服务器,然后在服务器上执行命令。打开系统的命令行终端,输入以下命令: + +```bash +ssh root@<服务器 IP 地址> +``` + +如果能连接到服务器,会输出以下信息: +```bash +ssh root@x.x.x.x +The authenticity of host 'x.x.x.x (x.x.x.x)' can't be established. +ED25519 key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxx. +This key is not known by any other names. +Are you sure you want to continue connecting (yes/no/[fingerprint])? yes +Warning: Permanently added 'x.x.x.x' (ED25519) to the list of known hosts. +root@x.x.x.x's password: +``` +这段输出的意思是,无法验证服务器的真实性,是否继续连接。 +输入 `yes` 然后 `输入服务器的密码` 即可连接到服务器。**这段真实性验证只会出现一次,以后再连接服务器就不会再出现了。** + +需要注意的是,**输入 SSH 密码时,屏幕上不会显示密码**,不用担心,将服务器的密码正确粘贴后回车即可。 + +现在你已经连接到服务器了,可以在服务器上执行命令了。如果连接过程出现报错,请按照报错信息进行排查。 + +## 2. 设置服务器时区 + +设置服务器的时区是非常重要的,因为服务器的时间会影响到很多服务的正常运行。比如日志记录、定时任务、证书有效期、数据库时间等等。 + +### 2.1 查看当前时区 + +```bash +timedatectl +``` + +你的输出有可能为: + +```bash + Local time: Tue 2024-03-05 05:39:46 UTC + Universal time: Tue 2024-03-05 05:39:46 UTC + RTC time: Tue 2024-03-05 05:39:50 + Time zone: UTC (UTC, +0000) +System clock synchronized: no + NTP service: active + RTC in local TZ: no +``` +这代表你的服务器的时区是 UTC 时间,而 UTC 时间是世界标准时间,也就是 0 时区。而 `System clock synchronized: no` 代表你的系统时钟同步没有开启。 + +### 2.2 设置服务器时区 + +根据你的服务器所在地区设置时区,输入以下命令来查看可用的时区: +```bash +sudo timedatectl list-timezones +``` + +比如我的服务器在香港,那么我就设置为 `Asia/Hong_Kong`。 + +```bash +sudo timedatectl set-timezone Asia/Hong_Kong +``` + +然后再次查看时区: + +```bash +timedatectl +``` +如果显示为 `Time zone: Asia/Hong_Kong`,那么就说明时区设置成功了。 + +### 2.3 系统时钟同步 +网络时间协议 NTP(Network Time Protocol)是一种用于同步系统时钟的协议,提供高精准度的时间校正,保证服务器的时间准确。 + +> 根据操作系统版本的不同,Debian 提供了多种安装 NTP 客户端的软件包。自 Debian 12 起,默认的 NTP 客户端是 systemd 的 systemd-timesyncd。[^2]timesyncd 是轻量级 ntpd 的替代品,配置更简单、更高效、更安全。此外,Timesyncd 还能更好地与 systemd 集成。这一特性使得使用 systemd 命令进行管理变得更容易。[^3] + + +{% fold info @Debian 12 %} + +如果你是 Debian 12,那么你可以使用 `systemd-timesyncd` 来同步服务器时间。 +输入以下命令来安装 `systemd-timesyncd`: +```bash +sudo apt install systemd-timesyncd -y +``` + +查看 `systemd-timesyncd` 的状态: +```bash +sudo systemctl status systemd-timesyncd +``` + +如果 `systemd-timesyncd` 是 `active (running)` 状态,那么就说明 `systemd-timesyncd` 已经在运行了。否则,你需要手动启动 `systemd-timesyncd`: +```bash +sudo systemctl start systemd-timesyncd +``` + +这时你的服务器的时间就会自动同步了。 +{% endfold %} + +{% fold info @Debian 11 及更早版本 %} + +如果你是 Debian 11 或更早的版本,那么你可以使用 `ntp` 来同步服务器时间。 + +输入以下命令来安装 `ntp`: +```bash +sudo apt install ntp -y +``` + +查看 `ntp` 的状态: +```bash +sudo systemctl status ntp +``` + +如果 `ntp` 是 `active (running)` 状态,那么就说明 `ntp` 已经在运行了。否则,你需要手动启动 `ntp`: +```bash +sudo systemctl start ntp +``` + +这时你的服务器的时间就会自动同步了。 +{% endfold %} + + +再次查看时区: +```bash +timedatectl +``` +如果显示为 `System clock synchronized: yes`,那么就说明系统时钟同步成功了。 + + +## 3. 安装 Web 服务器 + +`Nginx` 与 `Caddy` 是两个优秀的 Web 服务器,它们都是开源的免费的,功能强大,而且易于配置。我们可以选择其中一个来作为我们的 Web 服务器。 + +其中 `Nginx` 是市场占有量最高的 Web 服务器,没有之一。如果你是运维或者开发人员,那么我相信你多多少少一定会接触到 Nginx 的相关操作,建议还是学习一下相关的知识。 + +但如果你是小白或者想寻找`Nginx`的替代品,那么可以尝试一下 `Caddy`。`Caddy` 提供了简单易用的配置和自动提供 HTTPS 等功能,使得搭建和管理网站变得更加轻松。 + + +### 3.1 Nginx 安装与使用 + +可以参考我的文章:{% post_link Nginx-installation-and-usage-tutorial 'Nginx 安装与使用教程' %} +里面涉及 Nginx 的安装、配置、虚拟主机配置、反向代理配置等等。建议花时间阅读一下,对你的服务器操作和理解会有帮助。 + +### 3.2 Caddy 安装与使用 + +可以参考我的文章:{% post_link Caddy-installation-and-usage-tutorial 'Caddy 安装与使用教程' %} +现代化的 Web 服务器,具有自动 HTTPS、HTTP/3、反向代理、负载均衡、静态文件服务等功能。如果你想寻找 Nginx 的替代品或者是小白,那么可以尝试一下 Caddy。 + + +## 4. SSH 安全配置 + +### 4.1 修改 SSH 端口 + +> SSH 端口默认是 22,如果看过 SSH 登陆日志 你应该会发现,你的 SSH 每天都会被 **来自全球各地的大量的暴力破解** 密码尝试。这些攻击者会尝试使用常见的用户名和密码来登录你的服务器,如果你的密码不够复杂,那么你的服务器很有可能会被攻破。改变 SSH 端口理论上可以减少九成九以上的暴力破解尝试。 + +所以,修改服务器的 SSH 端口是非常有必要的。 +我们可以将 SSH 端口修改为一个不常用的端口来避免被直接爆破,比如 2222。 + +在服务器上编辑 SSH 配置文件: +```bash +sudo vim /etc/ssh/sshd_config +``` + +找到 `Port 22` 这一行,将 22 改为 2222。 +如果有注释符号 `#`,将其删除。 +```bash +Port 2222 +``` +保存并退出配置文件。 + +然后重启 SSH 服务: + +```bash +sudo systemctl restart sshd +``` + +现在你就可以使用新的端口来连接服务器了: + +```bash +ssh root@<服务器 IP 地址> -p 2222 +``` + +### 4.2 改用 SSH 密钥登录 + +SSH 密钥登录是一种更加安全的登录方式,它不需要输入密码,而是通过密钥对来进行验证。这样就可以避免密码被暴力破解。 + +SSH 密钥加密原理是使用非对称加密算法,原理如下[^1]: +![非对称加密算法](https://pic2.zhimg.com/80/v2-8e97a3e00c822f160241ba31cc8f8579_1440w.webp) + +密钥对分为公钥和私钥,公钥存放在服务器上,私钥存放在本地。当我们使用 SSH 密钥登录时,本地的私钥会与服务器上的公钥进行匹配,如果匹配成功,就可以登录到服务器。 + +#### 4.2.1 生成 SSH 密钥对 + +在本地终端输入以下命令,粘贴以下文本,将示例中使用的电子邮件替换为你的电子邮件地址。: +```bash +ssh-keygen -t ed25519 -C "your_email@example.com" +``` + +系统会提示你输入一个文件名,这个文件名是用来保存你的密钥对的,可以按 Enter 键接受默认文件位置。如果你已经有了 SSH 密钥对,可以选择覆盖或者使用新的文件名。 +```bash +Generating public/private ed25519 key pair. +Enter file in which to save the key (/home/user/.ssh/id_ed25519): +``` + +然后系统会提示你输入一个密码,这个密码是用来保护你的私钥的,如果你不想输入密码,可以直接按 Enter 键跳过。 +```bash +Enter passphrase (empty for no passphrase): +Enter same passphrase again: +``` + +现在你已经生成了 SSH 密钥对,你可以在 `~/.ssh` 目录或者你指定的目录下找到你的密钥对。 + +#### 4.2.2 将公钥添加到服务器 + +现在你需要将你的公钥添加到服务器上,这样你就可以使用私钥登录服务器了。 + +```bash +ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2222 root@<服务器 IP 地址> +``` +注意,这里的 +`-i` 参数是用来指定你的公钥文件的,如果你的公钥文件名不是 `id_ed25519.pub`,那么你需要将其替换为你的公钥文件名。 +`-p 2222` 是用来指定 SSH 端口的,如果你的 SSH 端口不是 2222,那么你需要将其替换为你的 SSH 端口。 + +如果没有报错,那么你的公钥已经成功添加到服务器上了。 + +#### 4.2.3 修改服务器 SSH 配置文件 + +现在你需要修改服务器的 SSH 配置文件,使得服务器可以使用密钥对登录。 +```bash +sudo vim /etc/ssh/sshd_config +``` + +找到 `PubkeyAuthentication` 这一行,将 `no` 改为 `yes` 或取消注释。 +```bash +PubkeyAuthentication yes +``` + +保存并退出配置文件。 + +然后测试一下是否可以使用密钥对登录服务器: +```bash +ssh root@<服务器 IP 地址> -p 2222 -i ~/.ssh/id_ed25519 +``` +如果你成功登录到服务器,那么你的密钥对已经登录成功了。 + + +现在你可以禁用密码登录,使得服务器更加安全: +```bash +sudo vim /etc/ssh/sshd_config +``` + +找到 `PasswordAuthentication` 这一行,将 `yes` 改为 `no`。 +```bash +PasswordAuthentication no +``` + +保存并退出配置文件。 + +测试一下是否可以使用密码登录服务器: +```bash +ssh root@<服务器 IP 地址> -p 2222 +``` + +如果你不能登录到服务器,那么你的密码登录已经被禁用了。 +如果还是可以登录到服务器,那么你需要检查一下你的配置文件是否正确。或者 `/etc/ssh/sshd_config.d/*.conf` 中是否有其他配置文件覆盖了你的配置。 + + +## 5. 配置防火墙 + +### 5.1 防火墙简介 + +防火墙是一种网络安全程序,用于监控和控制网络流量。它可以根据预定义的安全规则来阻止或允许流量通过。防火墙可以保护你的服务器免受来自互联网的恶意攻击。 + +### 5.2 防火墙的选择 + +RedHat/CentOS 系统可以选择 `firewalld` 防火墙,而 Debian/Ubuntu 系统可以选择 `ufw` 防火墙。 + +本文使用的是 Debian 系统,所以我们可以选择 `ufw` 防火墙。 + +### 5.3 安装 ufw + +```bash +sudo apt update +sudo apt install ufw -y +``` + +### 5.4 启用 ufw + +注意,在启用 UFW 防火墙之前,你必须显式允许进来的 SSH 连接。SSH 可能是你操作机器的唯一渠道,如果被防火墙拦住,将永远都无法连接到机器上,可能就得重置服务器了。 + +输入以下命令放开 SSH 端口: +```bash +sudo ufw allow 2222/tcp +``` + +SSH 默认为 22 端口,如果 SSH 运行在非标准端口,你需要将上述命令中的 2222 端口替换为对应的 SSH 端口。本文为 2222 端口 + +你还可以放开其他端口,比如 HTTP 端口 80、HTTPS 端口 443: +```bash +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp +``` + +输入以下命令启用 ufw: +```bash +sudo ufw enable +``` + +## 6. 服务器禁用 ping + +如果你不希望别人通过 ping 来探测你的服务器,可以禁用 ping。实测禁用 ping 以后,服务器就基本没有遭受 SSH 暴力破解的尝试了。 + +在 `/etc/sysctl.conf` 文件中添加以下内容: +```bash +net/ipv4/icmp_echo_ignore_all=1 +``` + +然后重新加载配置文件: +```bash +sudo sysctl -p +``` + +## 7. 配置 Fail2ban +可以参考我的文章:{% post_link Fail2ban-installation-and-usage-tutorial 'Fail2ban 安装使用教程' %} + +Fail2Ban 是一个入侵检测系统框架,它可以监控服务器的日志文件,当发现有暴力破解行为时,会自动封禁攻击者的 IP 地址。可以保护电脑服务器免受暴力破解。它用 Python 编写。能够在具有本地安装的数据包控制系统或防火墙(如 iptables)接口的 POSIX 系统上运行。 + +## 8. 一键脚本 +本文所讲述的内容我整理成了一键脚本,可以帮助你快速部署服务器,包括设置时区、安装 Web 服务器、SSH 安全配置、防火墙配置、禁用 ping、配置 Fail2ban 等等。 **`在使用前请最好先阅读脚本内容,以免造成不必要的损失`** 你可以根据自己的需求修改脚本内容。目前支持 Debian 12, Ubuntu 22.04 + +使用方法: +```bash +wget https://raw.githubusercontent.com/mobeicanyue/init-server/main/init-server.sh +sudo bash init-server.sh +``` +如果你的服务器无法访问 GitHub,可以使用 jsDelivr 加速访问: +```bash +wget https://cdn.jsdelivr.net/gh/mobeicanyue/init-server/init-server.sh +sudo bash init-server.sh +``` + +

+ +本文如有错误或者不足之处,欢迎指正。 + +

+ + +[^1]: https://help.aliyun.com/zh/ecs/ssh-service-introduction +[^2]: https://wiki.debian.org/DateTime +[^3]: https://phoenixnap.com/kb/debian-time-sync diff --git a/source/_posts/Install-Graalvm-on-Linux.md b/source/_posts/Install-Graalvm-on-Linux.md new file mode 100644 index 00000000..d4b6c4b8 --- /dev/null +++ b/source/_posts/Install-Graalvm-on-Linux.md @@ -0,0 +1,132 @@ +--- +title: 在 Linux 上安装和配置 GraalVM +tags: + - Java + - GraalVM +abbrlink: 526d514a +date: 2024-04-22 07:18:50 +--- + +{% note primary %} +GraalVM 是一个高性能的通用虚拟机,支持 Java、JavaScript、Python、Ruby、R、WebAssembly 等多种语言。通过它你可以将 Java 程序编译成本地二进制文件,大大提高程序的启动速度和运行效率。本文介绍如何在 Linux 系统上安装配置 GraalVM. +{% endnote %} + +截止到文章发布时,GraalVM 仍没有在 Debian 和 Archlinux 的官方仓库中发布,不能直接通过包管理器安装,需要我们手动下载。而 GraalVM 的 `Community Edition` 版本,是 GraalVM 的开源版本,与 `OpenJDK` 类似。本文将其作为 GraalVM 演示。 + +## 1. 下载 GraalVM + +访问 [GraalVM Community's builds](https://github.com/graalvm/graalvm-ce-builds/releases/) 下载页面,选择你需要的 JDK 版本。截止到文章发布时,最新的 `JDK LTS` 版本是 `21`. + +使用 `wget` 命令下载压缩包,我选择 `GraalVM for JDK 21 Community 21.0.2` 的压缩包下载: +```bash +wget https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz +``` +如果下载速度过慢可以考虑使用镜像站下载。 + +## 2. 解压 GraalVM + +下载完成后,解压你下载的 GraalVM: +```bash +tar -xvf graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz +``` + +将解压出的文件夹重命名为 `java-21-graalvm`: +```bash +mv graalvm-community-openjdk-21.0.2+13.1 java-21-graalvm +``` + +将 `java-21-graalvm` 移至 `/usr/lib/jvm` 目录: +```bash +sudo mv java-21-graalvm /usr/lib/jvm/ +``` + +## 3. 配置环境变量 + +编辑 `/etc/profile` 文件,添加 GraalVM 的环境变量。 +```bash +sudo vim /etc/profile +``` + +在文件末尾添加如下内容,将 `GRAALVM_HOME` 和 `JAVA_HOME` 设置为你的 GraalVM 安装路径: +```bash +export GRAALVM_HOME=/usr/lib/jvm/java-21-graalvm +export JAVA_HOME=$GRAALVM_HOME +export PATH=$PATH:$GRAALVM_HOME/bin +``` + +使配置生效: +```bash +source /etc/profile +``` + +## 4. 查看 GraalVM 版本 + +查看 GraalVM 的 `OpenJDK` 和 `native-image` 版本。 +```bash +java --version && echo && native-image --version +``` + +输出如下: +```bash +openjdk 21.0.2 2024-01-16 +OpenJDK Runtime Environment GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30) +OpenJDK 64-Bit Server VM GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30, mixed mode, sharing) + +native-image 21.0.2 2024-01-16 +GraalVM Runtime Environment GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30) +Substrate VM GraalVM CE 21.0.2+13.1 (build 21.0.2+13, serial gc) +``` + +## 5. 使用 GraalVM 编译 Java 程序 + +### 5.1 编译 Java 程序 +新建一个 Java 文件 `HelloWorld.java`,内容如下: +```java +public class HelloWorld { + public static void main(String[] args) { + System.out.println("Hello, GraalVM!"); + } +} +``` +首先使用 `javac` 编译 `Hello.java`,生成 `HelloWorld.class` 文件: +```bash +javac HelloWorld.java +``` + +然后使用 `native-image` 将 `HelloWorld.class` 文件编译成本地二进制文件: +```bash +native-image HelloWorld +``` + +执行编译后的二进制文件: +```bash +./helloworld +``` +输出 `Hello, GraalVM!` 则表示 GraalVM 安装成功。 + + +### 5.2 编译 SpringBoot 项目 + +同样的,你也可以对 SpringBoot 项目进行编译,提高启动速度和运行效率。 +首先将 SpringBoot 项目打包成 `jar` 文件 +- idea 可以点击左侧 `clean` --> `package` 直接打包, +- 或者使用 `maven` 命令打包: +```bash +mvn clean package +``` + +然后使用 `native-image` 将 `jar` 文件编译成本地二进制文件: +```bash +native-image -jar your-springboot-project.jar +``` + +执行编译后的二进制文件: +```bash +./your-springboot-project +``` + +

+ +参考文章: +[^1]: https://docs.oracle.com/zh-cn/learn/graalvm-native-image-quick-start/index.html +[^2]: https://www.graalvm.org/jdk21/reference-manual/native-image/overview/Options/ diff --git a/source/_posts/Install-microsoft-openjdk-on-Windows.md b/source/_posts/Install-microsoft-openjdk-on-Windows.md new file mode 100644 index 00000000..65658a94 --- /dev/null +++ b/source/_posts/Install-microsoft-openjdk-on-Windows.md @@ -0,0 +1,50 @@ +--- +title: Windows 安装 Java — Microsoft OpenJDK +tags: + - Java + - JDK +abbrlink: '7e833387' +date: 2024-04-08 23:46:34 +--- + +> 本文介绍如何在 Windows 系统上安装 Microsoft OpenJDK。也就是微软提供的 OpenJDK 版本。 +> +> (1) 为什么不使用 Oracle JDK 呢?因为 Oracle JDK 是商用协议,收费商用政策朝令夕改。而 OpenJDK 是开源免费的,是 Linux 发行版仓库中的默认 JDK。 +> +> (2) 有很多开源组织都提供 OpenJDK。为什么使用 Microsoft OpenJDK 呢?因为我们在 Windows 系统上安装 JDK,~~微软提供的 OpenJDK 与 Windows 系统更加兼容。~~没有人比巨硬更懂 Windows(bushi。 + + +## 1. 下载 Microsoft OpenJDK + +浏览器访问 [Microsoft OpenJDK](https://learn.microsoft.com/zh-cn/java/openjdk/download) 下载页面。 + +![下载 JDK](https://pic2.zhimg.com/80/v2-448eebb5cf154774a0e13ec84f0d728d_1440w.webp) + +选择 `Windows x64` 版本的 `msi` 安装包下载。 + +## 2. 安装 Microsoft OpenJDK + +打开下载的 `msi` 安装包,点击 `下一步`。 + +![打开安装包](https://pic4.zhimg.com/80/v2-023c05365fc09a59c2d380bcfc7f3843_1440w.webp) + +选择配置 `JAVA_HOME` 环境变量,相较于 Oracle JDK 的安装包多了这个选项,不用再去手动配置 `JAVA_HOME` 了。 + +![JAVA_HOME](https://pic3.zhimg.com/80/v2-6e72e861b8c74fe567f9253db08eb526_1440w.webp) + +功能调整完毕以后可以选择安装路径。 + +![配置路径](https://pic1.zhimg.com/80/v2-0fcf57f849c74b0df0996924e500d794_1440w.webp) + + +## 3. 验证安装 + +打开命令行工具,输入 `java -version` 查看版本信息。 + +```shell +java -version +``` + +![验证安装](https://pic3.zhimg.com/80/v2-30b70bcac8f5c9166a7ce8bebe1fd696_1440w.webp) + +总体来说,Microsoft OpenJDK 安装过程比 Oracle JDK 简单很多,并且不用再去手动配置系统环境变量和 `JAVA_HOME` 了,方便用户上手使用。 diff --git a/source/_posts/Java-Casual-talk.md b/source/_posts/Java-Casual-talk.md new file mode 100644 index 00000000..be0926b3 --- /dev/null +++ b/source/_posts/Java-Casual-talk.md @@ -0,0 +1,177 @@ +--- +title: Java 随谈 — 聊聊我对 Java 的看法 +tags: + - Java +abbrlink: f7c262de +date: 2024-01-10 02:02:20 +--- + +{% note secondary %} +Java 是一种高级的、基于类的面向对象的编程语言,其设计目的是尽可能减少对实现的依赖。它是一种通用编程语言,旨在让程序员一次编写,到处运行(WORA),也就是说,编译后的 Java 代码可以在所有支持 Java 的平台上运行,而无需重新编译。Java 应用程序通常被编译成字节码,可以在任何 Java 虚拟机(JVM)上运行,而不受底层计算机体系结构的限制。Java 的语法与 C 和 C++ 相似,但比它们少了一些底层设施。Java 运行时提供了传统编译语言通常不具备的动态功能(如反射和运行时代码修改)。 - wikipedia +{% endnote %} + + +Java 是一门历史悠久的面向对象的编程语言,生态与产品众多,国内与 Java 有关的开发技术栈也是相当热门。我写过不少关于 Java 的博客(在 CSDN),接触它的时间也不短了,去年还学习了两门新兴的编程语言。 + +今天以一个 Java 用户的身份来聊一聊我个人对 Java 的看法:`它的优缺点`、`与其他语言的比较`、`以及我对它的未来的看法`。 + +**本文默认你是一个有一定 Java 基础的读者,并且对其他编程语言也有一定的了解。** + +## 1. Java 的优点 + +首先呢,Java 它绝对不失为一门好语言。 + +Java 语言的优点有很多: + +1. **跨平台**,Java 语言编写的应用程序可以在不同的操作系统系统上运行(write once, run anywhere)。这种跨平台性是通过 JVM (Java Virtual Machine)。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 Java 虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。 +当然,这种跨平台实现`有利有弊`,也是我们后面要讨论的重点。 +2. **语法相对比 C/C++ 较容易理解**,Java 工具类也特别全面。当我学完 C++ 再来写 Java 代码时直呼太方便了,什么代码库都有现成的供调用。 +3. **生态相当丰富**(maven 仓库、安卓开发、服务端开发框架),很多功能只有你想不到,没有它做不到,直接导包使用就可以。 +4. **对线程的支持相当好**,线程的创建、销毁、同步等等都有现成的 API 可以使用。同步异步写起来也很方便。 +5. **健壮性**,Java 的强类型机制、异常处理、垃圾的自动收集等是 Java 程序健壮性的重要保证。 + +## 2. Java 的缺点 + +但是呢,Java 也有很多为人诟病的问题。 + +下面就来具体阐述一下我的看法,如果有不周到或者浅显、错误的观点,敬请指出。 + +### 2.1 性能与 JVM 的问题 +Java 的性能是令人诟病的,其中有相当一部分是因为 Java 的虚拟机 JVM。其性能表现不理想甚至还体现在基于 Java 的 Android 上。何出此言? + +众所周知,编程语言大体上可分为两类,一类是`编译型`,一类是`脚本型`。 + +Java 表面上虽然是一门编译型语言,但它终归是要在虚拟机里面执行的,光从这一点上来看,它就和脚本语言极为相似(脚本也要依靠解释器去执行)。 + +即使虚拟机再怎么精简,运行时也是需要占用相当部分容量的内存。这一点也体现在打包一个简单的 Java 项目的时候你会很头疼:即使你只写了一个 `hello world` 代码,但是你想要把这个 `hello world` 在系统上以二进制形式直接跑起来,也得打包完整的 JRE。(比如你写好了 Java 代码想 Windows 双击 exe 运行就得打包,因为小白用户总不可能给你提前装个 JRE 吧) + +AOT 编译(Ahead-of-time compilation, 预编译)将代码编译成本地机器代码,能够大大提高 Java 程序的性能,但 Java 不能完全依赖 AOT 去提高性能,多数情况 JIT(Just-in-time, 实时编译) 也是必不可少的。因为 Java 语言具有动态性,它的动态性主要体现在反射(reflection)和动态代理(dynamic proxy)上。通过反射,你可以在运行时获取类的信息并动态操作类的属性、方法等。动态代理允许你在运行时创建代理类,拦截对真实对象的调用并执行自定义的逻辑。 +这就决定了,你`无法在编译时就确定该如何使用 反射 和 动态代理`。因此,JVM 无法在编译时优化这些代码,只能在运行时进行优化。这就是 Java 为什么不能完全依赖 AOT 去提高性能的原因。 + +看到这里,我们似乎就能理解,基于 Java 的 Android 和 Objective-C/Swift 的 iOS,为什么性能会相差甚远(安卓苹果区别较大,编程语言的不同当然只是性能差距的一个重要原因之一,还有原因如:苹果生态对软件有非常一致的规范要求,而且言出法必随 等)。 + +看到这里有的同学可能就会说了。你一直在吐槽 Java 平台的 JVM,但这是 Java 为跨平台性作出必要的牺牲,有了它,Java 才能实现完美的跨平台。你看看 C 语言或者别的`编译型语言`有这样的跨平台能力吗?(脚本性语言就不包括在内了,因为`脚本性语言`本来就是交由解释器来执行的) + +你别说,还真有。`Go` 我觉得就是个比较好的例子。 +简单介绍一下这门语言吧:`Go`(又称 Golang)是由 Google 开发的一门编程语言,注重简洁、高效和并发编程。它具有垃圾回收机制、强大的标准库和并发支持。没有虚拟机,代码直接编译成可执行文件,且支持跨平台编译。 + +众所周知,越新的语言,它的特性、语法糖和工具链等等功能就越完善。比如说 Java 它相对于 C 和 C++ 就做了很多不错的工具类内置。我当初学完 C 和 C++ 再来学习 Java 的时候就直呼太方便了。 + +而 `Go` 这门语言,它在集成了一些更新更好用的语法糖和工具类的同时。还实现了编程语言一直梦寐以求的功能:跨平台编译。 + +可别小瞧了这 5 个字,它代表着即使你是 `Windows` 操作系统,你写好了一份 Go 语言的代码,那么你也可以在 `Windows` 操作系统上 编译出 `Linux` 和 `Mac OS` 系统的二进制文件。(当然系统不止这三个) + +Java 和 GO 的编译执行方式对比: +``` +.java --> .class --> jvm 执行(间接和操作系统打交道) + +.go --> 二进制文件.exe --> 操作系统执行 +``` + +我觉得后者的逻辑是比较`符合程序猿直觉`的:既然我写一份代码就可以直接跨平台编译执行二进制文件了,为什么还要用那个虚拟机占用内存呢? + +### 2.2 版本问题 +GO 语言的开源生态相对 Java 来说还是太弱了,Java 很多时候还依然是必需品。既然如此,有没有办法去改善 Java 的性能问题呢?有,就是尽可能升级 JDK 版本,不要坚守在 Java8。 + +Java 版本分为`非长期支持版本`(non-LTS)和`长期支持版本`(Long Term Support, LTS)。短期支持版本每半年发布一次,长期支持版本每 3 年发布一次。短期支持版本的生命周期只有 6 个月,而长期支持版本的生命周期为 8 年。 +目前,Java 21 是最新的 LTS 版本 但刚出还不太稳定,我推荐使用 Java 17,因为它是上个 LTS 版本 使用比较稳定。Springboot3 最低要求也是 JDK17。 + +性能提升还是相当明显的。 +[JDK8-17 性能对比](https://kstefanj.github.io/2021/11/24/gc-progress-8-17.html) +[JDK21 性能对比](https://timefold.ai/blog/2023/java-21-performance) + +但是国内很多公司还在使用 JDK 8,甚至还有更低的。直到现在,JDK 8 仍然是国内最流行的版本。我理解如果你的项目已经上线了,那么你肯定不会考虑去升级 JDK 版本,因为要投入不少的时间精力与人力成本,这样做还可能会引发一系列的问题。但是如果你是一个新项目,或者项目有长期规划,那么我觉得你可以考虑一下升级 JDK 版本了。Springboot2 最低要求是 JDK8,如上文提到 Springboot3 最低要求是 JDK17,有不小的跨度。希望开源社区和开源产品可以推动 JDK 的更新吧。 + + +### 2.3 商业化使用问题 + +最后就是不得不提的 `商业化使用` 的问题了。 +老话说得好:“你发任你发,我用 Java8”。除了因为上文提到的`生态和兼容问题`而不升级版本,从`商业化角度`来看,这么说也并非空穴来风,Java 8u202 是 Oracle 公司当时发布的最后一个免费的 JDK 版本,之后的版本都是收费的。这也是国内很多公司还在使用 JDK 8 的原因之一。 + +我在写文章的时候刚好看到这篇报道: +{% note warning %} +Java 自 2019 年起采用付费订阅模式,但 2023 年 1 月再次更改了定价模式,`宣布基于公司内总员工数来收取对应的费用,而不是使用 Java SE 的员工数`,这种定价模式的改变将对中小型企业产生重大影响,也引发了巨大的争议。甚至有网友直接爆料,「最近 Oracle“要求”公司每年付 72,000,000 英镑去使用 Java,所以公司关闭了所有的 Java 项目,从每台机器上卸载了 Java,并请来了几十个程序员,用 HTML 等重新创建他们的系统。」 +源于此,根据 TIOBE 指数显示,从 2023 年 1 月到 2024 年 1 月,Java 失去了 4.34% 的市场份额。从 Java 趋势榜单上也可以非常直观地看到,Java 已经降至自 2001 年 TIOBE 指数榜单推出以来的最低位。 +原文链接:https://blog.csdn.net/csdnnews/article/details/135469865 +{% endnote %} + +之前就知道 Oracle 在霍霍 JDK 进行商业化,但没想到又搞出这种幺蛾子。 +Java 开发国内有多火,相信大家应该都有所耳闻。但好端端天胡开局,搞成这样,不得不令人感叹。 +老实讲,`我是真不喜欢 Oracle 这家公司`。一切都以商业化为目的,包括收购的 Java,MySQL 等。将一门编程语言搞得这么商业化还是独一家(主流的哪个不开源免费)。虽说挣钱嘛不寒碜,但这样真的不体面,吃相是真的不好看。 + +反观 C#,相较 Java 的收费与严苛的审查规则,C# 自 2014 年以来一直是开源和免费使用的,没有迹象表明要改为订阅模式。今年 C# 也摘得 2023 年编程语言称号。至于为什么 C# 能至于此,可以看看 [上文这篇博客](https://blog.csdn.net/csdnnews/article/details/135469865),除了这些 也与微软围绕大力推广 .NET 离不开关系 + +最后,我建议要用 Java 就使用开源免费的 OpenJDK,功能上并没有什么大的差别,有些厂商还有自己定制的 OpenJDK。Linux 上默认的 JDK 就是 OpenJDK。 + +如果你是 Windows 系统,甚至可以直接安装 Microsoft 提供的 OpenJDK !(选择 .msi 安装包可以帮你安装、设置 JAVA_HOME,一条龙)。 + +另附上一份 Oracle 旗下的另一款数据库产品 MySQL(大家应该都熟悉)的开源免费替代品 MariaDB 的介绍: +{% note info %} +被甲骨文公司收购后,Oracle 大幅调涨 MySQL 商业版的售价,且甲骨文公司不再支持另一个自由软件项目 OpenSolaris 的发展,因此导致自由软件社群们对于 Oracle 是否还会持续支持 MySQL 社群版(MySQL 之中唯一的免费版本)有所隐忧,MySQL 的创始人麦克尔·维德纽斯 `以 MySQL 为基础`,成立分支计划 MariaDB。 -wikipedia +{% endnote %} + +所以基于开源的考虑,现在 Linux 发行版默认的 JDK 几乎都是 OpenJDK,数据库几乎都是 MariaDB(兼容 MySQL)。(如 Debian 和 ArchLinux) + +## 3. Java 与其他语言的比较 + +### 3.1 Java 与 C/C++ 的比较 + +- 性能:在性能上 C/C++ 是遥遥领先于 Java 的,这也是很多游戏引擎都用 C/C++ 编写的原因。甚至连 Java 的 JVM 本身都是用 C/C++ 写的。JVM 需要与底层系统进行交互,例如内存管理、线程控制等。而众所周知,C/C++ 是最接近底层的高级语言、是系统级编程语言,性能也优异,具有对这些底层操作的更好支持,使得实现 JVM 时更容易处理这些系统级任务。 + +- 语法:Java 语法相对 C/C++ 来说更加简洁,没有指针和复杂的底层操作;C/C++ 语法更加灵活和复杂,支持指针,可以进行更复杂的底层操作。 + +- 内存管理:Java 使用垃圾回收机制,程序员无需手动管理内存。这减少了内存泄漏和悬挂指针等问题,但也可能导致一些性能开销;而 C/C++ 没有垃圾回收机制,C/C++ 允许程序员手动管理内存,包括内存的分配和释放。这给了程序员更大的灵活性,但也增加了出错的可能性。 + +- 跨平台和编译执行过程: + Java 被设计为一种 "Write Once, Run Anywhere"(一次编写,到处运行)的语言,即 Java 程序可以在不同平台上运行而无需重新编译。编译执行过程是:`代码(.java)`先编译成`字节码(.class)`,然后`字节码`由 JVM 解释执行; + C/C++ 的可移植性相对较低(针对不同的操作系统和硬件有不同的写法,生成的二进制文件也不通用),它通常需要针对特定平台进行编译。编译执行过程是:直接编译成二进制文件,由`操作系统`执行。 +- 应用场景:Java 适合开发大型应用程序,例如企业级应用程序、Web 应用程序、移动应用程序等;C/C++ 适合开发系统级应用程序或对性能有较高要求的程序,例如操作系统、驱动程序、游戏引擎、图形应用程序等。 + +### 3.2 Java 与 Python 的比较 + +- 性能:Python 是脚本语言,性能不如 Java。Python 代码在执行时会被解释器逐行解释,性能较低。而 Java 代码是先编译成字节码(编译优化),然后由 JVM 解释执行。 + +- 语法:Python 以其简洁的语法而闻名,比 Java 更简洁。没有类型声明、分号等,代码量更少。 + +- 内存管理:都是使用垃圾回收机制,程序员无需手动管理内存。 + +- 跨平台和编译执行过程:Python 也是一种跨平台语言,但是 Python 代码在不同平台上运行时需要安装 Python 解释器,通过解释器解释执行代码,而 Java 代码在不同平台上运行时需要安装 JVM。实现思路都是类似的,JVM 在我看来何尝不是种解释器呢。 + +- 应用场景:Python 适合用于多种应用场景。例如自动化脚本和任务、Web 应用程序、数据分析、人工智能和自然语言处理等 + +### 3.3 Java 与 Go 的比较 + +- 性能:Go 语言的性能比 Java 稍好,但是差距不大。Go 被设计为一门轻量级语言,具有很好的性能。它使用了垃圾回收机制,帮助管理内存,避免了一些常见的内存错误。Go 语言的性能优势主要体现在并发编程上,Go 语言的并发编程更加简单高效。 + +- 语法:Go 语言的语法比 Java 更简单、直观、清晰,强调代码的可读性和易理解性。 + +- 内存管理:都使用垃圾回收机制,程序员无需手动管理内存。 + +- 跨平台和编译执行过程:Go 是一种静态编译语言,它的程序可以编译成本地机器码。这意味着 Go 程序不需要依赖于虚拟机,可直接在目标平台上运行,无需安装其他运行时环境。而且 Go 还提供了方便的交叉编译工具,可以生成不同操作系统和体系结构的可执行文件!使在一个平台上编译出另一个平台的可执行文件变得容易。编译执行过程是:`代码(.go)`直接编译成二进制文件,然后由`操作系统`执行。 + +- 应用场景:Go 适合用于开发 网络编程、分布式系统、云原生开发、Web 应用程序、系统工具、命令行工具等。 + +### 3.4 Java 与 C# 的比较 + +- 性能:在性能方面,Java 和 C# 在很多方面都非常接近,并且难以明确地说哪一个性能更好。二者都是类似的编译执行过程,也都使用垃圾回收机制。PS:主要是,我几乎没怎么用过 C#,所以不好评价。 + +- 语法:Java 语法是强类型、面向对象的编程范式,语法相对传统和熟悉;C# 的语法设计更加灵活和现代化。它引入了一些先进的语言特性,如 LINQ(Language Integrated Query)、异步编程等,使得代码更为简洁。C#使用属性(Attributes),而Java使用注解(Annotations)来添加元数据和特殊行为。 + +- 内存管理:都是使用垃圾回收机制,程序员无需手动管理内存。 + +- 跨平台和编译执行过程:C# 虽然最初是为 Windows 平台设计的,但通过 .NET Core 和 .NET 5+ 的推动,现在也支持跨平台开发。C# 程序可以使用跨平台的 .NET Core 运行时来执行。 + +- 应用场景:Java 广泛应用于企业级应用、大型系统、Web 开发、移动应用(Android 开发)、云计算等领域。由于其平台无关性和强大的生态系统,Java 在企业级开发中有着重要地位。C# 主要用于 Windows 平台上的开发,包括桌面应用、Web 应用、游戏开发(Unity 游戏引擎)、云服务等。近年来,通过 .NET Core 和 .NET 5+ 的跨平台支持,C# 在开发跨平台应用上的应用场景也在不断增加。 + +## 4. 对 Java 的未来的展望 + +#### GraalVM 的广泛使用以提高性能 +GraalVM 是由 Oracle 开发的一个高性能、通用的虚拟机,支持多种编程语言,包括 Java、JavaScript、Python、Ruby 等。以下是一些关键特性和用途: +多语言支持:GraalVM 支持多种编程语言,使得开发者可以在同一个运行时环境中使用不同语言编写的代码,包括 Java、JavaScript、Python、Ruby 等。这为混合语言的开发提供了便利。 +即时编译器(JIT):GraalVM 包含一个先进的 JIT 编译器,可以提供比传统的 Java 虚拟机更好的性能。它允许将程序源代码直接编译成机器码,而不需要预先将代码编译成字节码。 +Native Image:GraalVM 提供了 Native Image 工具,可以将 Java 程序直接编译成本地可执行文件,减少启动时间和内存占用。也就是我们提到的 AOT 编译。 +嵌入式执行:GraalVM 可以嵌入到其他应用程序中,使得开发者可以在自己的应用中利用 GraalVM 的多语言支持和性能优势。 +支持 Java 17+ 版本。 + +#### 直接使用 Kotlin 代替 Java +Kotlin 是一种静态类型的编程语言,它可以编译成 Java 字节码,也可以编译成本地机器码。Kotlin 由 JetBrains 开发,目前已经成为 Android 开发的首选语言。Kotlin 与 Java 兼容,可以与 Java 代码无缝集成,也可以直接使用 Kotlin 编写 Android 应用程序。Kotlin 语法简洁,易于学习,具有很好的可读性和可维护性。Kotlin 也可以嵌入到其他应用程序中,使得开发者可以在自己的应用中利用 Kotlin 的多语言支持和性能优势。Kotlin 也是一种跨平台语言,Kotlin/Native 允许将 Kotlin 代码编译成本地机器代码,而不是 Java 字节码,可以脱离 JVM,直接在支持的平台上运行编译后的二进制文件。 diff --git a/source/_posts/My-2023-Chronicles-and-Insights.md b/source/_posts/My-2023-Chronicles-and-Insights.md new file mode 100644 index 00000000..52be7b67 --- /dev/null +++ b/source/_posts/My-2023-Chronicles-and-Insights.md @@ -0,0 +1,114 @@ +--- +title: 纪事与感悟 — 我的 2023 +sticky: 100 +tags: + - "2023" +abbrlink: af028bbd +date: 2024-02-12 20:15:28 +--- + +2024 农历甲辰龙年,在这一年一度的新春佳节,祝大家龙年行大运! + +![龙行大运](https://pic1.zhimg.com/80/v2-95bbec13eb9e00e9310fcc23f3225dc4_1440w.webp) + +> 2023 已经过去了,迈入 2024。我总迫切着想记录点什么,记录这一年的点点滴滴或者写点感悟,以后回忆起来应该会感叹,“啊,原来我这一年干了这些事啊,现在看来真有意思”。一边摩挲着手机,一边回忆起青春岁月。 +> +> 本想要在元旦左右写下这一年的感悟与记事,但一来当时考完试打算歇一歇,二来元旦要去中学实习,拖来拖去 一拉一扯就拖到了现在。 + +
+ +兜兜转转又是一年春节,春节是我一年中最无拘无束、感到自由的一段时间,没有繁重的学业负担(中学会有假期作业,但起码过年那会不用考虑)、不用太规律的作息、不用考虑上学的事情、拜访亲戚有红包拿,想怎么玩就怎么玩,所有的烦恼似乎都可以在这段时间里甩开、忘掉。今余得闲,徐而思忆此岁之琐碎细事,如泉之流,如叶之落。 + + +## 技术折腾经历 +过去这一年,仿佛什么都折腾了,又仿佛什么都没折腾。一开始看见别的同学搭服务器玩,想着我也弄一个。白嫖了阿里云的半年学生机,在阿里云买了个域名,开始了我的折腾之路。 + +一开始折腾服务器一窍不通,踩了很多坑,但好在也是学到了很多东西。 + +看到别人都用宝塔面板,我也装了一个,了解了很多运维的知识。别人搭建了自托管的 Bitwarden 服务,我也装了一个,付费的 2FA 免费用,数据全在自己服务器上,直到现在我都还用着,跨平台确实挺方便的。 + +后面看别人用 halo 搭建的博客,我也折腾了一下,安装过程需要 docker-compose,由于没了解过相关 docker 的知识一开始是一窍不通。就初步学习了 docker 的知识和使用,自己折腾了一下午搞成了,过程中我还搞明白了 nginx 的反向代理。 + +halo 博客用了 hao 的主题,是一个非常好看的主题(张洪 Heo 的主题移植),博客内容就复制了一些 kpop 美女展示,没有正儿八经地写博客。但是 halo 有很多诟病的地方,比如写文章体验很差(那个文章编辑器很混乱),springboot 后台内存占用过高等等。后面服务器到期了我就不用 halo 了,转成了 hexo 静态博客,博客全静态生成,清爽无比。 + +宝塔面板也不用了,换成了更牛逼的 1Panel 面板,不仅开源、UI 好看,而且它的应用商店有很多开源的软件、项目可以一键安装部署,反向代理、防火墙、SSH 管理、Swap 分配等功能管理起来都是相当方便。 +服务器也不在阿里云买,换成了 Ucloud 的香港机,因为境内的服务器备案太麻烦了,香港的机器随便折腾。域名同理,转到了 dynadot,可用支付宝支付。 + +域名 DNS 用的是 Cloudflare 的服务,Cloudflare 是真牛逼,提供了很多免费的服务和集成了很多便捷的功能,域名经过它代理的话,还可以隐藏服务器的真实地址,积极跟进很多新的技术协议如 brotli http3 等等。 + +我还学习了几门型新的语言,Rust、Go、Dart,其中前两门都没有达到精通的程度,只是自己写个小程序玩玩。 +- Rust 我一开始被他的宣传吸引,系统级的语言,极致的安全与速度,代价是学习难度特别高,我学了大概三分之一就开摆了。 +- Go 语言是个好东西,有很大的潜力,语法简单,功能强大,我觉得是替代 Java 的不错的选择,但是国内生态好像一般。 +- Flutter 是一个由谷歌开发的开源跨平台应用软件开发工具包,用于为 Android、iOS、Windows、macOS、Linux Desktop 开发应用,编程语言是 Dart。国内有个社区专门负责 Flutter 和 Dart 的汉化,我给他们仓库提过翻译 PR,有幸被合并了。Dart 语言中规中矩。 + +之前用 Github 一直都是直接使用别人的成品 release,再后来 遇到问题会去定位报错、看源码、提 ISSUE。 +23 年学会了给别人的项目提 PR,给一些自己常用的开源项目提过 PR,看到别人 merge 了你的代码,还是挺有成就感的。我也开始写一些小的开源项目,比如一个简单的爬虫、简单的网络连接程序等等。 + + +## 实习经历 +去年也是颇为特殊的一年 —— 我备战考研 今年即将毕业,如果一切顺利,那我就成为一名硕士生,否则就将迈入社会。现在准备着毕设和找工作,希望一切顺利。比较气的是上个月考公没报上(最后那天才想起来要报名),教资则是报上了但是没缴费,被取消资格。😅 + +元旦的时候在市级中学实习。市里的重点中学有两所,一所是附中,一所是市级中学。 + +我实习的内容是上信息技术课,课程比较轻松,压力也小很多,心情也逐渐由忐忑变为从容。 +众所周知,信息课是水课,百分之 95 的学生去机房都是玩电脑的,很少有人听课。不知道你们是不是这样,至少我的中学时代是这么过来的。 + +第一天去的时候是看自习。和同学们说老师有事来不了就让他们自习了(老师是真有事了让我看自习) +从带我实习的老师那里了解到,学校的信息课课程数并不多,他是信息中心的老师,除了上课之外,还负责修理学校老师的电脑,对接公司产品等(如收银机等) + +第二天,听他们信息课课题组备课 讲了很多准备上课的要点和设计理念、思路,我才发现想上好一门课是真的不容易。其中还有老师提到了应试小技巧,比如说课题设计的时候有意引导检查老师往那个思路去想,然后准备好那里的课程,抽查的时候果然问了那里,等等。还有一些逸闻趣事,挺有意思的。 + +带我的老师让我去备课,讲授 python 的循环体结构,我一看这内容这么简单,相信自己一定能够讲好。结果隔天讲下来发现我轻敌了,没上课之前自信心满满,但是上了讲台开始讲课的时候才发现是非常紧张且束手无策,脑子里只有照着 ppt 念下去这个念头。老师给我提了许多意见和改进措施,我回去把教案写了,并且听了一天的课以后才再次走上讲台,这次我有所进步,心情也不再忐忑。 + +其实上课最重要的就是备好课,对要讲授的内容胸有成竹,再就是语速不要太快了,不然学生不仅听不懂,课还容易太早结束。 + +这次实习对我还是有帮助的,作为一名理工男,最缺乏的就是语言的表达能力。虽然计信学院每个学期的课程都会有好几门课程设计,而且都要上讲台亲自演讲,但那种感觉还是不一样的,课设只有老师在认真听,而且老师肯定比你懂,就算讲的很差老师也能理解,并且时间也不到五分钟。但是讲授给学生听就不一样了,他们对于编程一片空白,你需要将知识完整的、以简单易懂的方式传授给他们,需要精心设计与思考,以及自己对于课堂节奏的把握。熟能生巧吧,多做多会。这份技能相信对我的面试也会有所帮助。 + +说到饮食住宿,我在附近租了一个月的房子,且由于是在学校附近,吃饭也不愁,沙县 正新鸡排 炒粉 粉汤 炸鸡等应有具有。房子不大,但是住起来也算舒服,没有热水,热水壶煮水洗。 + + +## 重游附中有感 + +年年岁岁花相似,岁岁年年人不同。 +![年年岁岁花相似,岁岁年年人不同](https://pic4.zhimg.com/80/v2-4afcdf8dd414df34af9aafa2836087f3_1440w.webp) + +2023 这一年充满了未知与迷茫,不似中学时期那样方向明确 只有一个:好好读书,考个好大学。中学时代 6 年在附中,是我人生中最美好的一段时光。前段时间回了一趟母校,发现好像很多东西变了,但是很多东西又没变。 + +那天天气很阴,但我还是很高兴,沿着记忆中的路走了一遍。多年未见,学校里仍然是郁郁葱葱,一片生机盎然,校门附近那些树居然还是没长高,不知道是移植了还是干嘛了。往左走是通往报告厅的路,还记得这条路的大草坪是我们九年级的卫生区,恍惚中仿佛还能回忆起当时扫地和除草的人影。 +![校门口草坪](https://pic3.zhimg.com/80/v2-f066d0e58fe4a40b76e32f2496a064f2_1440w.webp) + + +沿路走下去,就是一条木质长廊,我印象中是高二高三修的,木质长廊在教学楼中间也有,不过不长。但是有很多植物和爬山虎围绕,郁郁葱葱。 +![教学楼旁](https://pic3.zhimg.com/80/v2-470e42f32ed0a32f5806c4ef699d2a3a_1440w.webp) +![教学楼中间](https://pic2.zhimg.com/80/v2-50d05aa0c217c99a2ed2080c2c887ba5_1440w.webp) +路过了 3,4 号教学楼,就来到了体育馆,附中的体育馆很大,在里面我们参加 观看了很多篮球比赛和学校组织的活动。但是很遗憾的是我印象深刻的不多了,印象里大都是来放松缓解学习压力的🤣 + +接着走会穿过体育馆,路过园丁超市,这个超市零食种类很多,有水果蔬菜,还有些食堂的超市买不到的玩意。 + +园丁超市对面是新华书店,印象中是初三左右开的?里面有很多书,中学时我是不折不扣的书迷,体育课摸鱼常常来这里看书,当然更多时候是在寝室看。当时看了很多刘慈欣的科幻长短篇小说,明朝那些事,缥缈录,还有一些名著 但是不多。那个时候看小说看得起劲都是挑灯夜读或者中午有空就看🤣,高三专心投入学习就没这么干了。 +穿过体育馆走廊就是三食堂和操场。 + +三食堂当时是高三学生的专属食堂,不知道现在还是不是。虽然没有进去看,但我现在还记得很清楚,里面是一条长长的通道。要么在门口打饭,要么就在走廊的尽头打饭。走廊的中间摆着若干台电视机,我们在吃饭的时候经常会抬头看。但在附中,吃饭的速度要相当快的,往往没看几眼饭就都吃完了。 + +往右走就是操场,每天都会跑操,高三除外。现在想想真是辛苦,冬天的时候往往天没亮就摸着黑起床了。在 6:30 之前赶到操场来跑步。🤣但是当时我居然都可以很早起床且不迟到 +![操场](https://pic3.zhimg.com/80/v2-48746a5a3ba4caf01df597f2ca82f7be_1440w.webp) +![操场](https://pic3.zhimg.com/80/v2-bb4edbc5b869aa9ad8327af029257262_1440w.webp) +学校每年夏季都会举办运动会,太阳相当毒辣,但好消息是有靓妹看😁乐。我记得我参加过好几次。最后一次参加是在高二,当时我想着说,高三就没机会了,给自己的中学留点回忆,就报名了跑步接力,成绩中规中矩,但起码没给自己的高中生涯留遗憾(比如垂垂老矣了懊悔自己年轻时有东西没体验?不知道老了会不会这么想,反正我当时就是抱着这种心态参加了。和同学过程中训练也挺有趣)。这种心态也直接导致了我大学后面参加运动会,虽然知道自己水平,但还是去参加了。不过唯一遗憾的是自己应该多训练再上场的,大型运动会太大了,人太多了,汗😓。 + +沿着操场外围小走一段就来到了体育馆前的一大片平地,体育课往往都在这里举行。6 年来,所有体育课的缩影似乎都化为了体育课开始的准备动作。一 二 三 四 五 六 七 八 +![体育馆](https://pic2.zhimg.com/80/v2-347c6ca656370e68d34875edc1c355dd_1440w.webp) +穿过体育馆的平地,就来到了 A 栋学生宿舍楼,高三的回忆。这栋宿舍楼地理位置特别好,周末休息,不上课的时候,午休结束直接翻栏杆就能去抢篮球场地。但是现在 1 楼好像都被套防盗网了,难绷。 + +沿着宿舍楼和篮球场的小路就能走到一食堂。 +![篮球场](https://pic1.zhimg.com/80/v2-a071d81c0d0970117328cc62823cc7f0_1440w.webp) +![一食堂](https://pic3.zhimg.com/80/v2-789fac615facf34553bcb49c27f7b60a_1440w.webp) +学校一共就 123 三个食堂。一食堂后面就是 E 栋学生宿舍楼。初一初三还有高一都住这里。印象中 A E 栋的宿管阿姨人特别好,受学生欢迎。八年级则是住 E 栋后面的 F 栋。住宿期间真是发生了很多有意思的趣事,说一天也道不尽。 +比如高一那会儿住在 2 楼宿管阿姨旁边的宿舍,夜里悄悄玩狼人杀,玩到半夜 2 点;和舍友天南海北聊天;放学急急忙忙洗澡。其实细细思索都是很美好的记忆,在那里站许久都能想起不少的事来,只是当时道寻常,现在叹年少不再,下次有空再展开说。 + +沿路右转,就是一条长长的路,通往 12 栋教学楼。我待的最久的教学楼。外面似乎还是老样子,教室我没近距离看。 + +我刚进入学校时 学校方才创立两年,我离开时,学校已然是能够培养出清北优秀学生的省内名校。虽然我最后高考成绩并没有那么理想,但还是要感谢学校给我的这段美好的回忆,感谢所有老师对我的栽培🙏。苦涩的东西总是在若干年后咀嚼反刍才显得那样清甜,怅然若失。 + +就像很多年前我给民哥写过的一封信一样。民哥是我高二的语文老师,我很喜欢上民哥的语文课,因为他相当风趣幽默且教学深入浅出,他经常读我的月考作文。但是我当时成绩不好。从实验班分到下面的班,他在走廊上鼓励我要接着好好学习,语重心长 尊尊教诲。我很感动,也很难过,因为分班就上不了他的课了,后面写了一封信和送了一本毕淑敏的书给他表达不舍。信的内容我记不起了,被读过的作文好像也找不到了。懊悔 难过😔 + +现在大学快毕业了,我会不会像怀念中学这样怀念我的大学时光呢?说实话,我不知道,但我知道应该先过好当下。有空了就多到校园里走走,拍照📸留念一下。愿无悔 diff --git a/source/_posts/New-Installation-of-Archlinux.md b/source/_posts/New-Installation-of-Archlinux.md new file mode 100644 index 00000000..864989f9 --- /dev/null +++ b/source/_posts/New-Installation-of-Archlinux.md @@ -0,0 +1,208 @@ +--- +title: 初来乍到 Archlinux +tags: + - Archlinux + - Linux +abbrlink: 22b3d1e2 +date: 2024-03-21 06:06:15 +--- + + +![Archlinux](https://pic1.zhimg.com/80/v2-ef995f2caaae0845f20544de906553cc_1440w.webp) + + +{% note info %} +`Archlinux` 是一个以简洁、轻量、灵活、可自定义为设计理念的 `Linux` 发行版,致力于通过 **滚动更新** 来更新系统和软件包。默认安装只有最小的基本系统,由用户自行添加需要的软件,它的安装过程相对于其他发行版来说要复杂一些。 + +它有社区维护的 [`AUR`(Arch User Repository)](https://aur.archlinux.org)软件仓库,用户可以在这里找到大量的软件包,通过简单的命令即可编译安装。 +除此以外,`Archlinux` 还有丰富的[官方文档](https://wiki.archlinux.org)和[庞大的社区](https://bbs.archlinux.org/),这些资源详细地描述了安装、配置和维护系统的过程,对新手或者有一定 Linux 基础的用户来说都是非常有帮助的。 + +当然,如果你没有足够的耐心和时间,或者你只是想要一个稳定的系统,并且你没有足够的 `Linux 基础`,那么 `Archlinux` 可能不适合你。 +{% endnote %} + +本文主要记录了我安装 `Archlinux` 的过程。 + +众所周知,[Manjaro](https://manjaro.org) 是一个基于 [Archlinux](https://archlinux.org) 的发行版。 + +我之前久闻 AUR 的大名,决定尝试一下 `Manjaro` 。经过我半年的使用,发现确实很不错,可堪大用,`Manjaro` 开箱即用,内置了很多好用的开源软件,很多系统设置也有对应缺省。开发写代码、日用看视频、写文章等都有不错的体验,除了玩游戏(其实我现在也很少玩游戏了)。 + +`Manjaro` 对 `Archlinux` 进行了很多魔改。 +尽管 Manjaro 使用 pacman 软件包管理器,但它有自己的软件库,如果看镜像源就会发现 Manjaro 的镜像源为 https://mirrors.ustc.edu.cn/manjaro/ 而 Arch 的镜像源为 https://mirrors.ustc.edu.cn/archlinux/ 二者并不完全等价 +且 Manjaro 使用 `archlinuxcn` 的软件源经常出现问题,导致我无法安装一些软件,经过询问相关人员得出结论,Manjaro 可以使用大部分 AUR,但是不要使用 `archlinuxcn`。加之 `Manjaro` 的软件源更新太慢了,用户需要等待几周,才可以安装上游的新版本软件。 + +如此种种致使我想尝试一下原汁原味的 `Archlinux`。 + +下面简单记录一下我的安装过程,以及一些配置,以备日后查阅。 +如果想查看更详细的安装过程,可以参考 [Archlinux 官方文档](https://wiki.archlinux.org/title/Installation_guide),和这篇教程 [Archlinux 安装教程](https://arch.icekylin.online)。建议两篇文章都看一遍,然后再开始安装。 + +## 1. 准备工作 + +### 1.1 确保网络连接 + +确保你有 `网线` 或者 `非中文名的 wifi` 连接,在安装过程中需要连接网络来下载软件包。 + +### 1.2 下载 Archlinux 镜像 + +[官方下载地址](https://archlinux.org/download/) + +如果下载太慢考虑使用上面连接的镜像站下载。 + +如 +`阿里云` 的镜像站:[https://mirrors.aliyun.com/archlinux/iso/latest/](https://mirrors.aliyun.com/archlinux/iso/latest/) +`中科大` 的镜像站:[https://mirrors.ustc.edu.cn/archlinux/iso/latest/](https://mirrors.ustc.edu.cn/archlinux/iso/latest/) +`清华大学` 的镜像站:[https://mirrors.tuna.tsinghua.edu.cn/archlinux/iso/latest/](https://mirrors.tuna.tsinghua.edu.cn/archlinux/iso/latest/) + + +可选操作: +下载完成后,可以选择校验哈希值来确保镜像文件的完整性,在 [Checksums and signatures +](https://archlinux.org/download/#checksums) 有最新镜像的 `SHA256` 哈希值。 + +如果你在使用 Linux,可以使用 `sha256sum` 命令来校验哈希值,如: + +```bash +sha256sum archlinux-2024.03.01-x86_64.iso +``` +将后面的参数替换成你的镜像文件名。 + +如果你在使用 Windows,可以使用 `certutil` 命令来校验哈希值,如: + +```bash +certutil -hashfile archlinux-2024.03.01-x86_64.iso SHA256 +``` + + +### 1.3 给你的硬盘分区 + +给你的硬盘腾出至少 128G 的空间,我分了 300G,看个人需求 尽量分大些免得后期扩容。 +如果你使用 Windows 可以直接 右键开始菜单,点 `磁盘管理` 进行分区(压缩卷),或者使用 `DiskGenius` 等工具进行分区。 + +**还请注意,数据无价!操作需谨慎!** +**在明白你的操作是什么意思之前,不要轻易操作!** + + +### 1.4 制作启动盘 + +我建议使用 `Ventoy` 制作启动盘。`Ventoy` 是一个开源的多功能启动盘制作工具,支持直接将 `ISO` 文件拷贝到 `U 盘` 上,然后通过 `UEFI` 或者 `BIOS` 启动。你可以在里面放置多个 `ISO` 文件,然后选择想要的镜像启动。 + +[Ventoy 官网](https://www.ventoy.net) + + +### 1.5 重启进入 BIOS,启动 Ventoy + +重启电脑,关闭 `Secure Boot`,调整 `Boot Order`,将 `U 盘` 放在第一位,然后保存退出。 + +这个时候时候你的电脑应该会出现 `Ventoy` 的启动界面。如果没有,请检查你的 `BIOS` 设置是否正确,或者查询 `Ventoy` 的文档:https://www.ventoy.net/cn/doc_news.html + +![Ventoy](https://pic4.zhimg.com/80/v2-3fb1906b0609633716b0d08f0e572183_1440w.webp) + +Ventoy 启动后,选择你下载的 Archlinux 镜像文件,然后启动。 + + +## 2. 安装 Archlinux + +安装过程其实没什么好说的了,我是参考教程的 [archlinux 基础安装](https://arch.icekylin.online/guide/rookie/basic-install.html) 进行安装的。 + +注意,安装的时候千万不要跳过、忽略、修改任何步骤(除非你知道你在干什么),否则可能会导致安装失败。如果有不懂的地方要善用搜索引擎。 + +在操作 `7. 分区和格式化` 的时候切记,如果你是 `Windows + Linux 双系统`,安装的时候 **不要格式化 EFI 分区!** **不要格式化 EFI 分区!** **不要格式化 EFI 分区!** + +其他的应该没什么问题,按照教程一步步来,直到安装完成。 +至此,你已经安装好了 Archlinux。 + +输入 `neofetch` 命令,你会看到类似的输出: + +![Arch Neofetch](https://pic2.zhimg.com/80/v2-d88f23c9033a83a9bb5c1b5459290f81_1440w.webp) + +> 图片来自:[wikipedia](https://en.m.wikipedia.org/wiki/File:Arch_Linux_Base_Neofetch_output.png) + +## 3. 安装桌面环境 KDE + +参照上文教程的 `桌面环境与常用应用安装` 一节继续安装。 + +我做出的修改: +- 不开启 `multilib` 仓库,因为我不想要 32 位的软件。 +- 输入法安装:只安装 `fcitx5-im`, `fcitx5-chinese-addons`, 还有 `fcitx5-rime` 输入法引擎 和 `fcitx-configtool`。没有安装 `fcitx5-anthy`, `fcitx5-pinyin-moegirl`, `fcitx5-material-color` 等,因为我不需要。 +- `timeshift` 配置的时候记得不要勾选 `@home`,因为 home 目录包含视频、音乐等大文件,且回滚时不需要回滚这些文件。 + +## 4. 可选配置 + +我做出的改动: +- 我的命令行美化采用 https://gitee.com/mo2/zsh 的 `powerlevel10k` 主题,非常好看。 + +- 小组件只安装了 `Netspeed Widget`,其他的都不需要。 + ![网速组件](https://pic2.zhimg.com/80/v2-47bacfb3127beeac28faef5e9afdb7b5_1440w.webp) + +- grub 引导界面主题采用了 `darkmatter-grub2-theme`,非常好看。 + ![Grub](https://pic2.zhimg.com/80/v2-f02c4381153538b1aed9b9f61367ea7d_1440w.webp) + +## 5. 我安装的软件包 + +### AUR helper +- `yay`:AUR 包管理工具,使用 `go` 语言编写。`archlinuxcn` +- `paru`:AUR 包管理工具,使用 `rust` 语言编写。用法与 `yay` 类似。`archlinuxcn` + +### 开发环境 +- `gcc`(C/C++), `python`:是 Archlinux 默认内置的,不需要额外安装。`core` +- `jdk21-openjdk`:openjdk 21,Java 开发环境,LTS 版本。`extra` +- `go`:Go 语言编译工具。`extra` +- `nodejs-lts-iron`:Node.js 20,LTS 版本。`extra` +- `npm`, `yarn`, `pnpm`: Node.js 包管理工具。`extra` + +### 开发工具 +- `visual-studio-code-bin`:伟大,无需多言。`aur` +- `intellij-idea-ultimate-edition`:强大,无需多言。`aur` +- `beekeeper-studio-bin`:数据库管理工具。`aur` +- `hoppscotch-bin`:API 接口调试工具。`aur` + +### 实用工具 +- `gvim`:是 `vim` 的增强版,支持剪贴板功能。`extra` +- `flameshot`:Linux 著名的截图工具,非常好用。`extra` +- `wireshark-qt`:网络抓包工具。`extra` +- `kdeconnect`:用于连接手机,可以在电脑上接收手机的通知,发送文件等,神器。`extra` +- `spectacle`:KDE 的截图工具,可以截取当前窗口,全屏,矩形等。但是总体没有 `flameshot` 好用。`extra` +- `xclip`:剪贴板工具,可以帮助用户在终端和系统剪贴板之间便捷地复制粘贴数据。`extra` +- `kfind`:文件搜索工具,搜索文件很方便。`extra` +- `obs-studio`:开源的录屏软件,非常好用,听说大主播都用这个。`extra` +- `filelight`:图形化界面直观查看磁盘占用情况。`extra` +- `timeshift`:系统备份工具,可以备份系统快照,方便回滚。`extra` +- `rar`:解压 rar 文件,万恶的 rar 格式。`archlinuxcn` +- `p7zip-natspec`:解压 7z 文件,解决 Ark 中文乱码。`archlinuxcn` + +### 系统组件 +- `openssh`:SSH 客户端和服务端。`core` +- `man-db`:man 帮助文档。`core` +- `typos`:拼写检查工具。`extra` + +### 休闲娱乐办公 +- `linuxqq-nt-bwrap`:Linux 上的 QQ 客户端,现在是用 electron 写的,好看。`aur` +- `wechat-universal-bwrap`:微信终于有了 Linux 非 wine 的好用版本,但功能还是有点少,慢慢加功能吧。`aur` +- `google-chrome`:谷歌浏览器,`aur`。你也可以选择开源的 `chromium`,`extra` +- `onlyoffice-bin`:开源的办公软件,支持云协作。`aur` +- `wps-office-cn`, `wps-office-mui-zh-cn`, `ttf-wps-fonts`, `freetype2-wps`:WPS Office,国产办公软件。`aur` +- `okular`:KDE 的 PDF 阅读器。`extra` + +### 字体 +- `misans`:小米 misans,很好看 适合日用。`aur` +- `ttf-jetbrains-mono-nerd`:JetBrains Mono 字体,适用于终端、代码字体。`extra` + + +## 6. 我的配置 + +- 开机自动启动数字键盘:KDE 系统设置 -> 键盘 -> Plasma 启动时 NumLock 状态 -> 开启 +- 命令行安装软件包 软件包显示颜色:`sudo vim /etc/pacman.conf`, 取消 `Color` 的注释。 +- paru 包序号从最下面开始显示,和 `yay` 一样:`sudo vim /etc/paru.conf`, 取消 `BottomUp` 的注释。 +- 下载软件包的时候不附带 debug 包:`sudo vim /etc/makepkg.conf`, 在 `OPTIONS` 的 `debug` 前面加上 `!`。是最近出现的新问题,以前没遇到过。参考:https://bbs.archlinux.org/viewtopic.php?id=293055 +- 让 Windows 和 Linux 的时间一致:`timedatectl set-local-rtc 1 --adjust-system-clock`。原理:Windows 会假设硬件时钟就是本地时间(Local Time),即硬件时钟存储的时间是与所在时区相同的时间,如东八区。而 Linux 会假设硬件时钟是协调世界时(UTC)时间。所以在 Linux 下设置硬件时钟为本地时间,Windows 和 Linux 的时间就会一致了。 +- `vim ~/.ssh/config`, 创建 ssh 配置文件,配置 github ssh 推送走 443 端口,避免被坤场阻止 22 端口: + ```config + Host github.com + Hostname ssh.github.com + Port 443 + User git + ``` + +## 7. 总结 + +吐槽一下,Arch 确实用得很清爽,没什么多余的东西。就是安装太折磨人了,我花了一天多才搞明白。`Archinstall` 脚本安装 还安装失败了,我只能手动安装。不过好在手动安装的教程很详细,再加上朋友的帮助,一步步就能搞定。镜像里面自带的 `Archinstall` 还不是最新版(因为有个小依赖 bug 修复,需要 pacman 手动更新)。 + +这篇文章可能还不太完善,在日后的使用中我会不断完善它。埋个坑 diff --git a/source/_posts/Nginx-installation-and-usage-tutorial.md b/source/_posts/Nginx-installation-and-usage-tutorial.md new file mode 100644 index 00000000..11c6c3c8 --- /dev/null +++ b/source/_posts/Nginx-installation-and-usage-tutorial.md @@ -0,0 +1,309 @@ +--- +title: Nginx 安装与使用教程 +tags: + - Nginx + - 部署 + - 运维 +abbrlink: 6645bed3 +date: 2024-03-02 14:04:40 +--- +![Nginx](https://pic3.zhimg.com/80/v2-118cd0af64df927a447a02272e1022de_1440w.webp) + +{% note secondary %} +Nginx 是一个高性能的开源 Web 服务器,也可以作为反向代理服务器、负载均衡器和 HTTP 缓存。其轻量级且高效的设计使其在处理高并发请求时表现优异。Nginx 采用事件驱动的异步架构,能够有效地处理大量连接而不会消耗过多系统资源。它支持多种功能模块和扩展,可以满足各种 Web 服务的需求。由于其稳定性、性能和可靠性,Nginx 已成为许多网站和应用程序的首选服务器。 +{% endnote %} + +其中 `Nginx` 是市场占有量最高的 Web 服务器,没有之一。如果你是运维或者开发人员,那么我相信你多多少少一定会接触到 Nginx 的相关操作。 + +本文将介绍 Nginx 的安装和基本配置,以及一些常用的功能和技巧。以 Debian12 为例,其他 Linux 发行版的安装方法类似。假设你已经拥有一个域名和一台能联网的服务器。 + + +## 1. 安装 Nginx + +输入以下命令安装 Nginx: +```bash +sudo apt update +sudo apt install nginx -y +``` + +安装完成后,可以使用以下命令检查 Nginx 的版本: +```bash +nginx -v +``` +当前教程演示的 Nginx 版本是 `1.22.1`。 + +## 2. 启动 Nginx + +安装完成后,Nginx 会自动启动。可以使用以下命令检查 Nginx 服务的状态: +```bash +sudo systemctl status nginx +``` +如果输出中显示 `Active: active (running)`,则表示 Nginx 已成功启动。 + +如果 Nginx 未启动,可以根据报错信息排查问题,解决后尝试手动启动 Nginx: +```bash +sudo systemctl start nginx +``` + +现在,可以在浏览器中输入服务器的 IP 地址或域名,就会看到 Nginx 的默认欢迎页面。 +![Nginx 欢迎页](https://pic1.zhimg.com/80/v2-6beedcc888ee88363467453a3a40d38c_1440w.webp) + + +## 3. 了解 Nginx + + +### 3.1 Nginx 配置文件 +Nginx 的默认配置文件位于 `/etc/nginx` 目录下 + +我们可以输出目录下的文件列表: +```bash +ls /etc/nginx +``` + +输出如下: +```bash +conf.d koi-utf modules-available proxy_params sites-enabled win-utf +fastcgi.conf koi-win modules-enabled scgi_params snippets +fastcgi_params mime.types nginx.conf sites-available uwsgi_params +``` + +其中, +- `nginx.conf` 是 Nginx 的`主配置文件` +- `sites-available` 目录下存放着`所有可用的网站配置文件` +- `sites-enabled` 目录下存放着`启用的网站配置文件` +- `conf.d` 目录下存放着`其他配置文件` + + +### 3.2 Nginx 常用命令 +Nginx 的常用命令如下: + +- `sudo nginx -t`:检查 nginx 配置文件是否正确: +- `sudo nginx -s reload`:重新加载配置文件,优雅地重新启动 +- `sudo nginx -s quit`:优雅地关闭 +- `sudo nginx -s stop`:快速关闭 +- `sudo systemctl status nginx`:查看 Nginx 服务的状态 + + +## 4. 配置网站 + +![Nginx 虚拟主机](https://pic2.zhimg.com/80/v2-4e0fb528e7ecf15e79a9133986eae349_1440w.webp) + +我们现在演示如何配置 `example.com`,使得访问 `example.com` 就会显示 `Hello World !` 页面。 + +假设你的域名为 `example.com`,且在域名供应商域名解析处已经将 `example.com` 解析到服务器的 IP 地址。 + + +### 4.1 创建网站根目录 + +`/var/www` 目录通常用于存放网站文件,我们可以在这个目录下创建一个目录,用于存放 `example.com` 的网站文件。 + +```bash +sudo mkdir -p /var/www/example.com +``` +并在其中创建一个 `index.html` 文件: +```bash +sudo vim /var/www/example.com/index.html +``` + +将以下内容粘贴到 `index.html` 文件中: +{% fold info @html 代码 %} +```html + + + + + + 漠北残月 + + +

Hello World !

+ + +``` +{% endfold %} +保存并退出编辑器。 + + +### 4.2 创建网站配置文件 + +那么,现在可以在 `sites-available` 目录下创建一个 Nginx 配置文件 `example.com.conf`: +```bash +sudo vim /etc/nginx/sites-available/example.com.conf +``` + +将以下内容粘贴到文件中: +```nginx +server { + listen 80; 监听 80 端口(HTTP) + server_name example.com; 域名 + + root /var/www/example.com; 文档根目录 + index index.html; 默认文件 + + location / { + try_files $uri $uri/ =404; + } +} +``` +保存并退出编辑器。 + +- `server{ }` 定义一个虚拟主机 +- `listen 80;` 监听 80 端口(HTTP) +- `server_name example.com;` 域名 +- `root /var/www/example.com;` 文档根目录 +- `index index.html;` 默认文件 +- `location /` `/` 表示所有以`/`开头的请求(也就是所有请求) +- `try_files $uri $uri/ =404;` 检查请求的文件是否存在,如果不存在则返回 404 错误 + +这样,Nginx 就会监听 `example.com` 的请求,并返回 `/var/www/example.com` 目录下的文件。 + + +测试配置文件是否编写正确: +```bash +sudo nginx -t +``` +如果没有错误,将输出以下内容: +```bash +nginx: the configuration file /etc/nginx/nginx.conf syntax is ok +nginx: configuration file /etc/nginx/nginx.conf test is successful +``` + + +### 4.3 启用网站配置 + +接下来,需要在 `sites-enabled` 目录下创建一个符号链接,指向 `sites-available` 目录下的配置文件: +```bash +sudo ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/ +``` + +然后,重新加载 Nginx 配置文件: +```bash +sudo systemctl reload nginx +``` + +现在,可以在浏览器中输入 `example.com`,就会看到 `Hello World !` 页面。 +![Hello World](https://pic3.zhimg.com/80/v2-1c2cfed9b0363a87826ee47d8781f43a_1440w.webp) + +### 4.4 执行流程 +整个执行流程如下: +1. 浏览器发送请求到服务器 +2. Nginx 接收到请求,根据请求的域名和端口,选择对应的网站配置文件 +3. Nginx 根据配置文件中的 `root` 指令,找到对应的文档根目录 +4. Nginx 根据配置文件中的 `index` 指令,找到默认文件 +5. Nginx 返回默认文件的内容给浏览器 +6. 浏览器显示页面 + + +## 5. 配置反向代理 + +![反向代理](https://pic4.zhimg.com/80/v2-23767a77ae76b8280a695bb3ff45f3eb_1440w.webp) + +Nginx 的反向代理是我们常用到的功能,它可以隐藏真实服务器地址,提高安全性,还可以实现负载均衡和缓存等功能。 + +假设你的域名为 `website.com`,并且你的服务器上有一个运行在 8080 端口的应用程序,你希望用户通过 `website.com` 访问这个应用程序,而不是通过 `website.com:8080` 直接访问。 +![没反向代理的网站](https://pic2.zhimg.com/80/v2-8daac8f8ba3b016f1eeb570f4c092af1_1440w.webp) +![反向代理过的网站](https://pic4.zhimg.com/80/v2-336d8da792bb9f774abb3c42a18fd2a3_1440w.webp) + + +### 5.1 创建反向代理配置文件 + +在 `sites-available` 目录下创建一个 Nginx 配置文件 `website.com.conf`: +```bash +sudo vim /etc/nginx/sites-available/website.com.conf +``` + +将以下内容粘贴到文件中: +```nginx +server { + listen 80; + server_name website.com; + + location / { + proxy_pass http://127.0.0.1:8080; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` +保存并退出编辑器。 + +这个配置文件定义了一个简单的反向代理。 +- `proxy_pass http://127.0.0.1:8080;` 将请求转发给 127.0.0.1:8080 端口来处理 +- `proxy_set_header` 设置请求头,这些请求头会被传递给后端服务器 + + +测试配置文件是否编写正确: +```bash +sudo nginx -t +``` + + +### 5.2 启用反向代理 + +接下来,需要在 `sites-enabled` 目录下创建一个符号链接,指向 `sites-available` 目录下的配置文件: +```bash +sudo ln -s /etc/nginx/sites-available/website.com.conf /etc/nginx/sites-enabled/ +``` + +然后,重新加载 Nginx 配置文件: +```bash +sudo systemctl reload nginx +``` + +现在再启动 Python Web 服务器,然后在浏览器中输入 `website.com`,就会看到 `Reverse Proxy` 页面。这时,`website.com` 就会显示 `website.com:8080` 的内容。 +```bash +cd /var/www/website.com +python3 -m http.server 8080 +``` + +![反向代理](https://pic4.zhimg.com/80/v2-336d8da792bb9f774abb3c42a18fd2a3_1440w.webp) + + +### 5.3 执行流程 +整个执行流程如下: +1. 浏览器发送请求到服务器 +2. Nginx 接收到请求,根据请求的域名和端口,选择对应的网站配置文件 +3. Nginx 根据配置文件中的 `location /` 指令,将请求转发给 `http://127.0.0.1:8080` 端口处理 +4. Python Web 服务器处理请求,返回 `Reverse Proxy` 页面 +5. Nginx 返回 `Reverse Proxy` 页面给浏览器 +6. 浏览器显示页面 + + +### 5.5 反向代理常见实践 +反向代理由于隐藏了实际后端服务的端口号,可以直接通过域名来访问。为了隐藏多个应用程序的端口号,我们通常会配置多个三级域名(如 `status.example.com` 和 `chat.example.com`)来对应不同的应用程序,实现一个主域名下(`example.com`)多个应用程序的访问。 + +例如,我们可以配置 `app1.website.com` 和 `app2.website.com`,分别代理到不同的应用程序。 + +```nginx +server { + listen 80; + server_name app1.website.com; + + location / { + proxy_pass http://127.0.0.1:8081; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + +```nginx +server { + listen 80; + server_name app2.website.com; + + location / { + proxy_pass http://127.0.0.1:8082; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + +更多 Nginx 的配置和功能,可以参考官方文档: [Nginx Documentation](https://nginx.org/en/docs/)。 diff --git a/source/_posts/Open-Source-Software-Recommendations.md b/source/_posts/Open-Source-Software-Recommendations.md new file mode 100644 index 00000000..31a30cf1 --- /dev/null +++ b/source/_posts/Open-Source-Software-Recommendations.md @@ -0,0 +1,26 @@ +--- +title: 服务器推荐部署的开源软件 +sticky: 101 +abbrlink: f297b285 +date: 2024-01-25 14:05:33 +tags: + - open-source +--- + +- `1Panel`,现代化、开源的 Linux 服务器运维管理面板:{% post_link 1panel-installation-and-usage-tutorial '1Panel 安装配置教程' %} + +- `Alist`,支持多种存储的文件列表程序:{% post_link Deploying-a-Web-Disk-of-Your-Own '部署自己的网盘 — Alist 安装配置教程' %} + +- `Bitwarden`,开源密码管理解决方案: {% post_link Vaultwarden-installation-and-usage-tutorial 'Bitwarden (Vaultwarden) 部署使用教程' %} + +- `Caddy`,现代化的 Web 服务器,具有自动 HTTPS、HTTP/3、反向代理、负载均衡、静态文件服务等功能:{% post_link Caddy-installation-and-usage-tutorial 'Caddy 安装使用教程' %} + +- `Fail2ban`,是一个入侵检测系统框架,可以保护电脑服务器免受暴力破解等攻击:{% post_link Fail2ban-installation-and-usage-tutorial 'Fail2ban 安装使用教程' %} + +- `Hexo`,快速、简洁且高效的博客框架:{% post_link Hexo-blog-deployment-tutorial 'Hexo 博客部署教程' %} + +- `Nginx`,高性能的 HTTP 和反向代理服务器:{% post_link Nginx-installation-and-usage-tutorial 'Nginx 安装使用教程' %} + +- `Umami`,简单、快速、注重隐私的开源分析解决方案:{% post_link Umami-installation-and-usage-tutorial 'Umami 安装使用教程' %} + +- `Uptime Kuma`,精致的自托管监控工具:{% post_link Using-uptime-kuma-as-Status-Page 'Uptime-Kuma 安装使用教程' %} diff --git a/source/_posts/Recording-the-Good-Life-1.md b/source/_posts/Recording-the-Good-Life-1.md new file mode 100644 index 00000000..4c43aee3 --- /dev/null +++ b/source/_posts/Recording-the-Good-Life-1.md @@ -0,0 +1,140 @@ +--- +title: 久违的放松与电影观后感 — 记录美好生活(一) +tags: + - 日常 +abbrlink: b92ae1fe +date: 2024-04-02 19:01:33 +--- +多图预警!!! + +3 月是个忙碌且紧张焦虑的月份,备考、写论文、参加招聘会、投简历,很多事情堆压让我感到异常疲惫、精神紧绷,整个人也不太好。 +但是,3 月份终于结束了,4 月已至,我也在昨天好好放松了一下,开始新的篇章。 + +### 一曲高歌一樽酒,一人独钓一江秋。 + +考完试的那天下午,我走出考场,感到阳光很明媚,我的心情也很好,考点学校的装修风格别有一番老式职工楼的风味。走出学校,漫步在街道上,看着周围的景色,感觉一切都是那么美好,天气有些闷热,风也不急不躁。吃完午饭回到住处,打开空调,终于可以随心所欲地休息了,刷着 B 站,敲着代码,感觉很好。 + +也许,远在四年前高考结束时的我,可能也有类似的感悟和微妙的心绪,对当时的我来说,高中的一切都还是那么熟悉,没有来得及好好感悟和说再见就已然结束了。 + +![考完试的天空](https://pic4.zhimg.com/80/v2-29b4762ef455ea245348ec968bbcea87_1440w.webp) + +![隆江猪脚饭](https://pic3.zhimg.com/80/v2-aa1df539f7ad5ee595428d1678176e2a_1440w.webp) + +![炫火锅](https://pic4.zhimg.com/80/v2-8e7619cf857065958c66010006e7f56f_1440w.webp) + +--- + +### 去留无意,望天上云卷云舒。 + +坐飞机所见的白雪皑皑的云层,大自然的瑰丽,是人的言语无法形容的。云层很美,我心情也很好。 + +有时候不禁在想,李白要是坐了飞机,看到这样的云层,会不会写出更加气势磅礴的诗句呢? + +这是玉皇大帝的宫殿吗?这是神仙的仙界吗?如果他们真的存在,那他们现在在哪? + +![云层](https://pic4.zhimg.com/80/v2-4cc817639180e4d7a020f246f5c3d71f_1440w.webp) +![云层](https://pic1.zhimg.com/80/v2-3cc63d236179fc4007b96e4ebebce540_1440w.jpg) +![云层](https://pic1.zhimg.com/80/v2-25feed5440c14c4837966f64c11d8bc8_1440w.webp) +![云层](https://pic3.zhimg.com/80/v2-3503722b032fcfa22902830a9132da76_1440w.webp) +![云层](https://pic3.zhimg.com/80/v2-8d21c167c3635cf41c9f2f7a4913779e_1440w.webp) + +下面是我拍摄的一段飞机云中穿行的视频,感觉略有意境。 + + + + + +--- + +### 山随平野尽,江入大荒流。 + +江边的风景也很美,分不清是嘉陵江还是长江。 + +一边是现代化建筑,一边是郁郁葱葱,现代与自然风景的结合。江上散落着许多货船,一片繁忙景象。 + +![江景](https://pic1.zhimg.com/80/v2-cfa3d85082dcccc74fb94e8826bcdb1c_1440w.webp) +![江景](https://pic4.zhimg.com/80/v2-e65afb7f7ff4b3ffd02011c70415deaf_1440w.webp) + +欲穷千里目,更上一层楼。果然是有道理的。 + +--- + +### 金樽清酒斗十千,玉盘珍羞直万钱。 + +和同学炫烧烤,吃得很爽。很久没有这样胃口好放开吃过了。战斗,爽! + +这家自助烧烤 食材好,分量足,种类多,肉非常鲜美,吃起来嘎嘎香,我们去的时候没什么人,服务员还一直在旁边帮忙烤烧烤,真是非常顶级的体验。 + +![烧烤](https://pic4.zhimg.com/80/v2-21bdec7110edeaeb9fab8f5d1b82981b_1440w.webp) +![烧烤](https://pic2.zhimg.com/80/v2-42c853445d5250d6bce410b68abf00a5_1440w.webp) +![烧烤](https://pic4.zhimg.com/80/v2-390ebdbb19a1cf56a3eba5d8ae04020b_1440w.webp) +![烧烤](https://pic4.zhimg.com/80/v2-208f004b2b846632f9be2e0995da93d3_1440w.webp) + +值得一提的是居然还有海鲜,味道不错。 + +![烧烤](https://pic2.zhimg.com/80/v2-20377146b08b082404975baa6aa6a2d5_1440w.webp) +![烧烤](https://pic3.zhimg.com/80/v2-f848bd04486b05376a40d9bf5547cde6_1440w.webp) + +--- + +### 君子以遏恶扬善,顺天休命。 + +周处除三害,很有意思,难得在内地看到这种类型的片子,电影引用古文典故,结合黑帮复仇、犯罪动作、暴力美学。 + +![周处除三害](https://pic4.zhimg.com/80/v2-e50e8780de15fa096f3512c5554b767f_1440w.jpg) + + +**`周处除三害`** 是典故,出自《晋书·周处传》和《世说新语》。 + +> 周处年轻时凶暴任性,被同乡的人认为是一大祸害。加上,河中有蛟龙,山上有猛虎,一起侵害百姓。义兴的百姓称他们是三害,而三害中周处最为厉害。有人劝说周处去杀死猛虎和蛟龙,实际上是希望三个祸害拼杀后只剩下一个。 +> +> 周处上山除猛虎斩蛟龙,三天三夜未归。乡亲们都认为他已经死了,遂互相庆祝。周处终于杀死了蛟龙归来,听说乡里人以为自己已死而互相庆贺,才知道自己实际上被当作一大祸害,因此有了悔改的心意,从此改过自新,最终成为历史上有名的忠臣孝子。 + +影片里的陈桂林的定位也和周处类似。 + +{% note primary %} +故事围绕黑道人物陈桂林展开。他在黑道大哥洪爷的葬礼上,在众目睽睽的情况下枪杀铁头哥,和警察搏斗后逃脱。 + +四年后,他得知自己身患重病,决定自首,却发现自己在警方的通缉榜上仅排第三,因此决意要成为除三害的周处,以自己的方式留名。 + +他通过绑架假象逼问出另一名黑道人物香港仔的线索,并在一场紧张的对决中成功击败并杀死香港仔。随后,他前往寻找另一名黑帮成员牛头林禄和,但在澎湖的新心灵舍宗教团体中,他发现自己身患的肺癌竟然好转,于是决定加入宗教以了结罪孽。 + +然而,他逐渐发现这个宗教团体其实是个骗局,尊者就是他要找的牛头林禄和。在一场激烈的冲突中,他揭露了尊者的真实身份并枪杀了他。尽管他成功揭露了宗教骗局,但教派并未因此解散,他只好大开杀戒,屠戮了留在现场继续唱歌的教徒和尊者的情妇。 + +在返回台湾的船上,他劫持了一名女子,用她的手机打电话给一直追捕他的刑警陈灰,并笑着向他自首。在监狱里,他得知真正患肺癌的是一直劝他自首的张医生,而她这么做是为了弥补过去的罪孽。最终,陈桂林在受枪决前平静地伏法,结束了自己的黑道生涯。 +{% endnote %} + +影片其实自始至终都包含着 `周处除三害` 的暗喻: +男主黑道犯罪 扰乱治安 是为周处 +男主除代表“**嗔**”的香港仔 是为周处除猛虎 +男主除代表“**贪**”的尊者 是为周处除蛟龙 + +但这如果就结束了,它就不是一部好电影。 +医生告诉他其实没有患癌,一切的一切都是医生为了让他去自首,让他去面对自己的罪孽,没想到最后他了解了猛虎和蛟龙;小美来找男主,替男主刮胡子,男主终于留下了悔恨的泪水。 +最后,男主被枪决,他的生命结束了,他的罪孽也结束了,是为除心魔(“**痴**”)。 +构成了完整意义上的 `周处除三害`。 + +`周处除三害` 这个故事的核心,不是 `除`,而是 `悔悟`,只有悔悟了,历史上那个曾经的祸害才能成为忠臣孝子,陈桂林也要认识到自己的罪孽,“痴”才算是真正的被除掉。 + +如果没有最后的流泪悔悟,那这个故事就不是周处除三害,而是 `贪嗔痴` 三毒互噬,真正改变周处的,是他的内心的潘然悔悟。 + +影片里其实还有很多细节值得回味,比如给了新心灵舍很多镜头,它的蛊惑 它的卑劣害人手段 它的洗脑 和医生勾结,影片不置一句邪教好坏,但是观众却可以感觉到它处处都是危害。最后男主发现了尊者的真面目,取枪除害 也是个名场面。 + +这里贴一个 B 站很好的解说视频,虽然有些小细节没有提到,但是寓意和故事的解读都很到位。 + +
+ +
+ +
+ + +![周处除三害](https://pic4.zhimg.com/80/v2-eb393b512ffc4a76e1bf68110a6f576b_1440w.webp) +![周处除三害](https://pic1.zhimg.com/80/v2-c0ca7c815acfa56b4bd82e1a73442838_1440w.webp) +![周处除三害](https://pic3.zhimg.com/80/v2-d23d8f56bb8673ffd536400c771b2e42_1440w.webp) +![周处除三害](https://pic2.zhimg.com/80/v2-649df7aa00cc09bdc85bf50e581941a9_1440w.webp) +![周处除三害](https://pic3.zhimg.com/80/v2-271fae28bdf1779fd7317f8bd8c86b5a_1440w.webp) + +希望以后影片引进的尺度可以更大一些,类型更加多样化,不要再只有主旋律和爱情片了。 + +总之,今天是个好日子,一扫颓势,换个好心情,重新整装再出发。希望我考编上岸,希望我论文顺利,希望我找到好工作,一切顺利!!! diff --git a/source/_posts/Tutorial-of-Building-a-blog.md b/source/_posts/Tutorial-of-Building-a-blog.md new file mode 100644 index 00000000..c36ae437 --- /dev/null +++ b/source/_posts/Tutorial-of-Building-a-blog.md @@ -0,0 +1,18 @@ +--- +title: 博客搭建相关教程 +abbrlink: 6db78a27 +date: 2023-12-28 19:03:00 +tags: +--- +## 目录 + +### Hexo 博客部署 +- {% post_link Hexo-blog-deployment-tutorial 'Hexo 博客部署教程' %} +- {% post_link Enable-blog-comment '启用博客评论 Giscus' %} + +### Fluid 主题、美化相关 +- {% post_link Fluid-theme-installation '安装 Fluid 主题' %} +- {% post_link Use-lxgw-wenkai-in-fluid '如何在博客中使用霞鹜文楷字体' %} + +### 博客优化 +- {% post_link Blog-seo-optimization '博客 SEO 优化' %} diff --git a/source/_posts/Umami-installation-and-usage-tutorial.md b/source/_posts/Umami-installation-and-usage-tutorial.md new file mode 100644 index 00000000..218d1732 --- /dev/null +++ b/source/_posts/Umami-installation-and-usage-tutorial.md @@ -0,0 +1,119 @@ +--- +title: Umami 安装使用教程 +tags: + - 部署 + - Umami +abbrlink: f7a090e6 +date: 2024-01-24 11:55:35 +--- +> Umami is a simple, fast, privacy-focused alternative to Google Analytics. +> +> Umami 是一个简单、快速、注重隐私的 Google Analytics 替代品。 + +![Umami 官网图](https://pic3.zhimg.com/80/v2-8a1bb7c3a6401964fbf1cc2ca92f2dc6_1440w.webp) + +## 1. 什么是 Umami,为什么要使用它? + +Umami 是一个简单、快速、注重隐私的开源分析解决方案,是 Google Analytics 的替代品。可轻松收集、分析和了解您的网络数据,同时维护访客隐私和数据所有权。不收集个人身份信息,不使用 Cookie,所有数据都经过匿名处理,符合 GDPR。 + +它是一个网站统计工具,可以帮助你分析网站的访问情况,比如访问量、访问来源、访问时间等等。这对于静态网站来说是非常有用的,因为静态网站无法像动态网站一样通过后端代码来统计访问情况。 + +## 2. 安装 Umami + +{% fold info @1Panel 一键安装 %} +打开 `1Panel` 面板,点击 `应用商店`,搜索 `umami`,点击 `安装` 即可。 + +{% post_link 1panel-installation-and-usage-tutorial '1Panel 安装配置教程' %} +{% endfold %} + +{% fold info @从源码安装 %} +要求: +Node.js >= 16.13 +MySQL or Postgresql + +- 安装 Yarn +```bash +npm install -g yarn +``` + +- 获取源码并安装依赖 +```bash +git clone https://github.com/umami-software/umami.git +cd umami +yarn install +``` + +- 配置 Umami +创建一个 `.env` 文件,内容如下: +``` +DATABASE_URL=connection-url +``` +其中 `connection-url` 为数据库连接地址,如 +``` +postgresql://username:mypassword@localhost:5432/mydb +``` +``` +mysql://username:mypassword@localhost:3306/mydb +``` + +- 构建 Umami +```bash +yarn build +``` + +- 启动 Umami +```bash +yarn start +``` + +{% endfold %} + +{% fold info @docker-compose 安装 %} +下载官方的 docker-compose.yml 文件: +https://github.com/umami-software/umami/blob/master/docker-compose.yml + +配置里默认是 Postgresql 数据库,如果你想使用 MySQL 数据库,可以修改 `docker-compose.yml` 文件,将 `DATABASE_URL` 的 `postgres` 替换为 `mysql`,并修改 `DATABASE_URL` 为 MySQL 对应的链接。 + +然后运行: +```bash +docker-compose up -d +``` +{% endfold %} + +默认情况下,应用程序将在 http://localhost:3000 上启动。你可能需要代理 Web 服务器的请求,或更改端口来直接为应用程序提供服务。 + + +## 3. 修改 Umami 密码 +Umami 启动后,默认用户名为 `admin`,默认密码为 `umami`。 + +第一件事是修改密码,选择 `Setting` -> `Profile`,然后设置你的新密码。 +![修改密码](https://pic4.zhimg.com/80/v2-8e5d01834b102bd9acedb220fe8cc29f_1440w.webp) + +点击右上角的地球图标,修改语言为 `中文`。 + +## 4. 添加网站 + +点击 `设置` -> `网站` -> `添加网站`,输入你的网站地址,点击 `添加` 即可。 +![添加网站](https://pic1.zhimg.com/80/v2-09b94e9c1d79acc10492e9954edd48f8_1440w.webp) + +填写信息后,点击 `编辑` +![编辑](https://pic2.zhimg.com/80/v2-8c75210e16bdb9ac1ad31ce04ec6014d_1440w.webp) + +再点击 `跟踪代码`,复制代码到你的网站中即可。 +![跟踪代码](https://pic3.zhimg.com/80/v2-9da304c3d1550731e064f3d9353b6296_1440w.webp) + +```javascript + +``` + +如果你在本地写博客,你会发现 `localhost` 也被统计了,可以添加 `data-domains` 属性,只统计你的域名: + +```javascript + +``` +如果你想遵循访客的 `Do Not Track` 设置,可以添加 `data-do-not-track` 属性: + +```javascript + +``` +更多使用方法请参考官方文档:https://umami.is/docs/tracker-configuration diff --git a/source/_posts/Use-lxgw-wenkai-in-fluid.md b/source/_posts/Use-lxgw-wenkai-in-fluid.md new file mode 100644 index 00000000..fa1e531a --- /dev/null +++ b/source/_posts/Use-lxgw-wenkai-in-fluid.md @@ -0,0 +1,90 @@ +--- +title: 如何在博客中使用霞鹜文楷字体 +tags: + - Hexo + - Fluid +abbrlink: f24b41b1 +date: 2023-12-27 14:58:04 +--- + +近来阅读竹林里有冰的博客,发现他的博客字体很好看,想着把他的字体也用到我的博客里,于是就有了这篇文章。 + +## 1. 字体介绍 +[霞鹜文楷字体仓库](https://github.com/lxgw/LxgwWenKai) +霞鹜文楷 我之前其实在手机上用过,不过后面由于装机加上懒得折腾就没有再设置了,但是博客我觉得为了好的阅读体验还是可以换一下的 +![霞鹜文楷](https://pic1.zhimg.com/80/v2-c1e0f7f058fbbf1cc6ac3aa0a2480178_1440w.webp) + +关于在 web 中使用 霞鹜文楷 请参阅 [issue#24](https://github.com/lxgw/LxgwWenKai/issues/24) + +其中 [chawyehsu](https://github.com/chawyehsu/lxgw-wenkai-webfont) 提供了打包,竹林里有冰教程中引用的就是其打包字体,但是点进去仓库发现已经有半年没更新了。在 issue 的下面我们可以看到 [CMBill](https://github.com/CMBill/lxgw-wenkai-screen-web) 提供了一个新的打包,我的教程就是这个打包。 + +在 [CMBill](https://github.com/CMBill/lxgw-wenkai-screen-web) 的仓库 README 中跳转 [css](https://cdn.jsdelivr.net/npm/lxgw-wenkai-screen-web/style.css) 看看内容: + +```css +@import url('./lxgwwenkaigbscreen/result.css'); +@import url('./lxgwwenkaimonogbscreen/result.css'); +@import url('./lxgwwenkaimonoscreen/result.css'); +@import url('./lxgwwenkaiscreen/result.css'); +``` + + +可以发现这个 css 分了几个不同的字体种类,有不同的霞鹜文楷变体可供选择 +将 `style.css` 替换为 `@import url` 之后的内容(去掉./),就可以直接使用了 + +我的博客字体文件为 +`https://cdn.jsdelivr.net/npm/lxgw-wenkai-screen-web/lxgwwenkaiscreen/result.css` + +## 2. 使用方法 + +### 2.1 直接引用 +直接将文后提供的链接以 `` 的形式添加到网页的 `` 内即可。 +```html + + + + + + + + + +``` + +### 2.2 Hexo 博客 +如果你使用的是 Hexo 博客,可以采用注入的方式,将字体 css 注入到你的博客中。 +首先在根目录创建一个 `scripts` 文件夹,然后在 `scripts` 文件夹中创建一个 `font.js` 文件,内容如下: +```javascript +hexo.extend.injector.register('head_end', +'', +'default'); +``` +然后修改你的主题配置文件 +```yaml +font: + font_size: 17px + font_family: "LXGW WenKai GB" + letter_spacing: 0.02em + code_font_size: 85% +``` + +### 2.3 Fluid 主题 +如果你使用 Hexo 的 Fluid 主题,那么恭喜你,替换字体很简单,只需要在主题的配置文件里加上一行 `custom_css: https://xxxx`代码就可以了,再修改 font_family。比如我的是 `fontFamily: LXGW WenKai GB`。 + +```yaml +# 主题字体配置 +font: + font_size: 17px + font_family: "LXGW WenKai GB" + letter_spacing: 0.02em + code_font_size: 85% + +custom_js: +custom_css: https://cdn.jsdelivr.net/npm/lxgw-wenkai-screen-web/lxgwwenkaiscreen/result.css +``` +## 3. 效果展示 +![效果](https://pic4.zhimg.com/80/v2-7a56f955ee9907745c1445b4efed89fb_1440w.webp) diff --git a/source/_posts/Using-mariadb-on-ArchLinux.md b/source/_posts/Using-mariadb-on-ArchLinux.md new file mode 100644 index 00000000..e2af3773 --- /dev/null +++ b/source/_posts/Using-mariadb-on-ArchLinux.md @@ -0,0 +1,251 @@ +--- +title: 在 Archlinux 上安装使用 MariaDB +tags: + - MariaDB + - 数据库 + - btrfs +abbrlink: 53c8336d +date: 2024-03-23 03:06:02 +--- + +{% note secondary %} +`MariaDB` 是一个可靠的、高性能的、功能全面的数据库,旨在为用户提供长期免费、向下兼容能直接替代 `MySQL` 的数据库服务。 +自 2013 年起,`MariaDB` 就被 Arch Linux 当作官方默认的 `MySQL` 实现。 +`MySQL` 也在 `Debian 9` 中被 `MariaDB` 取代。 +由此可见 `MariaDB` 体现了开源社区对 `MySQL` 的担忧,并且 `MariaDB` 几乎完全兼容 `MySQL`,所以使用上几乎没有区别,可以放心地使用。 +{% endnote %} + + +## 0. `btrfs` 文件系统禁用 `COW` + +如果你的系统分区为 `ext4`,可以跳过这一小节。 + + +{% fold info @在 btrfs 上禁用 COW %} +Btrfs(B-tree 文件系统),一种支持写入时复制(COW)的文件系统。 +`COW` 简单说就是 写入 `不会就地覆盖数据`;相反,数据块在被复制和修改后会 `写入到新的位置`,元数据也会更新以指向新的位置。 + +如果你的 `MariaDB` 数据库运行在 `btrfs` 系统分区之上,你应当在创建数据库之前禁用 `Copy-on-Write` 特性[^1],否则可能会导致性能问题。 +不应创建数据库之后再禁用,因为这一更改只会影响新创建的文件,而不会影响现有文件。 + +--- + +我们创建一个空目录 `/var/lib/mysql`: +```bash +sudo mkdir /var/lib/mysql +``` +这个目录就是 `MariaDB` 数据库的数据目录。 + +展示目录属性: +```bash +sudo lsattr -d /var/lib/mysql +``` +输出如下: +```bash +---------------------- /var/lib/mysql +``` +表示 **目录没有设置任何属性** + +--- + +现在设置禁用目录 `Copy-on-Write` 特性: +```bash +sudo chattr +C /var/lib/mysql/ +``` +
+ +展示目录属性: +```bash +sudo lsattr -d /var/lib/mysql +``` +输出如下: +```bash +---------------C------ /var/lib/mysql +``` +`C` 表示 `关闭 Copy-on-Write` 特性。[^2] +至此,我们已经在 `/var/lib/mysql` 目录下禁用了 `Copy-on-Write` 特性。 + +{% endfold %} + + +## 1. 安装 MariaDB + +```bash +sudo pacman -S mariadb +``` + +## 2. 初始化数据库 + +根据安装提示,我们在使用前还需初始化数据库: +```bash +sudo mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql +``` + +`--user=mysql` 表示使用 `mysql` 用户来初始化数据库,`--basedir=/usr` 表示 `MariaDB` 的安装目录,`--datadir=/var/lib/mysql` 表示数据库的数据目录。 + +我们可以在输出中看到: +```bash +Two all-privilege accounts were created. +One is root@localhost, it has no password, but you need to +be system 'root' user to connect. Use, for example, sudo mysql +The second is mysql@localhost, it has no password either, but +you need to be the system 'mysql' user to connect. +After connecting you can set the password, if you would need to be +able to connect as any of these users with a password and without sudo +``` + +翻译: +> 创建了两个全权限账户。 + 一个是 `root@localhost`,它没有密码,但需要系统 "root" 用户才能连接。例如,使用 sudo mysql。 + 第二个是 `mysql@localhost`,它也没有密码,但你必须是系统 "mysql" 用户才能连接。 +连接后,如果您需要能够 以任何这些用户身份使用密码 且无需 sudo 进行连接,则可以设置密码。 + + +## 3. 启动 MariaDB 服务 +输入以下命令来启动 `MariaDB` 服务: +```bash +sudo systemctl start mariadb +``` +确认服务是否启动成功 +```bash +sudo systemctl status mariadb +``` +如果输出中显示 `Active: active (running)` 就表示服务启动成功了。 + + +## 4. 配置 MariaDB + +根据 Archwiki 的建议: +> The `mariadb-secure-installation` command will interactively guide you through a number of recommended security measures, such as removing anonymous accounts and removing the test database: + + +所以我们可以运行 `mariadb-secure-installation` 来进行安全配置: +```bash +sudo mariadb-secure-installation +``` + +```bash +In order to log into MariaDB to secure it, we'll need the current +password for the root user. If you've just installed MariaDB, and +haven't set the root password yet, you should just press enter here. + +Enter current password for root (enter for none): +``` +这里我们直接回车,因为我们还没有设置密码。 +
+ +```bash +Setting the root password or using the unix_socket ensures that nobody +can log into the MariaDB root user without the proper authorisation. + +You already have your root account protected, so you can safely answer 'n'. + +Switch to unix_socket authentication [Y/n] +``` +这里我们选择 `n`,因为它说 `You already have your root account protected, so you can safely answer 'n'`,我们已经保护了 root 账户,所以可以安全地选择 `n`。 +
+ +```bash +You already have your root account protected, so you can safely answer 'n'. + +Change the root password? [Y/n] +``` +`Change the root password? [Y/n]` 这一步询问你是否要更改 MariaDB 的 root 用户的密码。如果你想更改密码,就输入 "Y",然后按回车键,系统会提示你输入新的密码。如果你不想更改密码,就输入 "n",然后按回车键,系统会跳过更改密码的步骤。 + +**我建议你设置密码**,因为后面会使用到 `mariadb -u root -p` 来登录数据库,如果不设置会报错,只能用 `sudo mariadb` 来登录。 +
+ +```bash +By default, a MariaDB installation has an anonymous user, allowing anyone +to log into MariaDB without having to have a user account created for +them. This is intended only for testing, and to make the installation +go a bit smoother. You should remove them before moving into a +production environment. + +Remove anonymous users? [Y/n] +``` +这里我们选择 `Y`,因为这是一个安全措施,我们应该删除匿名用户。 +
+ +```bash +Normally, root should only be allowed to connect from 'localhost'. This +ensures that someone cannot guess at the root password from the network. + +Disallow root login remotely? [Y/n] +``` +选择 `Y`,因为我们不希望 root 用户远程登录。可以配置反向代理或者 SSH 隧道来访问数据库。 +
+ +```bash +By default, MariaDB comes with a database named 'test' that anyone can +access. This is also intended only for testing, and should be removed +before moving into a production environment. + +Remove test database and access to it? [Y/n] +``` +这里我选择 `Y`,不需要 `test` 数据库。 +
+ +```bash + - Dropping test database... + ... Success! + - Removing privileges on test database... + ... Success! + +Reloading the privilege tables will ensure that all changes made so far +will take effect immediately. + +Reload privilege tables now? [Y/n] +``` +这里我们选择 `Y`,重新加载权限表。 +
+ +```bash +All done! If you've completed all of the above steps, your MariaDB +installation should now be secure. + +Thanks for using MariaDB! +``` + +至此,我们已经完成了 MariaDB 的安全配置。 + + +## 5. 使用 MariaDB + +### 5.1 登录 MariaDB +```bash +sudo mariadb +``` + +或者 +```bash +sudo mariadb -u root -p +``` + +如果这里报错:`ERROR 1698 (28000): Access denied for user 'root'@'localhost'`,那么你需要使用 `sudo mariadb` 来登录,或者重新运行 `sudo mariadb-secure-installation` 来设置密码。 + +### 5.2 查看数据库 +```sql +SHOW DATABASES; +``` + +命令行会输出: +```bash +MariaDB [(none)]> show databases; ++--------------------+ +| Database | ++--------------------+ +| information_schema | +| mysql | +| performance_schema | +| sys | ++--------------------+ +4 rows in set (0.001 sec) +``` + +现在,你可以开始使用 `MariaDB` 了。 + + +参考文章: +[^1]: https://wiki.archlinux.org/title/MariaDB +[^2]: https://man.archlinux.org/man/chattr.1 diff --git a/source/_posts/Using-postgresql-on-ArchLinux.md b/source/_posts/Using-postgresql-on-ArchLinux.md new file mode 100644 index 00000000..eaee4a23 --- /dev/null +++ b/source/_posts/Using-postgresql-on-ArchLinux.md @@ -0,0 +1,149 @@ +--- +title: 在 ArchLinux 上安装使用 PostgreSQL +tags: + - PostgreSQL + - 数据库 + - btrfs +abbrlink: d2adab3b +date: 2024-02-29 09:44:23 +--- + +{% note secondary %} +我之前一直使用 `MySQL`,最近才接触 `PostgreSQL`。如果你也是 `PostgreSQL` 的新手,想必也会和我一样在安装使用的时候遇到一些问题(如安装完没有初始化数据库 想启动服务却启动失败等),所以我在这里记录一下我遇到的问题和解决方法。 + +本文主要介绍如何在 ArchLinux 上安装和使用 `PostgreSQL`。 +{% endnote %} + + +## 0. `btrfs` 文件系统禁用 `COW` + +如果你的系统分区为 `ext4`,可以跳过这一小节。 + + +{% fold info @在 btrfs 上禁用 COW %} +Btrfs(B-tree 文件系统),一种支持写入时复制(COW)的文件系统。 +`COW` 简单说就是 写入 `不会就地覆盖数据`;相反,数据块在被复制和修改后会 `写入到新的位置`,元数据也会更新以指向新的位置。 + +如果你的 `PostgreSQL` 数据库运行在 `btrfs` 系统分区之上,你应当在创建数据库之前禁用 `Copy-on-Write` 特性[^1],否则可能会导致性能问题。 +不应创建数据库之后再禁用,因为这一更改只会影响新创建的文件,而不会影响现有文件。 + +--- + +我们创建一个空目录 `/var/lib/postgres/data`: +```bash +sudo mkdir /var/lib/postgres/data +``` +这个目录就是 `PostgreSQL` 数据库的数据目录。 + +展示目录属性: +```bash +sudo lsattr -d /var/lib/postgres/data +``` +输出如下: +```bash +---------------------- /var/lib/postgres/data +``` +表示 **目录没有设置任何属性** + +--- + +现在设置禁用目录 `Copy-on-Write` 特性: +```bash +sudo chattr +C /var/lib/postgres/data/ +``` +
+ +展示目录属性: +```bash +sudo lsattr -d /var/lib/postgres/data +``` +输出如下: +```bash +---------------C------ /var/lib/postgres/data +``` +`C` 表示 `关闭 Copy-on-Write` 特性。 +至此,我们已经在 `/var/lib/postgres/data` 目录下禁用了 `Copy-on-Write` 特性。 + +{% endfold %} + + +## 1. 安装 `PostgreSQL` +```bash +sudo pacman -S postgresql +``` +检查 `Postgresql` 版本 +```bash +psql -V +``` + + +## 2. 初始化数据库 +`PostgreSQL` 与 `MySQL` 不同,它需要初始化数据库。 +
+输入以下命令,来进入 `postgres` 用户的 shell `[postgres]$` 中 +```bash +sudo -iu postgres +``` +执行下面的命令来初始化数据库 +```bash +initdb -D /var/lib/postgres/data +``` +如果没有报错,可以退出 `postgres` shell。 +```bash +exit +``` + + +## 3. 启动 PostgreSQL 服务 +输入以下命令来启动 `PostgreSQL` 服务 +```bash +sudo systemctl start postgresql +``` +确认服务是否启动成功 +```bash +sudo systemctl status postgresql +``` +如果输出中显示 `Active: active (running)` 就表示服务启动成功了。 + + +## 4. 创建用户和数据库 +PostgreSQL 还需要添加一个新的数据库用户。进入 `postgres` shell +```bash +sudo -iu postgres +``` +输入以下命令 +```bash +createuser --interactive +``` +输入要增加的角色名称,新的角色是否是超级用户。 + +提示:如果创建一个与 Linux 用户名相同的 PostgreSQL 角色/用户,就可以访问 PostgreSQL 数据库 shell,而无需指定用户登录(非常方便)。 + +## 5. 创建数据库 +使用 createdb 命令,创建一个上述用户可以读写的新数据库。 +```bash +createdb myDatabaseName +``` + +## 6. 登录数据库 +在 `postgres` shell 中,输入以下命令来登录数据库 +```bash +psql +``` + +`postgres` shell 中,一些常用的命令: + +- `\help`:列出所有命令 +- `\l`:列出所有数据库 +- `\c database`:连接到指定数据库 +- `\du`:列出所有用户 +- `\dt`:列出当前数据库的所有表 +- `\q`:退出数据库 + + +
+ + +参考文章: +[^1]: https://wiki.archlinux.org/title/PostgreSQL +[^2]: https://gist.github.com/NickMcSweeney/3444ce99209ee9bd9393ae6ab48599d8 diff --git a/source/_posts/Using-uptime-kuma-as-Status-Page.md b/source/_posts/Using-uptime-kuma-as-Status-Page.md new file mode 100644 index 00000000..e7c7fb84 --- /dev/null +++ b/source/_posts/Using-uptime-kuma-as-Status-Page.md @@ -0,0 +1,107 @@ +--- +title: Uptime-Kuma 安装使用教程 +tags: + - 部署 + - Uptime-kuma +abbrlink: c7c2ca22 +date: 2024-01-04 11:56:45 +--- +> A fancy self-hosted monitoring tool +> +> 一个精致的自托管监控工具 +## 1. 什么是 uptime-kuma,为什么要使用它? +uptime-kuma 是一个开源的 Status Page,它可以帮助你监控你的网站、服务器、API 等,当你的网站、服务器、API 等出现故障时,它会在网页上显示,同时它还可以作为一个 Status Page,展示你的网站、服务器、API 等的状态。 +支持多种监测方式如 HTTP(S), TCP Port, Ping, DNS, Docker 等等 + +在线体验:[https://demo.uptime.kuma.pet](https://demo.uptime.kuma.pet/) + +官网安装教程:[louislam/uptime-kuma](https://github.com/louislam/uptime-kuma/wiki/%F0%9F%94%A7-How-to-Install) + +## 2. 安装 uptime-kuma + +{% fold info @1Panel 一键安装 %} +打开 `1Panel` 面板,点击 `应用商店`,搜索 `uptime kuma`,点击 `安装` 即可。 + +{% post_link 1panel-installation-and-usage-tutorial '1Panel 安装配置教程' %} +{% endfold %} + +{% fold info @docker-compose 安装 %} +在安装之前,先确保你的服务器已经安装了 `docker` 和 `docker-compose` + +在准备好的安装目录下,新建一个 `docker-compose.yml` +内容如下: +```yml +services: + uptime-kuma: + image: louislam/uptime-kuma:1 + volumes: + - ./data:/app/data + ports: + # : + - 3001:3001 + restart: unless-stopped +``` +编辑好以后在 `docker-compose.yml` 所在目录下执行 `docker-compose up -d` 启动服务。 +{% endfold %} + +现在访问 `http://:3001` 即可看到 uptime-kuma 的首页。 + +配置反向代理(过程略),二级域名 status 映射 3001 端口,即 `status.example.com`,用域名而不是 ip 访问。 + + +## 3. 配置 uptime-kuma +访问 `status.example.com`,进入配置页面。 +![配置页面](https://pic1.zhimg.com/80/v2-d2c29dd21a893eeb98ed6baa480a0268_1440w.webp) +设置账号密码,然后点击 `创建`。 + +## 4. 添加监控项 +我们尝试添加一个监控项,监控 `Github`. +![添加监控项](https://pic2.zhimg.com/80/v2-1528df98aa77c6dc52dd950b27d4ca3d_1440w.webp) +填写相关信息 如 `监控类型` `名称` `URL` `心跳间隔(监控频率)` 等,然后 +点击保存 +(如果你想监控 `chatgpt` 可能要使用 `ping` 的方式,`https` 由于官方限制会 `403`,不知道加什么请求头才行,有懂的朋友可以评论区说一下) + +这个时候我们可以看到,我们的监控项已经添加成功了。显示了 `Github` 的响应状态等信息。但是这个时候我们还不能直接访问,因为我们还没有添加对外展示的 `Status Page`。 +![监控项](https://pic1.zhimg.com/80/v2-2e8308882c77f75a5500b5ca5bc89e30_1440w.webp) + +## 5. 添加 Status Page +点击 `状态页面`,然后点击 `新的状态页`。 + +![添加状态页面](https://pic4.zhimg.com/80/v2-85471f0624ddaa475eb9f53ea1ea6e57_1440w.webp) + +填写 `名称` 和 `路径`,然后点击 `创建`。 + +`路径` 就是你的状态页面的访问路径,比如我填写的是 `show`,那么我的状态页面的访问路径就是 `http://:3001/status/show`。如果你不想这样,而是想直接访问 `status.example.com` 就能得到 `Status Page`。可以先填写一个值 等进去再配置。 +![添加状态页面](https://pic3.zhimg.com/80/v2-259949550d0be9cfa78847eb4c16deca_1440w.webp) + +## 6. 配置 Status Page +点击 `添加分组`,再点击 `添加监控项`(就是前面配置的)。 +![配置状态页面](https://pic3.zhimg.com/80/v2-98926849dc41e2d454655bcfbc2284ba_1440w.webp) + +点击左边的 `域名`,填写你的域名,然后点击 `保存`。这样就可以使用域名 `status.example.com` 访问 而不是 `status.example.com/status/show` 。 +![填写域名](https://pic2.zhimg.com/80/v2-1c4c9719809e32dab8c6be704b622695_1440w.webp) + +换个浏览器访问域名验证一下,我们的状态页面已经添加成功了。显示了 `Github` 的响应状态信息。 +![状态页面](https://pic2.zhimg.com/80/v2-02107bc3749d6bd8ef35bda2f3121d95_1440w.webp) + +## 7. 配置邮件通知 +![监控项](https://pic1.zhimg.com/80/v2-2e8308882c77f75a5500b5ca5bc89e30_1440w.webp) +点击一个监控项的 `编辑`,然后点击 `设置通知`,`通知类型` 选择 `SMTP`,然后填写你的邮箱信息,点击 `保存`。 + +这里我以 `outlook` 为例,参考 [微软 Outlook.com 的 POP、IMAP 和 SMTP 设置 +](https://support.microsoft.com/zh-cn/office/outlook-com-%E7%9A%84-pop-imap-%E5%92%8C-smtp-%E8%AE%BE%E7%BD%AE-d088b986-291d-42b8-9564-9c414e2aa040) + +微软邮箱的参数如下: +**SMTP 主机名**:`smtp-mail.outlook.com` +**SMTP 端口**:`587` +**SMTP 加密**:`STARTTLS` + +**用户密码**就是你的 `outlook` 邮箱和密码。 + +**发信人**写成 `Uptime Kuma <你的邮箱>`,收信人写 `你的邮箱`。 + +**邮件主题**可以自定义,我建议为 `Uptime Kuma - {{NAME}}: is {{STATUS}}` + +填写完毕后点击 `测试`,如果收到邮件,说明配置成功。 + +![测试成功,可以收到邮件](https://pic2.zhimg.com/80/v2-4139c28c2b3f13eaa274ed1c0e1ef445_1440w.webp) diff --git a/source/_posts/Vaultwarden-installation-and-usage-tutorial.md b/source/_posts/Vaultwarden-installation-and-usage-tutorial.md new file mode 100644 index 00000000..b84630f0 --- /dev/null +++ b/source/_posts/Vaultwarden-installation-and-usage-tutorial.md @@ -0,0 +1,135 @@ +--- +title: Bitwarden (Vaultwarden) 部署使用教程 +abbrlink: 2d9cb7bd +date: 2024-04-13 13:11:03 +tags: + - Bitwarden + - Vaultwarden + - 部署 + - 安全 +--- + +![bitwarden](https://pic1.zhimg.com/80/v2-37027f299fa4cff9f29e0cb223d127ec_1440w.webp) + +{% note info %} +相信大家对 Bitwarden 这款密码管理工具并不陌生,它是一款 **`开源`** 的密码管理工具,可以帮助我们管理各种账号密码,支持多种平台,包括 Windows、macOS、Linux、Android、iOS 等。 + +Bitwarden 的官方服务有些功能是收费的(如 2FA),但它开源了服务端的代码,所以我们可以自己搭建一个 Bitwarden 服务。而我们今天要介绍的 **`Vaultwarden`** 就是 Bitwarden 服务器的一个开源实现。Vaultwarden 是用 Rust 编写的 Bitwarden 服务器 API 的替代实现,兼容上游 Bitwarden 客户端,非常适合在运行官方资源繁重的服务并不理想的情况下进行自托管部署[^1]。 +{% endnote %} + +本文将介绍如何在 Linux 服务器上通过 Docker Compose 部署 Vaultwarden 服务。当然你也可以使用 `1Panel` 一键安装部署。 + +## 1. 创建目录 + +输入以下命令创建一个目录,用于存放 Vaultwarden 的数据: +```bash +sudo mkdir /opt/vaultwarden && cd /opt/vaultwarden +``` + +## 2. 创建 Docker Compose 配置文件 + +输入以下命令创建一个 Docker Compose 配置文件: +```bash +sudo vim /opt/vaultwarden/docker-compose.yml +``` +
+ +复制以下内容到文件中: +```yaml +version: '3' + +services: + vaultwarden: + image: vaultwarden/server:latest-alpine + container_name: vaultwarden + restart: always + ports: + - '6666:80' #主机:容器 + volumes: + - ./vw-data:/data + environment: + DOMAIN: "https://example.com" +``` +保存并退出编辑器。 + +## 3. 启动服务 + +输入以下命令启动 Vaultwarden 服务: +```bash +sudo docker-compose up -d +``` + +现在 Vaultwarden 服务已经启动了,地址为 `http://example.com:6666` + +但是**在使用之前,你最好使用反向代理隐藏端口并配置 HTTPS,避免中间人攻击。**配置完毕之后你就可以访问你的 Vaultwarden 网页版服务了。 + +![登陆](https://pic3.zhimg.com/80/v2-64812e3da6683431d0ecf696e102afc2_1440w.webp) + +创建一个账号,然后你就可以在各个平台上使用 Bitwarden 客户端了。电脑上推荐使用浏览器插件,手机上推荐使用官方客户端。注意在登陆的时候要选择 `自托管`,输入你的 `服务器 URL` 即可。 + +![登陆选择](https://pic4.zhimg.com/80/v2-196b3cc79509562d5cec5426076a14b3_1440w.webp) + + +## 4. Docker Compose 配置详解 + +### 4.1 image + +`vaultwarden/server:latest` 是 Vaultwarden 服务器的 Docker 镜像,latest 是最新版本。 + +而本文使用的是 `vaultwarden/server:latest-alpine`,是基于 Alpine Linux 的最新版本。该镜像功能上与 latest 相同,但镜像基于 Alpine 而非 Debian,镜像更小,基础应用程序更新。 + +当然你也可以指定一个特定的版本,如 `vaultwarden/server:1.22.0` 或 `vaultwarden/server:1.22.0-alpine`。 + +### 4.2 ports + +`6666:80` 表示将容器的 80 端口映射到主机的 6666 端口。可以根据自己的需求修改。 + +### 4.3 volumes + +`./vw-data:/data` 表示将主机的 `./vw-data` 目录挂载到容器的 `/data` 目录。但是不建议更改,与官方文档保持一致。 + +### 4.4 environment + +Vaultwarden 推荐使用环境变量来配置服务 + +- `DOMAIN`:你的域名。 + +下面是一些其他的环境变量[^2],你可以根据自己的需求添加: + +- `SIGNUPS_ALLOWED`:是否允许注册新用户,默认为 `true`。你可以在自己注册完毕后,将其设置为 `false` 来关闭注册功能。但即使禁用了,管理员还是可以继续邀请新用户。 +- `ADMIN_TOKEN`:开启管理员功能,需要设置一个 token,推荐使用命令 `openssl rand -base64 48` 生成一个随机 token。设置以后,访问 `https://example.com/admin`,输入 token 即可进入管理员界面。管理员可以查看并删除所有已注册的用户。它也允许邀请新用户,即使禁用了注册功能。 +- `INVITATIONS_ALLOWED`:是否允许管理员邀请新用户,默认为 `true`。关闭后,管理员将无法邀请新用户。 +- `WEB_VAULT_ENABLED`:是否启用 Web 界面,默认为 `true`。关闭后,用户将无法使用 Web 界面,但仍然可以使用客户端。注册之后也可以禁用 Web 界面。 + + +建议前端注册用户成功后,进行如下配置,禁止注册和 Web 界面: +```yml +environment: + SIGNUPS_ALLOWED: "false" + WEB_VAULT_ENABLED: "false" +``` + +## 5. 维护 Vaultwarden + +### 5.1 更新 + +```bash +sudo docker-compose pull +sudo docker-compose up -d +``` + +### 5.2 停止并移除容器 + +```bash +sudo docker-compose down +``` + +### 5.3 数据备份 + +Vaultwarden 的数据存储在 `./vw-data` 目录中,你可以直接备份这个目录。 + + +--- + +[^1]: https://github.com/dani-garcia/vaultwarden +[^2]: https://github.com/dani-garcia/vaultwarden/wiki diff --git a/source/_posts/Writing-Umami-s-uv-pv-access-display.md b/source/_posts/Writing-Umami-s-uv-pv-access-display.md new file mode 100644 index 00000000..03ebc15f --- /dev/null +++ b/source/_posts/Writing-Umami-s-uv-pv-access-display.md @@ -0,0 +1,199 @@ +--- +title: Umami UV / PV 统计显示 +tags: + - Umami +abbrlink: 4259ee82 +date: 2024-02-25 19:47:17 +--- + +I'll demonstrate how to implement Umami's UV, PV visit statistics display. +这篇文章我将演示如何实现 Umami 的 UV, PV 访问统计显示。 + +
+ +这是本站的 Umami 访问统计页面,显示了每日的访问量和访问人数,链接:https://umami.ovvv.top/share/SYu8qUKmty52PW9w/blog + +![浏览量展示](https://pic4.zhimg.com/80/v2-a96d771513470a3a394727e04bb3afcb_1440w.webp) + +我们在前文介绍过如何安装 Umami:{% post_link 'Umami-installation-and-usage-tutorial' 'Umami 安装使用教程' %}。本文 **默认你已经安装了 Umami 并且添加了一个网站**。下面我们将编写一个简单的页面,通过 Umami 的 API 调用显示 Umami 的 UV, PV 访问情况。 + +本文会使用类似于 `postman` 的 API 测试工具来发送 `GET`, `POST` 请求。你也可以使用 `hoppscotch`、`curl` 等工具。 + +## 1. 新建 `View only` 权限的用户 + +`Settings` -> `Users` -> `Create user` -> 填写账号密码,`Role` 选择 `View only` -> `Save` + +![新建用户](https://pic1.zhimg.com/80/v2-3947dd0fa291aa3db02b5bb251ea2d30_1440w.webp) + + +{% fold info @一点碎碎念 %} +肯定有读者很疑惑,为什么不直接调用 Umami 的 API 获取数据,而是要额外创建一个账户。 + +因为我的博客是 **静态开源无服务器** 的,所有代码都展示在前端,包括 API 调用。而 Umami 的 `admin` API 权限太大了[^1],如果使用 `admin` 权限的 API Token,那么这个 token 可以获取、修改、删除所有网站的数据,会有严重的安全隐患。 + +所以我们需要创建一个 `View only` 权限的用户,使用这个 `低权限的用户`的 API Token 来访问我们的浏览量等数据。 +{% endfold %} + +## 2. 新建 `Team` 并添加用户和网站 + +`Settings` -> `Teams` -> `Create team` -> 填写名称 -> `Save` -> 找到刚刚创建的 `Team` -> `Edit` -> 复制 `Access code`,点击 `Websites`,点击 `Add website` 添加你想共享的网站 + +换一个浏览器登录 Umami(使用`View only` 权限的用户) -> `Settings` -> `Teams` -> `Join team` -> 输入 `Access code` -> `Join` -> 如果没有出错的话,点击 `Dashboard` 就可以看到你刚刚添加的网站了 + +## 3. 获取 `View only` 用户的 API Token +根据 Umami 的文档[^2],我们可以通过以下方式获取 API Token: + +``` +POST /api/auth/login +``` +例如 你的网站地址为 `example.com`,那么你需要使用 `View only` 的账户密码向 `https://example.com/api/auth/login` 发送一个 `POST` 请求,请求体为: + +```json +{ + "username": "your-username", + "password": "your-password" +} +``` + +如果成功,你应该会得到以下的结果: +```json +{ + "token": "eyTMjU2IiwiY...4Q0JDLUhWxnIjoiUE_A", + "user": { + "id": "cd33a605-d785-42a1-9365-d6cad3b7befd", + "username": "your-username", + "createdAt": "2020-04-20 01:00:00" + } +} +``` + +保存 token 值,并在所有请求中发送带 `Bearer ` 值的 `Authorization` 标头。请求标头应该如下所示: + +``` +Authorization: Bearer eyTMjU2IiwiY...4Q0JDLUhWxnIjoiUE_A +``` + +## 4. 发送请求获取数据 + +先分析一下官方文档的 API 接口[^3]: +`GET /api/websites/{websiteId}/stats` +![API](https://pic2.zhimg.com/80/v2-3c570a96d2d263c81415fea5a97a94fd_1440w.webp) + +有两个必填的 查询参数:`startAt` 和 `endAt`,都是 Unix 毫秒时间戳,表示开始时间和结束时间 + +`websiteId` 和 `startAt` 需要我们自己获取 + +`websiteId` 可以在 `Dashboard` -> 点击你网站的 `View details` -> 浏览器栏的地址 `https://example.com/websites/{websiteId}` 中找到 {websiteId} + +`startAt` 可发送 `GET` 请求到 `https://example.com/api/websites/{websiteId}`,带上上文获取的请求头 + +``` +Authorization: Bearer eyTMjU2IiwiY...4Q0JDLUhWxnIjoiUE_A +``` + +在返回结果中找到 `createdAt` 字段,这个字段就是 `startAt` 的值,也就是你的网站创建时间,数据的开始时间 +![createdAt](https://pic3.zhimg.com/80/v2-0f39fd39907c3d7bd911395ba890d82e_1440w.webp) + + +## 5. 编写页面 + +![页面展示](https://pic1.zhimg.com/80/v2-c07238914da7b6773ee1d26f03ace7f0_1440w.webp) + +代码是看到木木的博客[^4]而有灵感,而评论区下面的 Nick[^5] 提供了相对正确的思路,我在他代码的基础上进行了改进,如删除无用的参数和优化步骤等。代码如下,修改你对应的参数即可运行: + +{% fold info @html 代码 %} +```html + + + + + + + Document + + + +
+

Umami 网站统计

+ 总访问量 + + 总访客数 +
+ + + + + +``` +{% endfold %} + +## 参考 +[^1]: https://umami.is/docs/websites-api +[^2]: https://umami.is/docs/authentication +[^3]: https://umami.is/docs/website-stats +[^4]: https://immmmm.com/hi-umami-api/ +[^5]: https://github.com/nick-cjyx9/ilesBlog/blob/main/src/composables/useUmami.ts \ No newline at end of file diff --git a/source/_posts/hello-world.md b/source/_posts/hello-world.md new file mode 100644 index 00000000..13e83cab --- /dev/null +++ b/source/_posts/hello-world.md @@ -0,0 +1,6 @@ +--- +title: Hello World +abbrlink: 4a17b156 +date: 2023-12-26 22:19:15 +--- +欢迎来到 [mobeicanyue's Blog](https://blog.ovvv.top/)! 这是我的第一篇博客。 diff --git a/source/_posts/note.md b/source/_posts/note.md new file mode 100644 index 00000000..76ba3f11 --- /dev/null +++ b/source/_posts/note.md @@ -0,0 +1,9 @@ +--- +title: 漠北残月的笔记 +abbrlink: fcd36967 +date: 2024-03-29 22:03:03 +tags: + - 笔记 +--- + +这篇文章主要通过 Discussion 记录一些琐碎的笔记,如:博客搭建过程、技术问题解决过程、生活琐事等。因为这些内容可能并不适合放在博客正文中,所以单独开辟一个 Discussion 专栏。 diff --git a/source/about/index.md b/source/about/index.md new file mode 100644 index 00000000..ffd2440b --- /dev/null +++ b/source/about/index.md @@ -0,0 +1,30 @@ +--- +title: 关于漠北残月 +date: 2023-12-26 22:43:21 +layout: about +--- + +# 你好 👋 +### 欢迎来到漠北残月的博客 + +本站建于 2023 年 12 月 26 日,是一个个人博客,主要记录一些技术、生活、学习、等方面的内容。博主个人简介见 [mobeicanyue](https://www.ovvv.top). + +本博客使用了开源静态博客框架 [Hexo](https://hexo.io/zh-cn) 及主题 [Fluid](https://hexo.fluid-dev.com/docs),开源统计工具 [Umami](https://umami.is),遵守您的 DNT 设定,网站访问情况可通过 https://umami.ovvv.top/share/SYu8qUKmty52PW9w/blog 查看。 + +本站文章知识共享许可协议为 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh-hans)。**您可以在遵守协议的前提下自由转载、分享、修改,但需注明作者和出处、不得用于商业目的、基于本协议进行再分享。** + +之前还在 CSDN 写过博客,有不少阅读量。但是奈何 CSDN 广告太多,使用体验也不太好,所以就搭建了这个博客。现在的博客主要用来写一些长篇的技术文章,以及一些生活感悟。CSDN 就更新一些简单、零碎的文章。 + +源代码托管于 [Github](https://github.com/mobeicanyue) 并自动构建,通过 Cloudflare Pages 和 Cloudflare CDN 部署在 Cloudflare 的全球边缘网络上。大力感谢 [Cloudflare](https://www.cloudflare.com) 的优质服务支持。 + +
+ +![Cloudflare](https://pic2.zhimg.com/80/v2-5dc3a549cd89aec337d268b17940e101_1440w.webp) + +
+ +由于奇奇怪怪的玄学原因,百度并没有收录本站,除了百度的主流搜索引擎都可以搜索到本站,如 Google、Bing(必应)、DuckDuckGo、Yandex、Yahoo(雅虎)等。 + +

+ +

Supports IPv6, Brotli, HTTP 2 / HTTP 3, TLS 1.3, HSTS Preload, DNSSEC, Security headers via Cloudflare.

diff --git a/source/images/avatar.webp b/source/images/avatar.webp new file mode 100644 index 00000000..b76707eb Binary files /dev/null and b/source/images/avatar.webp differ diff --git a/source/images/favicon.jpg b/source/images/favicon.jpg new file mode 100644 index 00000000..b023044e Binary files /dev/null and b/source/images/favicon.jpg differ diff --git a/source/images/rss.svg b/source/images/rss.svg new file mode 100644 index 00000000..25bf09c9 --- /dev/null +++ b/source/images/rss.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/source/js/duration.js b/source/js/duration.js new file mode 100644 index 00000000..71aabe70 --- /dev/null +++ b/source/js/duration.js @@ -0,0 +1,18 @@ +const now = new Date(); // 获取当前时间 +const init = new Date("2023-12-26T22:19:15"); // 设置初始化时间 + +const currentYear = now.getFullYear(); // 获取当前年份 + +// 计算运行时间 +const days = Math.floor((now - init) / 1000 / 60 / 60 / 24); // 计算天数 +const years = Math.floor(days / 365); // 计算年数 +const remainingDays = days % 365; // 计算剩余天数 +const hours = Math.floor((now - init) / 1000 / 60 / 60 - 24 * days); + +function createTime() { + document.getElementById("copyrightYear").textContent = ` - ${currentYear}`; + document.getElementById("timeYear").textContent = `本站已运行 ${years} 年`; + document.getElementById("timeDate").textContent = ` ${remainingDays} 天`; + document.getElementById("times").textContent = ` ${hours < 10 ? "0" : ""}${hours} 小时`; +} +createTime(); diff --git a/source/js/random.js b/source/js/random.js new file mode 100644 index 00000000..a787508f --- /dev/null +++ b/source/js/random.js @@ -0,0 +1,40 @@ +let randomNavItem = document.querySelector(".nav-item:nth-child(5) a"); +randomNavItem.addEventListener("click", randomRedirect); // 给 item 设置 js 函数,点击时触发随机跳转 + +function randomRedirect() { + // 发起网络请求获取 sitemap.txt 文件内容 + fetch("/sitemap.txt") + .then((response) => { + if (!response.ok) { + throw new Error( + "Network response was not ok. Status: " + response.status + ); + } + return response.text(); + }) + .then((data) => { + let links = data.trim().split("\n"); // 将获取的内容按行分割成数组 + + // 验证链接数组不为空 + if (links.length === 0) { + throw new Error("No links found in the sitemap."); + } + + // 随机选择一个链接 + let randomIndex = Math.floor(Math.random() * links.length); + let randomLink = links[randomIndex].trim(); + + // 验证随机选择的链接不为空 + if (!randomLink) { + throw new Error("Invalid random link: " + randomLink); + } + + window.location.assign(randomLink); + }) + .catch((error) => { + console.error( + "There was a problem with the fetch operation:", + error + ); + }); +} diff --git a/source/robots.txt b/source/robots.txt new file mode 100644 index 00000000..b5bfd0a4 --- /dev/null +++ b/source/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Disallow: + +Sitemap: https://blog.ovvv.top/sitemap.xml \ No newline at end of file diff --git a/themes/.gitkeep b/themes/.gitkeep new file mode 100644 index 00000000..e69de29b