1 lang

1.1 path

01.Java
    a.安装
        mv jdk-8u191-linux-x64.tar.gz /usr/local
        cd /usr/local
        tar -zxvf jdk-8u191-linux-x64.tar.gz
        rm -r jdk-8u191-linux-x64.tar.gz
        mv jdk1.8.0_191 jdk-1.8.0_191
    b.环境变量
        gedit /root/.bashrc
        export JAVA_HOME=/usr/local/jdk-1.8.0_191
        export CLASSPATH=$JAVA_HOME/lib:$CLASSPATH
        export PATH=$JAVA_HOME/bin:$PATH
        source /root/.bashrc
    c.测试
        java -version

02.Maven
    a.安装
        mv apache-maven-3.6.3-bin.tar.gz /usr/local
        cd /usr/local
        tar -zxvf apache-maven-3.6.3-bin.tar.gz
        rm -r apache-maven-3.6.3-bin.tar.gz
    b.环境变量
        gedit /root/.bashrc
        export MAVEN_HOME=/usr/local/apache-maven-3.6.3
        export PATH=$MAVEN_HOME/bin:$PATH
        source /root/.bashrc
    c.测试
        mvn -V

03.Tomcat
    a.安装
        mv apache-tomcat-9.0.78.tar.gz /usr/local
        cd /usr/local
        tar -zxvf apache-tomcat-9.0.78.tar.gz
        rm -r apache-tomcat-9.0.78.tar.gz
    b.环境变量
        gedit /root/.bashrc
        export MAVEN_HOME=/usr/local/apache-tomcat-9.0.78
        export PATH=$MAVEN_HOME/bin:$PATH
        source /root/.bashrc
    c.测试
        startup.sh

04.Nodejs-14.21.1,【不支持】npm安装pnpm
    a.安装
        mv node-v14.21.1-linux-x64 /usr/local
        cd /usr/local
        tar -zxvf node-v14.21.1-linux-x64
        rm -r node-v14.21.1-linux-x64
        mv node-v14.21.1 node-14.21.1
    b.环境变量
        gedit /root/.bashrc
        export NODE_HOME=/usr/local/node-14.21.1
        export PATH=$NODE_HOME:$NODE_HOME/bin:$NODE_HOME/node-global:$PATH
        source /root/.bashrc
    c.配置
        npm config set prefix "/usr/local/node-14.21.1/node-global"
        npm config set cache "/usr/local/node-14.21.1/node-cache"
        npm config ls
    d.测试
        npm -v
        node -v

05.Nodejs-16.20.1,【不支持】npm安装pnpm
    a.安装
        mv node-v16.20.1-linux-x64.tar /usr/local
        cd /usr/local
        tar -zxvf node-v16.20.1-linux-x64.tar
        rm -r node-v16.20.1-linux-x64.tar
        mv node-v16.20.1 node-16.20.1
    b.环境变量
        gedit /root/.bashrc
        export NODE_HOME=/usr/local/node-16.20.1
        export PATH=$NODE_HOME:$NODE_HOME/bin:$NODE_HOME/node-global:$PATH
        source /root/.bashrc
    c.配置
        npm config set prefix "/usr/local/node-16.20.1/node-global"
        npm config set cache "/usr/local/node-16.20.1/node-cache"
        npm config ls
    d.测试
        npm -v
        node -v

06.Nodejs-20.18.0,【支持】npm安装pnpm
    a.安装
        mv node-v20.18.0-linux-x64.tar.gz /usr/local
        cd /usr/local
        tar -zxvf node-v20.18.0-linux-x64.tar.gz
        rm -r node-v20.18.0-linux-x64.tar.gz
        mv node-v20.18.0 node-20.18.0
    b.环境变量
        gedit /root/.bashrc
        export NODE_HOME=/usr/local/node-20.18.0
        export PATH=$NODE_HOME:$NODE_HOME/bin:$NODE_HOME/node-global/bin:$PATH
        source /root/.bashrc
    c.配置
        npm config set prefix "/usr/local/node-20.18.0/node-global"
        npm config set cache "/usr/local/node-20.18.0/node-cache"
        npm config ls
    d.测试
        npm -v
        node -v
    e.安装
        npm install -g pnpm
        pnpm set registry http://172.17.8.54/
        pnpm set registry https://registry.npmmirror.com
        pnpm adduser --registry http://172.17.8.54/
        pnpm profile set password --registry http://172.17.8.54/
        -----------------------------------------------------------------------------------------------------
        pnpm login
        j057240
        qwER159263
        -----------------------------------------------------------------------------------------------------
        pnpm c get
        pnpm i --registry https://registry.npmmirror.com

07.Navicat
    a.权限
        mkdir /usr/local/navicat
        cd /Ubuntu/software/SQL/Navicat/
        mv navicat15-premium-cs.AppImage /usr/local/navicat/navicat15-premium-cs.AppImage
        mv navicat.jpg /usr/local/navicat/navicat.jpg
        cd /usr/local/navicat/
        chmod +x navicat15-premium-cs.AppImage
    b.创建Navicat.desktop
        gedit /usr/share/applications/Navicat.desktop
    c.编辑pycharm.desktop
        [Desktop Entry]
        Version=1.0
        Type=Application
        Name=Navicat
        Icon=/usr/local/navicat/navicat.jpg
        Exec=/usr/local/navicat/navicat15-premium-cs.AppImage
        MimeType=application/x-py;
        Name[en_US]=Navicat

1.2 debian

00.Debian13包含了超过14,100个新软件包,总数达到近70,000个
    a.系统与内核
        Linux Kernel: 6.12 LTS 系列
        Systemd: 257
        GNU C Library: 2.41
    b.编译器与工具链
        GCC: 14.2
        LLVM/Clang: 19 (默认), 17, 18 可选
        Python: 3.13
        Perl: 5.40
        PHP: 8.4
        Rustc: 1.85
        OpenJDK: 21
    c.服务与数据库
        Apache: 2.4.64
        Nginx: 1.26
        MariaDB: 11.8
        PostgreSQL: 17
        Samba: 4.22
        OpenSSH: 10.0p1
        OpenSSL: 3.5
    d.桌面环境与应用
        GNOME: 48
        KDE Plasma: 6.3
        Xfce: 4.20
        LibreOffice: 25.2
        GIMP: 3.0.4
        Inkscape: 1.4

01.开机设置一:介绍
    a.Debian10(Buster)
        引入新的Debian 10的主题 “FuturePrototype”
        新版本的电脑桌面环境GNOME 3.30、Cinnamon 3.8、KDE Plasma 5.14、MATE 1.20、Xfce 4.12
        长期支持版内核4.19.0-4
        新的Python 3 (3.7.2)、Perl 5.28、PHP 7.3
        iptables替换为 nftables
        更新LibreOffice 6.1、GIMP 2.10.8
        更新OpenJDK 11、MariaDB 10.3 和 Apache 2.4.38
        更新Chromium 73.0、Firefox 60.7
    b.默认账号
        User(osboxes、osboxes.org)(myslayers、4023615)
        Root(root、osboxes.org)(root、4023615)
    c.切换root
        su -
        osboxes.org
    d.用户sudo权限
        sudo vi /etc/sudoers
        osboxes ALL=(ALL:ALL) ALL                                       --打开osboxes全部权限
        myslayers ALL=(ALL:ALL) ALL                                     --打开myslayers全部权限
    e.安装Vmware Tools
        tar -zxvf VMwareTools-10.0.0-2977863.tar.gz
        sudo ./vmware-install.pl -y
    f.Settings
        Privacy -> Off(ScreenLock、LocationServices、Usage&History、PurgeTrash&TemporaryFiles)
        Power -> PowerSaving(Never)、Suspend&PowerButton(Off)
        KeyboardShortcuts -> HomeFolder(Win+E)、Settings(Win+I)、Browser(Win+1)
        KeyboardShortcuts -> add -> 名称(Terminal)、命令(gnome-terminal)、快捷键(Win+R)
        Account -> User(myslayers)、Password(40236155)

02.开机设置二:更新工具
    a.默认vi-tiny
        a.解决默认vi-tiny无法使用“删除键”、“方向键”
            sudo vi /etc/vim/vimrc.tiny
            set nocompatible                                            --将compatible变nocompatible(方向)
            set backspace=2                                             --末行增加set backspace=2(删除键)
        b.将默认vi-tiny替换为vim
            apt-get update && apt-get -y remove vim-common && apt-get -y install vim*
    b.国内镜像源
        a.备份默认镜像源
            sudo cp /etc/apt/sources.list /etc/apt/sources.list_bak
        a.切换tsinghua镜像源
            sudo apt install apt-transport-https ca-certificates
        b.查看tsinghua镜像源
            vi /etc/apt/sources.list
            deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free
            deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-updates main contrib non-free
            deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-backports main contrib non-free
            deb https://mirrors.tuna.tsinghua.edu.cn/debian-security buster/updates main contrib non-free
    c.tasksel命令
        a.tasksel一键搭建LAMP服务器、邮件服务器、DNS服务器
            sudo tasksel install lamp-server
            sudo tasksel install mail-server
            sudo tasksel install dns-server
        b.切换桌面
            sudo tasksel -> KDE Plasma、GNOME、Xfce、Cinnamon、web server、print server、SSH server -> 空格选
            update-alternatives --config x-session-manager              --切换桌面系统
    d.IPv4+DNS
        a.修改网卡配置:dhcp,vi /etc/network/interfaces
            # This file describes the network interfaces available on your system
            # and how to activate them. For more information, see interfaces(5).
            source /etc/network/interfaces.d/*

            # The loopback network interface
            auto lo
            iface lo inet loopback

            # The primary network interface
            allow-hotplug ens33
            iface ens33 inet dhcp
        b.修改网卡配置:vi /etc/network/interfaces,假设网卡名为eth33
            # This file describes the network interfaces available on your system
            # and how to activate them. For more information, see interfaces(5).
            source /etc/network/interfaces.d/*

            # The loopback network interface
            auto lo
            iface lo inet loopback

            # The primary network interface
            auto ens33
            iface ens33 inet static
            address 192.168.2.138
            netmask 255.255.255.0
            gateway 192.168.2.1
            dns-nameservers 192.168.2.1
        c.配置DNS解析
            vi /etc/NetworkManager/NetworkManager.conf                          --在[main]后追加dns=none
            vi /etc/resolv.conf                                                 --设置DNS解析
            nameserver 192.168.2.1
        d.重启网卡
            systemctl restart networking                                        --Ubuntu/Debian:重启网络
            systemctl status networking                                         --Ubuntu/Debian:查看状态
        e.auto与allow-hotplug区别
            auto:不管有无网线,网卡都会启用,运行/etc/init.d/networking restart之后,网卡能自动重启
            allow-hotplug:只会在开机时启动插网线的网卡,运行/etc/init.d/networking restart之后,网卡不能自动重启
            DNS优先级:/etc/hosts文件 > /etc/network/interfaces中DNS > /etc/resolv.conf中DNS
            修改主机名:/etc/hostname -> debian01
    e.映射 vi /etc/hosts 或 C:\Windows\System32\drivers\etc\hosts
        192.168.2.128 bigdata01
        192.168.2.129 bigdata02
        192.168.2.130 bigdata03
        192.168.2.131 bigdata04
        192.168.2.132 bigdata05
        192.168.2.138 debian01
        192.168.2.2 bigdata

03.开机设置三:配置root用户(图形界面)
    a.配置一:root用户密码修改
        sudo passwd root                                                --修改root密码
        su                                                              --切换root用户
        sudo whoami                                                     --查看用户是否具有sudo权限
    b.配置二:root用户登陆图像界面
        vi /etc/gdm3/daemon.conf
        AutomaticLoginEnable = true                                     --以root自动登录
        AutomaticLogin = root                                           --以root自动登录
        [security]
        AllowRoot=true                                                  --允许root登录
    c.配置三:root用户登陆图像界面
        vi /etc/pam.d/gdm-autologin
        auth required pam_success_if.so user!=root quiet_success        --注释该行
    d.配置四:root用户登陆图像界面
        vi /etc/pam.d/gdm-password
        auth required pam_success_if.so user!=root quiet_success        --注释该行
    e.配置五:root用户图形界面登陆错误
        vi /root/.profile
        tty -s && mesg n || true                                        --修改内容

04.开机设置四:配置root用户(SSH界面)
    a.安装openssh-server
        yum list installed | grep openssh-server                        --检测是否安装
        yum install openssh-server                                      --如果未安装,则安装openssh-server
        yum install -y glibc libgcc libstdc++ python ca-certificates tar openssh-server bash curl
    b.配置
        vi /etc/ssh/sshd_config
        Port 22                                                         --监听端口
        ListenAddress 0.0.0.0                                           --监听地址
        ListenAddress ::                                                --监听地址
        PermitRootLogin yes                                             --开启远程访问(SSH,root用户登录)
        --------------------------
        PubkeyAuthentication yes                                        --开启密钥验证(SSH,pubkey登录)
        AuthorizedKeysFile  .ssh/authorized_keys                        --开启密钥验证(SSH,pubkey登录)
        --------------------------
        PasswordAuthentication yes                                      --开启密码验证(SSH,密码验证)
    c.开启服务
        systemctl start sshd                                            --开启服务
        systemctl enable sshd                                           --开机自启
        systemctl restart sshd                                          --重启服务
        ps -e | grep sshd                                               --检查sshd服务是否已经开启
        systemctl list-unit-files | grep sshd                           --检查sshd服务是否开机自启
        yum check-update && yum install code -y                         --远程机器安装VScode
    d.ssh免密钥登录(Remote-SSH只提供使用RSA秘钥远程登录,SSH不支持命令行-p输入明文密码)(默认aes256-cbc类型)
        a.win10生成密钥
            ssh-keygen -t rsa
        b.将Win10中的公钥id_rsa.pub -> 手动放到Centos7中的authorized_keys
            chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
        c.win10远程访问(C:\Windows\System32\OpenSSH)
            ssh [email protected]
            ssh [email protected] -i "C:\Users\mysla\.ssh\id_rsa.ppk" -P 22
            ssh [email protected] -i "C:\Users\mysla\.ssh\id_rsa.ppk" -P 22
        d.putty远程访问(D:\software\Java\putty-0.74)
            connection -> SSH -> Auth -> Browse -> 选中putty密钥(id_rsa.ppk)
            session -> IP(192.168.2.128)、Port(22)、Saved(bigdata01) -> 连接

1.3 ubuntu

00.Ubuntu 24.04 LTS 是一个里程碑式的版本
    a.系统与内核 (System & Kernel)
        Linux Kernel: 6.8,带来了最新的硬件支持,并增强了性能调度与网络功能。
        Systemd: 255,提供了更完善的系统和服务管理能力。
        GNU C Library: 2.39,基础C库更新,提升了兼容性和安全性。
        Netplan: 1.0,网络配置工具迎来重要更新,支持更复杂的网络场景。
    b.编译器与工具链 (Compilers & Toolchain)
       GCC: 14 (可选, 默认 13.2),提供了对最新C++标准的支持和更强的编译优化能力。
       LLVM/Clang: 18
       Python: 3.12,默认版本,带来了性能改进和新的语言特性。
       Perl: 5.38
       PHP: 8.3
       Rustc: 1.75
       Go: 1.22
       OpenJDK: 21 (默认), 17, 11 可选,全面支持最新的Java LTS版本。
    c.服务与数据库 (Services & Databases)
       Apache: 2.4.58
       Nginx: 1.24
       MariaDB: 10.11
       PostgreSQL: 16
       Samba: 4.19
       OpenSSH: 9.6p1,增强了安全性,默认禁用较弱的RSA/SHA1签名。
       OpenSSL: 3.2
    d.桌面环境与核心应用 (Desktop Environment & Core Applications)
       GNOME: 46,带来了全局搜索的重大改进、更高效的文件管理、可变刷新率(VRR)的实验性支持以及优化的设置面板。
       KDE Plasma: 5.27.11 (Kubuntu),Kubuntu 24.04 LTS 仍然使用 Plasma 5.27,以保证稳定性。
       Installer: Subiquity,采用了全新的基于Flutter构建的桌面安装程序,支持如ZFS、自动安装等高级功能,界面更现代化。
       App Center: 新的应用中心,替代了原有的 "Ubuntu Software",提供更流畅的Snap应用浏览和管理体验。
       LibreOffice: 24.2
       GIMP: 2.10.36
       Inkscape: 1.3.2

01.开机设置一:安装
    a.空白分区
        此电脑 -> 管理 -> 磁盘管理 -> D盘 -> 压缩 -> 307200MB
    b.手动分区,将EFI系统分区作为系统启动引导器
        4096MB      逻辑分区    空间起始位置      EFI文件系统
        32768MB     逻辑分区    空间起始位置      SWAP交换空间
        4096MB      逻辑分区    空间起始位置      Ext4日志文件系统      /tmp
        4096MB      逻辑分区    空间起始位置      Ext4日志文件系统      /boot
        108544MB    逻辑分区    空间起始位置      Ext4日志文件系统      /home
        153600MB    主分区      空间起始位置      Ext4日志文件系统      /
    c.使用Ubuntu双系统
        a.设置Bios
            F2 -> Security -> Secure Boot  -> Disabled                      --关闭安全防护
            F2 -> Boot -> Legacy support  -> Boot priority -> Windows       --默认启动windows
        b.切换系统
            F12
    d.关闭AOMEI OneKey Recovery
        a.设置Bios
            F2 -> Security -> Secure Boot  -> Enabled                       --开启安全防护
            F2 -> Boot -> Legacy support  -> Boot priority -> Windows       --默认启动windows
        b.切换系统
            F12
        c.系统设置
            msconfig -> 常规(选择性启动:加载系统服务、加载启动项)、引导(删除AOMEI OneKey Recovery)-> 应用
    e.删除分区(Windows系统)
        diskpart                                                        --进入分区命令
        list disk                                                       --查看当前磁盘列表
        select disk 0                                                   --选中操作的磁盘
        list partition                                                  --查看该磁盘下的分区
        select partition X                                              --选择操作的分区
        delete partition override                                       --强制删除该分区
    f.安装Vmware Tools
        tar -zxvf VMwareTools-10.0.0-2977863.tar.gz
        sudo ./vmware-install.pl -y
    g.常见的镜像源
        http://mirrors.aliyun.com/ubuntu-releases/16.04/
        http://mirrors.zju.edu.cn/ubuntu-releases/16.04/
        http://mirrors.melbourne.co.uk/ubuntu-releases/
        http://mirrors.ustc.edu.cn/ubuntu-releases/16.04/

02.开机设置二:配置root用户
    a.配置一:root用户密码修改
        sudo passwd root                                                --修改root密码
        su                                                              --切换root用户
        sudo whoami                                                     --查看用户是否具有sudo权限
    b.配置二:root用户登陆图像界面
        gedit /usr/share/lightdm/lightdm.conf.d/50-ubuntu.conf
        greeter-show-manual-login=true                                  --追加内容
        all-guest=false                                                 --追加内容
    c.配置三:root用户登陆图像界面
        gedit /etc/pam.d/gdm-autologin
        auth required pam_success_if.so user!=root quiet_success        --注释该行
    d.配置四:root用户登陆图像界面
        gedit /etc/pam.d/gdm-password
        auth required pam_success_if.so user!=root quiet_success        --注释该行
    e.配置五:root用户图形界面登陆错误
        gedit /root/.profile
        tty -s && mesg n || true                                        --修改内容

03.开机设置三:网卡
    a.配置:卸载ideapad_laptop模块,启用无线网卡,打开文件权限
        gedit /etc/modprobe.d/ideapad.conf
        blacklist ideapad_laptop                                        --追加内容
    b.终端
        sudo chmod 777 /etc/modprobe.d/ideapad.conf                     --打开文件权限
        sudo modprobe -r ideapad_laptop                                 --卸载ideapad模块

04.开机设置四:声卡
    a.配置:root用户使用音频设备
        gedit /etc/profile
        pulseaudio --start --log-target=syslog                          --追加内容
    b.终端
        alsamixer -> HDA Intel PCH -> M                                 --允许音频输出

05.开机设置五:显卡
    a.配置:root用户亮度调节
        gedit /etc/default/grub
        quiet splash acpi_backlight=vendor acpi_osi=Linux               --修改内容
    b.终端
        sudo update-grub                                                --更新grub

06.开机设置六:进程
    a.查看
        ps -a                                                           --查看当前所有程序
        top                                                             --查看当前活跃程序
        q                                                               --返回终端
    b.终止
        kill [PID]                                                      --终止PID
        kill 37788                                                      --示例
        pkill [ProcessName]                                             --终止进程
        pkill gnome-software                                            --示例
        killall [ProcessName]                                           --终止程序所有实例
        killall gedit                                                   --示例
    c.snap
        snap changes
        sudo snap abort 7

07.开机设置七:更换数据源
    a.配置文件
        cd /etc/apt
        cp sources.list sources.list.bak
        vim sources.list
    b.配置内容
        deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
        deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
        deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
        deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
        deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
        deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
        deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
        deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
        deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
        deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
    c.更新配置
        sudo apt-get update
        sudo apt-get upgrade

1.4 machine1

01.CUDA
    a.禁止自带nouveau驱动
        a.卸载已安装的nvidia驱动
            sudo apt-get remove --purge nvidia*
            sudo apt-get purge nvidia*
            sudo apt-get autoremove
            sudo ./NIVIDIA-Linux-X86_64-384.59.run --uninstall
        b.禁用自带nouveau驱动
            gedit /etc/modprobe.d/blacklist-nouveau.conf
            blacklist nouveau
            blacklist lbm-nouveau
            options nouveau modeset=0
            alias nouveau off
            alias lbm-nouveau off
        c.更新内核
            sudo update-initramfs -u                                    --更新内核
        d.重启
            reboot
        e.测试
            lsmod | grep nouveau
    b.安装依赖
        a.获取build-essential、 gcc-multilib、dkms
            sudo apt-get install build-essential gcc-multilib dkms
            sudo apt install make
            sudo apt install gcc
            sudo apt install g++
        b.获取kernel source
            apt-get install linux-source
            apt-get install linux-headers-$(uname -r)
        c.降低内核版本
            uname -r
            sudo apt-get remove linux-image-4.4.0-140-generic
            sudo apt-get remove linux-image-$(uname -r)
        d.内核相关命令
            a.查看内核列表
                sudo dpkg --get-selections |grep linux-image
            b.查看当前使用的内核
                uname -r
            c.升级/安装内核
                sudo apt-get install linux-image-4.4.0-75-generic
            d.删除内核
                sudo apt-get remove linux-image-4.4.0-75-generic
    c.安装NVIDIA驱动
        a.查看系统信息
            lspci | grep -i nvidia                                  --查看GPU型号
            sudo dpkg --list | grep nvidia-*                        --查看NVIDIA驱动版本
            lspci | grep -i vga                                     --查看显卡型号
            http://pci-ids.ucw.cz/mods/PC/10de?action=help?help=pci --电脑显卡型号:2191
            nvidia-smi                                              --具体显卡型号
            nvcc -V                                                 --查看cuda版本
        b.卸载已安装的nvidia驱动
            sudo apt-get remove --purge nvidia*
        c.关闭图形界面
            sudo apt-get install lightdm
            sudo service lightdm stop                               --停止服务
        d.安装NVIDIA驱动
            sudo chomd a+x NVIDIA-Linux-x86_64-430.09.run
            sudo NVIDIA-Linux-x86_64-430.09.run -no-x-check -no-nouveau-check -no-opengl-files
            -no-x-check:安装驱动时关闭X服务
            -no-nouveau-check:安装驱动时禁用nouveau
            -no-opengl-files:只安装驱动文件,不安装OpenGL文件
            -Z, --disable-nouveau:禁用nouveau,此参数非必需,之前已经手动禁用nouveau
            -A:查看更多高级选项
        e.安装过程中一些选项
            The distribution-provided pre-install script failed! Are you sure you want to continue? 选择 yes 继续
            Would you like to register the kernel module souces with DKMS? This will allow DKMS to automatically build a new module, if you install a different kernel later? 选择 No 继续
            Nvidia's 32-bit compatibility libraries? 选择 No 继续
            Would you like to run the nvidia-xconfigutility to automatically update your x configuration so that the NVIDIA x driver will be used when you restart x? Any pre-existing x confile will be backed up. 选择Yes 继续
        f.挂载Nvidia驱动
            modprobe nvidia
        g.重启图形界面
            sudo service lightdm start                              --开启服务
        h.验证驱动是否安装成功
            nvidia-smi
            nvidia-settings
    d.安装CUDA9.0
        a.关闭图形界面
            sudo service lightdm stop                               --停止服务
        b.安装CUDA9.0
            sudo chmod a+x cuda_9.0.176_384.81_linux.run
            sudo ./cuda_9.0.176_384.81_linux.run --no-opengl-libs
            --no-opengl-libs:只安装驱动文件,不安装OpenGL文件,必需参数,注意不是-no-opengl-files
        c.安装过程中一些选项
            阅读声明:一直按D,然后Accept
            选项install nvidia accelerated Graphics Driver:选择N(已安装了NVIDIA驱动)
            选项install the OpenGL libraries:选择N(双显卡),选择Y(单显卡)
            后面选项:都可以选择Y
            最后一个选项:选择N(不复制Samples,因为安装目录下有samples)
            Driver :Installed
            Toolkit :Installed in /usr/local/cuda-9.0
            Samples :Installed in /home/vincent
        d.环境变量
            export CUDA_HOME=/usr/local/cuda-9.0
            export LD_LIBRARY_PATH=/usr/local/cuda-9.0/lib64:$LD_LIBRARY_PATH
            export PATH=/usr/local/cuda-9.0/bin:$PATH
        e.重启图形界面
            sudo service lightdm start                              --开启服务
        f.验证cuda是否安装成功
            nvcc -V
        g.两个测试均为Result = PASS,说明CUDA安装成功
            cd /usr/local/cuda-9.0/samples/1_Utilities/deviceQuery  --测试1:编译并测试设备 deviceQuery
            sudo make
            ./deviceQuery
            cd ../bandwidthTest                                     --测试2:编译并测试带宽 bandwidthTest
            sudo make
            ./bandwidthTest
        h.若上述测试不通过,则有有可能是缺少依赖
            sudo apt-get install freeglut3-dev \
            build-essential \
            libx11-dev \
            libxmu-dev \
            libxi-dev \
            libgl1-mesa-glx \
            libglu1-mesa \
            libglu1-mesa-dev
        i.重启
            重启黑屏,在grub界面进入linux的选择上按e键,找到quiet splash,在后面加nouveau.modeset=0,然后按F10启动
        j.卸载
            sudo /usr/local/cuda-9.2/bin/uninstall_cuda-9.2.pl      --卸载CUDA
            sudo /usr/bin/nvidia-uninstall                          --卸载NVIDIA
    e.安装CUDNN7.0.5
        a.安装:Debian File形式
            sudo dpkg -i libcudnn7_7.0.5.15-1+cuda9.0_amd64.deb
            sudo dpkg -i libcudnn7-dev_7.0.5.15-1+cuda9.0_amd64.deb
            sudo dpkg -i libcudnn7-doc_7.0.5.15-1+cuda9.0_amd64.deb
        b.安装:Tar File形式
            tar -xzvf cudnn-9.0-linux-x64-v7.tgz
            sudo cp cuda/include/cudnn.h /usr/local/cuda/include
            sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64
            sudo chmod a+r /usr/local/cuda/include/cudnn.h
            sudo chmod a+r /usr/local/cuda/lib64/libcudnn*
        c.验证Debian File形式,在/usr/src/cudnn_samples_v7有一些cudnn示例,编译mnistCUDNN sample进行验证
            cp -r /usr/src/cudnn_samples_v7/ $HOME
            cd  $HOME/cudnn_samples_v7/mnistCUDNN
            make clean && make
            ./mnistCUDNN
        d.验证CUDNN是否安装成功
            cat /usr/local/cuda/version.txt
            cat /usr/local/cuda/include/cudnn.h | grep CUDNN_MAJOR -A 2
    f.其他方式
        a.方式一:使用标准Ubuntu仓库进行自动安装
            sudo apt-get update
            sudo ubuntu-drivers devices                             --显示可安装NVIDIA驱动
            sudo ubuntu-drivers autoinstall                         --安装
        b.方式二:使用图形驱动程序PPA存储库安装NVIDIA beta驱动程序
            sudo add-apt-repository ppa:graphics-drivers/ppa        --添加ppa库到系统中
            sudo apt-get update                                     --更新
            sudo ubuntu-drivers devices                             --显示可安装NVIDIA驱动
            sudo apt-get install nvidia-xxx                         --xxx代表版本号

02.Anaconda
    a.安装Anaconda3
        sh /Ubuntu/software/JetBrains/Anaconda3/Anaconda3-2019.10-Linux-x86_64.sh
        [/root/anaconda3] >>> /usr/local/anaconda3
        mv /Ubuntu/software/JetBrains/Anaconda3/.condarc /root/.condarc
        mkdir /root/pip
        mv /Ubuntu/software/JetBrains/Anaconda3/pip/pip.ini /root/pip/pip.ini
    b.环境变量
        gedit /root/.bashrc
        export PATH=$PATH:/usr/local/anaconda3/bin
        source /root/.bashrc
    c.conda测试
        a.命令
            conda info
            conda info --envs
            conda create -n tf2 tensorflow-gpu python=3.6
            conda activate tf2
            conda deactivate
            conda remove -n tf2 --all
            conda install scipy
            conda remove scipy
            conda list
            conda --version
            conda update -n base -c defaults conda
        b.镜像源(/root/.condarc)
            channels:
              - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
              - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
              - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
              - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/menpo/
              - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/bioconda/
              - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/
              - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/
            show_channel_urls: true
            ssl_verify: true
        c.查看配置信息
            conda info
    d.python测试
        a.命令
            pip3 --version
            pip3 install --upgrade pip
            python3 --version
            python3 -m site
            python3 -m site -help
            pip freeze > requirements.txt
            pip install -r requirements.txt
            pip unistall -r requirements.txt
            https://pypi.tuna.tsinghua.edu.cn/simple
        b.镜像源(/root/pip/pip.ini)
            [global]
            index-url = https://pypi.tuna.tsinghua.edu.cn/simple/
        c.修改pip默认下载位置(/usr/lib/python3.6/site.py,第87行附近)
            USER_SITE = "/root/.local"
            USER_BASE = "/root/.local/lib/python3.6/site-packages"
        d.查看配置信息
            python3 -m site
    e.快捷方式
        a.创建anaconda.desktop
            gedit /usr/share/applications/anaconda.desktop
        b.编辑anaconda.desktop
            [Desktop Entry]
            Version=1.0
            Name=Anaconda
            Type=Application
            GenericName=Anaconda
            Comment=Scientific Python Development Environment - Python3
            Categories=Development;Science;IDE;Qt;Education;
            Exec=/usr/local/anaconda3/bin/anaconda-navigator
            Icon=/usr/local/anaconda3/lib/python3.7/site-packages/anaconda_navigator/static/images/anaconda-icon-256x256.png
            Terminal=false
            StartupNotify=true
            MimeType=text/x-python;

03.Pytorch 1.2.0
    a.创建Pytorch新环境,并指定python版本为3.7.9
        conda create -n pytorch python=3.7.9
    b.列举conda当前全部环境
        conda env list
    c.激活Pytorch新环境
        conda activate pytorch
    d.安装Pytorch(conda方式,可以判断所有安装包的版本间的兼容性,各种必备包自动安装),管理员方式启动
        a.升级conda
            conda update -n base -c defaults conda
        b.安装Pytorch的GPU版本(注意一定去掉-c pytorch,才可以使用国内镜像加速)
            conda install pytorch==1.2.0 torchvision==0.4.0 cudatoolkit=10.0
        c.安装Pytorch的CPU版本
            conda install pytorch torchvision cpuonly
    e.测试Pytorch
        import torch
        print(torch.__version__)
        print('gpu:', torch.cuda.is_available())

04.TensorFlow 2.0.0
    a.创建TensorFlow新环境,并指定python版本为3.7.9
        conda create -n tf2 tensorflow-gpu python=3.7.9
    b.列举conda当前全部环境
        conda env list
    c.激活TensorFlow新环境
        conda activate tf2
    d.安装TensorFlow(conda方式,可以判断所有安装包的版本间的兼容性,各种必备包自动安装),管理员方式启动
        a.升级conda
            conda update -n base -c defaults conda
        b.安装TensorFlow的GPU版本
            conda search tensorflow-gpu
            conda install tensorflow-gpu=2.0.0
        c.安装TensorFlow的CPU版本
            conda search tensorflow
            conda install tensorflow=2.0.0
    e.测试TensorFlow
        import tensorflow as tf
        tf.compat.v1.disable_eager_execution()
        sess = tf.compat.v1.Session()
        a=tf.constant(1)
        b=tf.constant(2)
        print(sess.run(a+b))
        print(tf.test.is_gpu_available())
    f.解决报错
        pip uninstall tensorflow
        pip install tensorflow==2.0.0
    g.tensorflow-gpu==1.8.0只支持gcc4.9
        a.报错:
            软件包gcc还没有可供安装的候选者
        b.解决
            a.添加源
                sudo gedit /etc/apt/sources.list
                deb http://dk.archive.ubuntu.com/ubuntu/ xenial main
                deb http://dk.archive.ubuntu.com/ubuntu/ xenial universe
            b.更新源
                sudo apt update
            c.安装
                sudo apt install g++-4.9
                sudo apt install gcc-4.9
        c.用update-alternatives来为整个系统更改gcc版本
            a.设置优先级
                update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 40
                update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 55
                update-alternatives --install /usr/bin/gcc gcc /usr/local/bin/gcc 54
            b.列出可用的gcc替代版本
                update-alternatives --list gcc
            c.选择可用的Python替代版本
                update-alternatives --config gcc
            d.查看版本
                gcc -v

05.Jupyter Notebook
    a.常见错误
        a.命令
            jupyter notebook --generate-config
        b.报错
            ImportError: DLL load failed: 找不到指定的模块
            ModuleNotFoundError: No module named 'pysqlite2'
        c.解决
            https://www.pianshen.com/article/56211259074/
            去sqlite3官网下载对应64位的插件,将sqlite3.def、sqlite3.dll复制到../Anaconda/DLLs目录
    b.默认路径
        a.打开文件
            gedit /root/.jupyter/jupyter_notebook_config.py
        b.修改jupyter_notebook_config.py
            ## The directory to use for notebooks and kernels.
            c.NotebookApp.notebook_dir = '/Ubuntu/software_ware/workspace_conda'
        c.运行
            jupyter notebook --allow-root

1.5 machine2

01.常见工具
    a.VScode
        sudo dpkg -i /Ubuntu/software/JetBrains/VScode/code_1.50.1-1602600906_amd64.deb
    b.Chorme
        sudo dpkg -i /Ubuntu/document/Office/Chorme/google-chrome-stable_current_amd64.deb
    c.CloudMusic
        sudo dpkg -i /Ubuntu/document/CloudMusic/netease-cloud-music_1.2.1_amd64_ubuntu_20190428.deb
    d.QQ
        sudo dpkg -i /Ubuntu/document/Tencent/QQ/linuxqq_2.0.0-b2-1084_amd64.deb
    e.software
        electronic-wechat
        Telegram Desktop
        Gnome Tweaks

09.搜狗输入法
    a.安装
        sogoupinyin_2.3.2.07_amd64-831.deb
    b.卸载
        Language Support -> fcitx修改为IBus                              --修改输入法
        sudo dpkg -l sog*                                               --查找
        sudo dpkg -P sogoupinyin                                        --卸载
        sudo apt-get purge fcitx                                        --彻底删除fcitx
        sudo apt-get autoremove                                         --删除多余的依赖

10.火狐浏览器
    a.安装国内版
        tar jxvf Firefox-latest-x86_64.tar.bz2
        cd Firefox-latest-x86_64
        sudo mv firefox /usr/lib/
    b.快捷方式
        gedit /usr/share/applications/firefox.desktop
        [Desktop Entry]
        Name=firefox
        Name[zh_CN]=火狐浏览器
        Comment=火狐浏览器
        Exec=/usr/lib/firefox/firefox
        Icon=/usr/lib/firefox/browser/chrome/icons/default/default128.png
        Terminal=false
        Type=Application
        Categories=Appliction;
        Encoding=UTF-8
        StartupNotify=true
    d.Flash
        tar -zxvf flash_player_npapi_linux.x86_64.tar.gz
        mv libflashplayer.so  /usr/lib/mozilla/plugins
        chmod 777 /usr/lib/mozilla/plugins/libflashplayer.so

11.Typora
    a.下载
        wget -qO - https://typora.io/linux/public-key.asc | sudo apt-key add -
    b.仓库
        sudo add-apt-repository 'deb https://typora.io/linux ./'
        sudo apt-get update
    c.安装
        sudo apt-get install typora
    d.图标
        usr/share/application -> Typora -> 属性 -> 命令:Exec=typora %U --no-sandbox
    e.解压
        /Ubuntu/document/Office/Typora
        tar -zxvf Typora-linux-x64.tar.gz
        cd Typora-linux-x64
        mv /bin/Typora-linux-x64 /usr/local
    f.创建pycharm.desktop
        gedit /usr/share/applications/Typora.desktop
    g.编辑pycharm.desktop
        [Desktop Entry]
        Name=Typora
        GenericName=Editorubuntu / linux
        Comment=Typroa - a markdown editor
        Exec="/usr/local/Typora-linux-x64/Typora" %U --no-sandbox
        Icon=/usr/local/Typora-linux-x64/resources/app/asserts/icon/icon_256x256.png
        Terminal=false
        Categories=Markdown;ux
        StartupNotify=false
        Type=Application

12.宝塔面板
    a.升级openssl版本为1.1.1
        cd /Ubuntu/software/Linux/BaoTa/
        tar -zxvf openssl-1.1.1g.tar.gz
        cd openssl-1.1.1g
        ./config
        make && make install
        echo "export LD_LIBRARY_PATH=/usr/local/lib" >> ~/.bashrc       --添加环境
        export LD_LIBRARY_PATH=/usr/local/lib                           --添加环境
        openssl version                                                 --查看版本
    b.安装
        wget -O install.sh http://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh f2dec8
    c.登录
        外网面板地址: http://192.168.3.102:8888/9a6bf9a9
        内网面板地址: http://192.168.3.102:8888/9a6bf9a9
        username: myslayers
        password: XXXXXXXX
    d.设置
        bt
        /etc/init.d/bt default

13.Pycharm
    a.安装
        cd /Ubuntu/software/JetBrains/Pycharm/
        tar -zxvf pycharm-professional-2019.2.6.tar.gz
        mv pycharm-2019.2.6 /usr/local/pycharm
    b.环境变量
        gedit /root/.bashrc
        export PATH=$PATH:/usr/local/pycharm/bin
        source /root/.bashrc
    c.快捷方式
        a.创建pycharm.desktop
            gedit /usr/share/applications/pycharm.desktop
        b.编辑pycharm.desktop
            [Desktop Entry]
            Version=1.0
            Type=Application
            Name=PyCharm
            Icon=/usr/local/pycharm/bin/pycharm.svg
            Exec=sh /usr/local/pycharm/bin/pycharm.sh
            MimeType=application/x-py;
            Name[en_US]=pycharm

14.IntelliJ IDEA
    a.安装
        cd /Ubuntu/software/JetBrains/IDEA
        tar -zxvf ideaIU-2019.3.5.tar.gz
        mv idea-IU-193.7288.26 /usr/local/idea
    b.环境变量
        gedit /root/.bashrc
        export PATH=$PATH:/usr/local/idea/bin
        source /root/.bashrc
    c.快捷方式
        a.创建idea.desktop
            gedit /usr/share/applications/idea.desktop
        b.编辑idea.desktop
            [Desktop Entry]
            Version=1.0
            Type=Application
            Name=IntelliJ IDEA
            Icon=/usr/local/idea/bin/idea.svg
            Exec=sh /usr/local/idea/bin/idea.sh
            MimeType=application/x-py;
            Name[en_US]=IntelliJ IDEA

15.WebStorm
    a.安装
        cd /Ubuntu/software/JetBrains/WebStorm
        tar -zxvf WebStorm-2019.3.5.tar.gz
        mv WebStorm-193.7288.28 /usr/local/webstorm
    b.环境变量
        gedit /root/.bashrc
        export PATH=$PATH:/usr/local/webstorm/bin
        source /root/.bashrc
    c.快捷方式
        a.创建webstorm.desktop
            gedit /usr/share/applications/webstorm.desktop
        b.编辑webstorm.desktop
            [Desktop Entry]
            Version=1.0
            Type=Application
            Name=WebStorm
            Icon=/usr/local/webstorm/bin/webstorm.svg
            Exec=sh /usr/local/webstorm/bin/webstorm.sh
            MimeType=application/x-py;
            Name[en_US]=WebStorm

16.Datagrip
    a.安装
        cd /Ubuntu/software/JetBrains/Datagrip
        tar -zxvf datagrip-2019.3.5.tar.gz
        mv DataGrip-2019.3.5 /usr/local/datagrip
    b.环境变量
        gedit /root/.bashrc
        export PATH=$PATH:/usr/local/datagrip/bin
        source /root/.bashrc
    c.快捷方式
        a.创建datagrip.desktop
            gedit /usr/share/applications/datagrip.desktop
        b.编辑datagrip.desktop
            [Desktop Entry]
            Version=1.0
            Type=Application
            Name=Datagrip
            Icon=/usr/local/datagrip/bin/datagrip.svg
            Exec=sh /usr/local/datagrip/bin/datagrip.sh
            MimeType=application/x-py;
            Name[en_US]=Datagrip

2 mysql

2.1 bio

01.常用信息1
    a.db4free,替代sqlite
        db4free.net - 免费的 MySQL 数据库
        只提供MySQL服务
        提供服务:基本最新版Mysql8.0服务
        服务器地址:国外
        优点:
        1、无需注册,直接用邮箱申请
        2、用户名称和密码可以自定义
        缺点:
        1、一个邮箱账号,只能绑定一个账号
        2、不定期重置仓库大小超过200MB的仓库数据
    b.sqlpub
        SQLPub - 免费的MySQL数据库
        只提供MySQL服务
        提供服务:最新版Mysql8.0服务;最大36000次/小时的请求、同时30个连接和500M存储空间
        服务器地址:国内
        优点:
        1、无需注册,直接用邮箱申请
        2、仓库空间比较大
        缺点:
        1、一个邮箱账号,只能绑定一个账号
        2、密码自动生成,比较复杂
    c.ElephantSQL
        ElephantSQL - PostgreSQL as a Service
        提供PostgreSQL服务
        服务器地址:由国内地址
        提供服务:20MB免费
    d.MongoDB Cloud
        提供MongoDB数据库服务
        服务器地址:有国内
        提供服务:永久512MB免费
        优点:
        1、空间大且永久免费
        2、有国内服务器地址
    e.Redis Cloud
        提供Redis服务

02.常用信息2
    a.SVNCloud
        专业SVN服务,代码托管,数据库托管,MYSQL服务(wsfdb.cn)
        只提供MySQL服务
        提供服务(免费版本):Mysql7.x;永久5MB(免费),可以升级vip扩展(存储容量);支持:在线备份、备份下载、导入备份、修改密码、实时开通、自动清理日志
        服务器地址:国内
        优点:
        1、一个账号,可以无限创建仓库
        2、用户名和密码可以自定义(用户名和仓库名一样)
        缺点:
        需要注册账号使用
        注:这个公司同时提供svn云服务,免费的有80MB,同样不限制创建数量
    b.MemFireDB
        只提供PostgreSQL服务
        服务器地址:国内
        缺点:一个账号只能注册一个
    c.Heroku
        Cloud Application Platform | Heroku
        提供PostgreSQL服务
        服务器地址:国外
        提供服务:1w行数据(小的可怜)
        优点:可创建多个数据库
        缺点:空间小、连接速度慢
    d.RabbitMQ
        CloudAMQP - Queue starts here.
        提供RabbitMQ服务
        -----------------------------------------------------------------------------------------------------
        Little Lemur - For Development
        Max 100 queues
        Max 10 000 queued messages
        Max idle queue time 28 days
    e.Kafka
        CloudKarafka
        Apache Kafka Message streaming as a Service
        提供Kafka服务
        -----------------------------------------------------------------------------------------------------
        付费

03.常用信息3
    a.地区
        US East (N. Virginia) - 美国东部(北弗吉尼亚)
        US East (Ohio) - 美国东部(俄亥俄)
        US West (Oregon) - 美国西部(俄勒冈)

2.2 mock

01.windows
    a.Node
        a.环境变量
            NODE_HOME:D:\software\JavaScript\Nodejs
            path:%NODE_HOME%
                  %NOED_HOME%\node_modules
                  D:\software\Repository\Repository_Npm
        b.测试
            node -v
        c.配置
            npm config set prefix "D:\software\Repository\Repository_Npm"       --设置本地仓库
            npm config set cache "D:\software\Repository\Repository_Npm_Cache"  --设置缓存位置
            npm config ls                                                       --查看是否修改成功
    b.MongoDB
        a.环境变量
            MongoDB_HOME:D:\software\SQL\MongoDB
            path:%MongoDB_HOME%\bin
        b.测试
            mongod --dbpath=D:\software_ware\workspace_mongo\data --port=27017 --logpath=D:\software_ware\workspace_mongo\log\mongo.log --install --serviceName "MongoDB"
            net start MongoDB                                                   --启动服务
            mongo                                                               --启动
    c.Redis
        a.环境变量
            Redis_HOME:D:\software\SQL\Redis
            path:%Redis_HOME%
        b.测试
            redis-server.exe redis.windows.conf                                 --服务端
            redis-cli.exe -h 127.0.0.1 -p 6379                                  --客户端
    d.Easymock
        a.下载git
            yum install -y git
        b.克隆项目
            git clone https://github.com/easy-mock/easy-mock.git
        c.安装npm
            npm install -g cnpm --registry=https://registry.npm.taobao.org
            cnpm install(如果无法使用npm,刷新环境变量source /etc/profile)
        d.启动
            npm run dev
        e.测试
            http://127.0.0.1:7300
        f.部署阶段
            a.编译easy-mock文件
                npm run build
            b.启动
                pm2 start app.js -i 4 -n Easymock                               --启动
                pm2 save                                                        --保存NodeJS服务
                pm2 list                                                        --查看列表
                pm2 startup                                                     --创建开机启动
                127.0.0.1:7300                                                  --访问

02.linux
    a.nodejs
        a.下载
            wget https://nodejs.org/dist/v8.9.1/node-v8.9.1-linux-x64.tar.xz
        b.解压
            tar -xvJf node-v8.9.1-linux-x64.tar.xz
        c.重命名
            mv node-v8.9.1-linux-x64 node
        d.配置环境变量
            vi /etc/profile
            export PATH=$JAVA_HOME/bin:/apps/node/bin:/apps/mongodb/bin:$PATH
            source /etc/profile
    b.MongoDB
        a.下载
            curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.6.4.tgz
        b.解压
            tar -zxvf mongodb-linux-x86_64-3.6.4.tgz
        c.重命名
            mv mongodb-linux-x86_64-3.6.4 mongodb
        d.配置环境变量
            vi /etc/profile
            export PATH=$JAVA_HOME/bin:/apps/node/bin:/apps/mongodb/bin:$PATH
            source /etc/profile
        e.配置存储数据、日志
            cd mongodb/
            mkdir data
            touch logs
        f.启动
            bin/mongod --dbpath=/apps/mongodb/data --logpath=/apps/mongodb/logs --port=27017 &
    c.redis
        a.下载
            wget http://download.redis.io/releases/redis-4.0.0.tar.gz
        b.解压
            tar -zxvf redis-4.0.0.tar.gz
        c.重命名
            mv redis-4.0.0 redis
        d.编译
            cd redis/
            yum install gcc-c++
            make MALLOC=libc
        e.配置redis.conf
            daemonize yes
        f.启动
            src/redis-server redis.conf &
            src/redis-cli -p 6379
    d.easymock
        a.下载git
            yum install -y git
        b.克隆项目
            git clone https://github.com/easy-mock/easy-mock.git
        c.安装npm
            npm install -g cnpm --registry=https://registry.npm.taobao.org
            cnpm install(如果无法使用npm,刷新环境变量source /etc/profile)
        d.启动
            npm run dev
        e.测试
            http://192.168.2.128:7300

2.3 yearning

01.下载
    http://yearning.io/

02.配置
    [Mysql]
    Db = "Yearning"
    Host = "127.0.0.1"
    Port = "3306"
    Password = "xxxx"
    User = "root"

    [General]   #数据库加解密key,只可更改一次。
    SecretKey = "dbcjqheupqjsuwsm"

03.初始化数据结构
    ./Yearning -m

04.启动
    ./Yearning -s

05.测试
    192.168.2.128:8000
    admin / Yearning_admin

2.4 activemq

01.下载
    wget https://mirrors.tuna.tsinghua.edu.cn/apache/activemq/5.15.13/apache-activemq-5.15.13-bin.tar.gz
    tar -zxvf apache-activemq-5.15.13-bin.tar.gz

02.启动
    cd apache-activemq-5.15.13
    bin/activemq start

03.测试
    192.168.2.128:8161                                                      --测试(用户名:admin  密码:admin)

2.5 rabbitmq

01.安装erlang
    a.安装依赖
        yum -y install gcc glibc-devel make ncurses-devel openssl-devel xmlto perl wget gtk2-devel binutils-devel
    b.下载
        wget http://erlang.org/download/otp_src_22.0.tar.gz
        http://file.zhaobl.com/common/otp_src_22.0.tar.gz                   --速度过慢,切换地址直接下载
    c.解压
        tar -zxvf otp_src_22.0.tar.gz
    d.移走
        mv otp_src_22.0 /usr/local/
    e.切换目录
        cd /usr/local/otp_src_22.0/
    f.创建即将安装的目录
        mkdir ../erlang
    g.配置安装路径
        ./configure --prefix=/usr/local/erlang
    h.安装
        make install
    i.查看是否安装成功
        ll /usr/local/erlang/bin
    j.添加环境变量
        echo 'export PATH=$PATH:/usr/local/erlang/bin' >> /etc/profile
    k.刷新环境变量
        source /etc/profile
    l.测试命令
        erl

02.安装RabbitMQ
    a.下载
        wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.15/rabbitmq-server-generic-unix-3.7.15.tar.xz
    b.解压
        yum install -y xz                                                   --解压tar.xz格式
        /bin/xz -d rabbitmq-server-generic-unix-3.7.15.tar.xz               --第一次解压
        tar -xvf rabbitmq-server-generic-unix-3.7.15.tar                    --第二次解压
    c.移走
        mv rabbitmq_server-3.7.15/ /usr/local/
    d.改名
        mv /usr/local/rabbitmq_server-3.7.15  rabbitmq
    e.配置环境变量
        echo 'export PATH=$PATH:/usr/local/rabbitmq/sbin' >> /etc/profile
    f.刷新环境变量
        source /etc/profile
    g.创建配置目录
        mkdir /etc/rabbitmq
    h.启动命令
        rabbitmq-server -detached                                           --启动
        rabbitmqctl stop                                                    --停止
        rabbitmqctl status                                                  --状态
    i.WEB管理
        rabbitmq-plugins enable rabbitmq_management                         --开启WEB插件
        http://127.0.0.1:15672/                                             --用户名guest、密码guest
    j.用户管理
        rabbitmqctl list_users                                              --查看所有用户
        rabbitmqctl add_user myslayers 4023615                              --添加一个用户
        rabbitmqctl set_permissions -p "/" zhaobl ".*" ".*" ".*"            --配置权限
        rabbitmqctl list_user_permissions myslayers                         --查看用户权限
        rabbitmqctl set_user_tags zhaobl administrator                      --设置tag
        rabbitmqctl delete_user guest                                       --删除用户

2.6 mysql-5.5.58

01.清理Centos7自带mariadb
    rpm -qa |grep -i mysql
    rpm -qa |grep -i mariadb
    yum remove mariadb-libs-5.5.56-2.el7.x86_64

02.rpm安装MySQL
    a.安装
        rpm -ivh MySQL-server-5.5.58-1.el6.x86_64.rpm --force --nodeps
        rpm -ivh MySQL-client-5.5.58-1.el6.x86_64.rpm --force --nodeps
    b.验证
        mysqladmin --version

03.配置MySQL
    a.启动MySQL服务
        service mysql start
    b.查看MySQL状态
        service mysql status
    c.设置密码
        /usr/bin/mysqladmin -u root password root
    d.登录MySQL
        mysql -uroot -p
    e.开启MySQL远程访问
        mysql> grant all privileges on *.* to 'root'@'%' identified by 'root' with grant option;
        mysql> flush privileges;
        mysql> exit
    f.Windows远程访问
        mysql -uroot -proot -h192.168.2.128 -P3306

04.常见命令
    a.启动命令
        service mysql start
    b.关闭命令
        service mysql stop
    c.重启命令
        service mysql restart
    d.查看服务状态
        service mysql status
    e.查看MySQL系统配置
        cat /etc/my.cnf

05.MySQL服务:常见报错/var/lib/mysql/mysql.sock不存在
    a.手动启动服务
        /etc/init.d/mysql start
    b.开机自启
        chkconfig mysql on
    c.关闭开机自启
        chkconfig mysql off
    d.检查开机自启
        ntsysv

2.7 mysql-5.7.17

01.清理Centos7自带mariadb
    rpm -qa |grep -i mysql
    rpm -qa |grep -i mariadb
    yum remove mariadb-libs-5.5.56-2.el7.x86_64

02.安装MySQL
    a.下载
        wget http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm
    b.解压
        rpm -ivh mysql57-community-release-el7-10.noarch.rpm
    c.安装
        yum install mysql-community-server

03.修改密码
    a.启动MySQL服务
        systemctl start mysqld.service
    b.查看MySQL状态
        systemctl status mysqld.service
    c.从日志中获取临时密码
        grep "password" /var/log/mysqld.log
    d.登录MySQL
        mysql -uroot -p
    e.修改密码
        mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';

04.远程访问
    a.开启MySQL远程访问
        mysql> grant all privileges on *.* to 'root'@'%' identified by '123456' with grant option;
        mysql> flush privileges;
        mysql> exit;
    b.firewalld添加开放端口
        firewall-cmd --zone=public --add-port=3306/tcp --permanent      --mysql端口3306
        firewall-cmd --zone=public --add-port=8080/tcp --permanent      --Tomcat端口8080
        firewall-cmd --reload                                           --重启防火墙
        systemctl stop firewalld                                        --关闭防火墙
        systemctl disable firewalld                                     --禁止开机自启
    c.远程cmd登录MySQL
        mysql -uroot -proot -h192.168.2.128 -P3306 -Dtest
        mysql -u用户名 -p密码 -h远程数据库IP地址 -P端口 -D数据库名(可以不用指定具体的数据库名)

05.修改编码
    a.查看字符编码
        mysql> status
        mysql> show variables like '%char%' ;
    b.修改配置文件,vi /etc/my.cnf
        [client]                                                    --添加第一行
        default-character-set=utf8                                  --添加第二行

        [mysqld]
        datadir=/var/lib/mysql
        socket=/var/lib/mysql/mysql.sock
        character-set-server=utf8                                   --添加第三行
        collation-server=utf8_general_ci                            --添加第四行

        symbolic-links=0

        log-error=/var/log/mysqld.log
        pid-file=/var/run/mysqld/mysqld.pid
    c.保存更改后的my.cnf文件后,重启下mysql
        systemctl restart mysqld.service

06.创建新的MySQL用户,并授权
    a.创建用户
        create user 'testuser'@'%' identified with mysql_native_password by '123456';
    b.授权
        grant all privileges on *.* to 'testuser'@'%' with grant option;
    c.修改密码过期规则
        alter user 'testuser'@'%' identified by '123456' password expire never;
    d.立即生效
        flush privileges;

07.binlog功能
    a.修改配置文件,vi /etc/my.cnf
        [client]
        default-character-set=utf8

        [mysqld]
        datadir=/var/lib/mysql
        socket=/var/lib/mysql/mysql.sock
        character-set-server=utf8
        collation-server=utf8_general_ci

        symbolic-links=0

        log-error=/var/log/mysqld.log
        pid-file=/var/run/mysqld/mysqld.pid

        log-bin=mysql-bin                                           --文件目录
        binlog-format=ROW                                           --选择row模式
        server_id=1                                                 --canal和slaveId不重复
    b.验证是否开启
        show master logs;                                           --查看所有日志文件
        show master status;                                         --查看正在写入的日志文件
        show binlog events;                                         --查看当前binlog文件内容
        show binlog events in 'my-bin.000001';                      --指定日志文件查看
        flush logs;                                                 --结束正在写入日志文件
        reset master;                                               --删除所有日志,重新记录
    c.二进制日志文件导出
        mysqlbinlog binlog.000001 >1.sql                            --导出为sql格式
        mysqlbinlog --start-datetime="2018-03-20 11:25:56" --stop-datetime="2018-03-20 14:20:10" mysql-bin.000001 > /data/test01.log                       --按时间点导出
        mysqlbinlog --start-position=5786 --stop-position=6254 mysql-bin.000001 > /data/test02.log                                                   --按事件位置导出

08.如何确定MySQL服务已经启动?
    a.chkconfig命令
        chkconfig --list
    b.查询端口
        netstat -tulpn
    c.查询进程
        ps -ef | grep mysqld
        ps -ef | grep mysqld_safe

09.MySQL服务:常见报错/var/lib/mysql/mysql.sock不存在
    a.手动启动服务
        /etc/init.d/mysqld start
    b.开机自启
        systemctl enable mysqld.service
    c.关闭开机自启
        systemctl disable mysqld.service
    d.检查开机自启
        ntsysv

10.彻底卸载MySQL
    a.查看是否有安装的MySQL:
        rpm -qa | grep -i mysql
        yum list install mysql*
    b.卸载MySQL安装包
        yum remove mysql mysql-server mysql-libs compat-mysql51
        yum remove mysql-community-release、
        rpm -e --nodeps mysql-community-libs-5.7.22-1.el7.x86_64
        rpm -e –nodeps mysql57-community-release-el7-11.noarch
    c.删除残留的MySQL目录或文件
        i.残留的MySQL目录
            whereis mysql
        ii.残留的MySQL文件
            find / -name mysql
        iii.删除
            rm -rf xxx
    d.删除MySQL配置文件
        rm –rf /usr/my.cnf
        rm -rf /root/.mysql_sercret
    e.删除MySQL开机自启服务
        chkconfig --list | grep -i mysql
        chkconfig --del mysqld

11.免密码登录MySQL
    a.停止MySQL服务
        systemctl stop mysqld.service
    b.以不检查权限的方式启动mysqld,root身份运行
        mysqld --user=root --skip-grant-tables &
    c.免密码登录MySQL
        mysql -u root
    d.设置密码
        UPDATE mysql.user SET authentication_string=PASSWORD('密码') where USER='root';
        ALTER USER 'root'@'localhost' IDENTIFIED BY '密码';
        SET PASSWORD FOR root=PASSWORD('密码');

12.数据库存放目录
    a.数据库目录
        datadir=/var/lib/mysql
    b.pid文件目录
        pid-file=/var/lib/mysql/bigdata01.pid
    c.MySQL核心目录
        /var/lib/mysql          安装目录
        /usr/share/mysql        配置文件
        /usr/bin                命令目录(mysqladmin、mysqldump等)
        /etc/init.d/mysql       启停脚本
    d.MySQL配置文件
        my-huge.cnf             高端服务器  1-2G内存
        my-large.cnf            中等规模
        my-medium.cnf           一般
        my-small.cnf            较小
        但是,以上配置文件mysql默认不能识别,默认只能识别 /etc/my.cnf
        若采用 my-huge.cnf,通过命令:#cp /usr/share/mysql/my-huge.cnf /etc/my.cnf
    e.注意
        MySQL5.5:默认配置文件/etc/my.cnf
        MySQL5.6:默认配置文件/etc/mysql-default.cnf

2.8 mysql-8.0.21

01.清理Centos7自带mariadb
    rpm -qa |grep -i mysql
    rpm -qa |grep -i mariadb
    yum remove mariadb-libs-5.5.56-2.el7.x86_64

02.安装MySQL
    a.下载
        wget https://dev.mysql.com/downloads/file/?id=496950
    b.解压
        tar -xvf mysql-8.0.21-1.el7.x86_64.rpm-bundle.tar
    c.依次安装common、libs、client、server
        rpm -ivh mysql-community-common-8.0.21-1.el7.x86_64.rpm --force --nodeps
        rpm -ivh mysql-community-libs-8.0.21-1.el7.x86_64.rpm --force --nodeps
        rpm -ivh mysql-community-client-8.0.21-1.el7.x86_64.rpm --force --nodeps
        rpm -ivh mysql-community-server-8.0.21-1.el7.x86_64.rpm --force --nodeps
    d.验证
        mysqladmin --version

03.修改密码
    a.用户授权:初始化时,如果不存在,会创建它;如果存在,而且该目录里有数据,会报错并终止初始化
        vi /etc/my.cnf
        datadir=/var/lib/mysql
        socket=/var/lib/mysql/mysql.sock
        chmod -R 777 /var/lib/mysql                                 --文件权限
        rm -rf /var/lib/mysql/*                                     --删除文件,防止报错
    b.初始化数据
        mysqld --initialize
    c.开启服务
        systemctl start mysqld.service
    d.启用数据
        systemctl enable mysqld
    e.从日志中获取临时密码
        grep "password" /var/log/mysqld.log
    f.登录MySQL
        mysql -uroot -p
    g.修改密码
        ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '123456';

04.远程访问
    a.开启MySQL远程访问
        mysql> use mysql;
        mysql> select host, user, authentication_string, plugin from user;
        mysql> update user set host='%' where user='root';
        mysql> flush privileges;
        mysql> exit;
    b.firewalld添加开放端口
        firewall-cmd --zone=public --add-port=3306/tcp --permanent      --mysql端口3306
        firewall-cmd --zone=public --add-port=8080/tcp --permanent      --Tomcat端口8080
        firewall-cmd --reload                                           --重启防火墙
        systemctl stop firewalld                                        --关闭防火墙
        systemctl disable firewalld                                     --禁止开机自启
    c.远程cmd登录MySQL
        mysql -uroot -proot -h192.168.2.128 -P3306 -Dtest
        mysql -u用户名 -p密码 -h远程数据库IP地址 -P端口 -D数据库名(可以不用指定具体的数据库名)

3 fastdfs

3.1 tracker

01.gcc环境
    yum install gcc-c++

02.下载Tracker依赖库 -> libevent库
    yum -y install libevent

03.下载Tracker依赖库 -> libfastcommon库
    a.下载
        cd /usr/local
        wget https://github.com/happyfish100/libfastcommon/archive/V1.0.43.tar.gz
        tar -zxvf libfastcommon-1.0.43.tar.gz
    b.编译
        cd /usr/local/libfastcommon-1.0.43/
        ./make.sh
        ./make.sh install

04.安装Tracker
    a.下载
        cd /usr/local
        https://github.com/happyfish100/fastdfs/archive/V6.06.tar.gz
        tar -zxvf fastdfs-6.06.tar.gz
    b.编译
        cd /usr/local/fastdfs-6.06/
        ./make.sh
        ./make.sh install
    c.将conf目录下的配置文件拷贝到/etc/fdfs目录下
        cd /usr/local/fastdfs-6.06/conf/
        cp ./* /etc/fdfs/
    d.配置tracker.conf
        mkdir /home/myslayers/fastdfs                                   --创建元数据存储目录

        vi /etc/fdfs/tracker.conf                                       --打开tracker.conf

        port = 22122                                                    --默认端口
        base_path = /home/myslayers/fastdfs                             --元数据存储目录必须存在
    e.启动
        /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf start             --启动Tracker
        /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf stop              --关闭Tracker

3.2 storage

01.gcc环境
    yum install gcc-c++

02.下载Tracker、Storage依赖库 -> libevent库
    yum -y install libevent

03.下载Tracker、Storage依赖库 -> libfastcommon库
    a.下载
        cd /usr/local
        wget https://github.com/happyfish100/libfastcommon/archive/V1.0.43.tar.gz
        tar -zxvf libfastcommon-1.0.43.tar.gz
    b.编译
        cd /usr/local/libfastcommon-1.0.43/
        ./make.sh
        ./make.sh install

04.安装Storage
    a.下载
        cd /usr/local
        https://github.com/happyfish100/fastdfs/archive/V6.06.tar.gz
        tar -zxvf fastdfs-6.06.tar.gz
    b.编译
        cd /usr/local/fastdfs-6.06/
        ./make.sh
        ./make.sh install
    c.将conf目录下的配置文件拷贝到/etc/fdfs目录下
        cd /usr/local/fastdfs-6.06/conf/
        cp ./* /etc/fdfs/
    d.配置storage.conf
        mkdir /home/myslayers/fastdfs                                   --创建元数据存储目录

        vi /etc/fdfs/storage.conf                                       --打开storage.conf

        base_path = /home/myslayers/fastdfs
        store_path0 = /home/myslayers/fastdfs
        tracker_server = 192.168.2.128.:22122                           --不能是127.0.0.1
        #tracker_server = 192.168.209.122:22122                         --注释掉另一个不用的地址
    e.启动
        /usr/bin/fdfs_storaged /etc/fdfs/storage.conf start             --启动Storage
        /usr/bin/fdfs_storaged /etc/fdfs/storage.conf stop              --关闭Storage

3.3 nginx_fastdfs_module

01.fastdfs-nginx-module:重定向文件连接到源服务器取文件,避免客户端由于复制延迟导致的文件无法访问错误
    a.下载
        cd /usr/local
        https://github.com/happyfish100/fastdfs-nginx-module/archive/V1.22.tar.gz
        tar -zxvf fastdfs-nginx-module-1.22.tar.gz
    b.将/usr/local/fastdfs-nginx-module-1.22/src/mod_fastdfs.conf拷贝到/etc/fdfs/目录下
        cp /usr/local/fastdfs-nginx-module-1.22/src/mod_fastdfs.conf /etc/fdfs/
    c.配置mod_fastdfs.conf
        mkdir /home/myslayers/fastdfs                                   --创建元数据存储目录
        vi /etc/fdfs/mod_fastdfs.conf                                   --打开mod_fastdfs.conf
        base_path = /home/myslayers/fastdfs
        store_path0 = /home/myslayers/fastdfs
        tracker_server = 192.168.2.128:22122
        url_have_group_name = true

02.Nginx编译时,--add-module
    a.下载
        cd /usr/local
        wget https://nginx.org/download/nginx-1.14.0.tar.gz
        tar -zxvf nginx-1.14.0.tar.gz
    b.依赖
        yum install -y gcc pcre pcre-devel
        yum install -y openssl openssl-devel
    c.编译
        cd /usr/local/nginx-1.14.0/
        ./configure --add-module=/usr/local/fastdfs-nginx-module-1.22/src
        make
        make install
    d.配置,请求转发
        vi /usr/local/nginx/conf/nginx.conf

        user root;                                                      --解决权限
        worker_processes  1;
        events {
            worker_connections  1024;
        }
        http {
            include       mime.types;
            default_type  application/octet-stream;
            sendfile        on;
            keepalive_timeout  65;
            server {
                listen       80;
                server_name  localhost;
                location ~/group[0-9]/ {
                    ngx_fastdfs_module;
                }
                error_page   500 502 503 504  /50x.html;
                location = /50x.html {
                    root   html;
                }
            }
        }

        /usr/local/nginx/sbin/nginx -s reload                           --重启nginx
    e.启动
        /usr/local/nginx/sbin/nginx                                     --启动Nginx
        /usr/local/nginx/sbin/nginx -s stop                             --停止Nginx

03.开机自启
    vi /etc/rc.local                                                    --打开文件

    /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart               --追加
    /usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart               --追加
    /usr/local/nginx/sbin/nginx                                         --追加

    chmod 755 /etc/rc.local                                             --设置文件权限

3.4 upload download

01.pom.xml
    <dependency>
        <groupId>cn.bestwu</groupId>
        <artifactId>fastdfs-client-java</artifactId>
        <version>1.27</version>
    </dependency>

02.fastdfs-client.properties
    fastdfs.connect_timeout_in_seconds = 5
    fastdfs.network_timeout_in_seconds = 30
    fastdfs.charset = UTF-8
    fastdfs.http_anti_steal_token = false
    fastdfs.http_secret_key = FastDFS1234567890
    fastdfs.http_tracker_http_port = 80
    fastdfs.tracker_servers = 192.168.2.128:22122
    fastdfs.connection_pool.enabled = true
    fastdfs.connection_pool.max_count_per_entry = 500
    default value is 3600
    fastdfs.connection_pool.max_idle_time = 3600
    millisecond, default value is 1000
    fastdfs.connection_pool.max_wait_time_in_ms = 1000

03.文件上传
    @Test
    void testUpload() throws IOException, MyException {
        //创建StorageClient1
        ClientGlobal.initByProperties("fastdfs-client.properties");
        TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        StorageServer storageServer = null;
        StorageClient1 client1 = new StorageClient1(trackerServer, storageServer);
        //NameValuePair保存的是文件的元数据信息
        NameValuePair pairs[] = null;
        String filePath = client1.upload_file1("D:\\document\\Background\\2.jpg", "jpg", pairs);
        System.out.println(filePath);
    }

04.文件下载
    @Test
    void testDownload() throws IOException, MyException {
        ClientGlobal.initByProperties("fastdfs-client.properties");
        TrackerClient tracker = new TrackerClient();
        TrackerServer trackerServer = tracker.getConnection();
        StorageServer storageServer = null;
        StorageClient1 client = new StorageClient1(trackerServer, storageServer);
        byte[] bytes = client.download_file1("group1/M00/00/00/wKgCgF-FtTuAW7D5ABOZB_BKrKk977.jpg");
        FileOutputStream fos = new FileOutputStream(new File("D:\\test.png"));
        fos.write(bytes);
        fos.close();
    }

3.5 token check

01.开启令牌校验
    vi /etc/fdfs/http.conf

    http.anti_steal.check_token = true                                  --开启校验
    http.anti_steal.secret_key = FastDFS1234567890                      --密钥
    http.anti_steal.token_check_fail = /home/yuqing/fastdfs/conf/anti-steal.jpg

02.重启服务器
    /usr/local/nginx/sbin/nginx -s stop                                 --停止Nginx
    /usr/local/nginx/sbin/nginx                                         --启动Nginx

03.获取令牌
    @Test
    public void getToken() throws Exception {
        int ts = (int) Instant.now().getEpochSecond();
        //第一个参数:访问的文件,注意不包含 group
        //第二个参数:时间戳
        //第三个参数:密钥
        String token = ProtoCommon.getToken("M00/00/00/wKgCgF-FtTuAW7D5ABOZB_BKrKk977.jpg", ts, "FastDFS1234567890");
        StringBuilder sb = new StringBuilder();
        sb.append("?token=").append(token);
        sb.append("&ts=").append(ts);
        System.out.println(sb.toString());
    }

04.携带令牌访问
    http://192.168.2.128/group1/M00/00/00/wKgCgF-FtTuAW7D5ABOZB_BKrKk977.jpg?token=5f4b1976727a3ba439fc2d8874945581&ts=1602603800

4 service

4.1 aria2

01.安装(一是命令行下载模式,二是RPC模式+网页管理)
    将https://github.com/aria2/aria2/releases/tag/release-1.35.0替代文件夹中的“aria2c.exe” -> 启动aria2.exe

02.配置(aria2.conf)
    a.修改默认下载目录
        #文件的保存路径(可使用绝对路径或相对路径),默认: 当前启动位置
        dir=D:\Download
    b.修改服务器默认连接数
        #同一服务器连接数,添加时可指定,默认:1,默认编译windows可设置的最大连接数为16
        max-connection-per-server=16
    c.开启BT下列设置
        enable-dht=true
        bt-enable-lpd=true
        enable-peer-exchange=true
    d.添加trackers,逗号隔开,获取https://github.com/XIU2/TrackersListCollection/blob/master/best_aria2.txt
        bt-tracker=udp://tracker.coppersurfer.tk:6969/announce,

03.实现开机无cmd窗口启动
    a.方式一:编辑HideRunAria2.vbs文件(普遍写法)
        CreateObject("WScript.Shell").Run "D:\software\Linux\Window\Aria2\aria2c.exe --conf-path=aria2.conf",0
    b.方式二:编辑HideRunAria2.vbs文件(防止多开)
        Set wmi=GetObject("winmgmts:\\.\root\cimv2")
         Set list=wmi.ExecQuery("select * from win32_process where name='aria2c.exe'")
         If list.count=0 Then
         Set objShell = CreateObject("Wscript.Shell")
         objShell.Run "D:\software\Linux\Window\Aria2\aria2c.exe --conf-path=aria2.conf",0
         End If
    c.开机启动
        HideRunAria2.vbs.快捷方式 -> C:\Users\13514\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
        d: && cd D:\software\Linux\Window\Aria2 && nssm install Aria2 && net start Aria2

04.测试
    a.命令行管理
        aria2c http://example.org/mylinux.iso                                   --下载网络文件
        aria2c http://a/f.iso ftp://b/f.iso                                     --下载多个文件
        aria2c -x2 http://a/f.iso                                               --下载时每个host使用两个连接
        aria2c http://example.org/mylinux.torrent                               --使用BitTorrent协议下载
        aria2c 'magnet:?xt=urn:btih:248D0A1CD08284299DE78D5C1ED359BB46717D8C'   --使用磁力链接下载
        aria2c http://example.org/mylinux.metalink                              --Metalink
        aria2c -i uris.txt                                                      --下载text文本文件中的链接
    b.网页管理(Motrix WebExtension、百度网盘助手、BaiduExporter)
        Aria2 for Chrome
        YAAW for Chrome
        http://aria2c.com/
        http://localhost:6800/jsonrpc                                           --AriaNg设置 -> RPC地址

05.Motrix
    a.安装
        https://motrix.app/
    b.插件
        集装箱 -> 右键 -> 使用Motrix下载
    c.进阶设置
        Tracker 服务器 -> 自动更新
        RPC 授权密钥(生成密钥、2ZMAiC7r3gqr、保存)-> Motrix Chrome Extension(2ZMAiC7r3gqr、Set Key)

4.2 seafile

01.直接编译(Seafile会自动配置 MariaDB,Memcached,WebDAV,Ngnix 和开机自动启动脚本)
    a.安装
        yum install wget -y
        wget https://raw.githubusercontent.com/haiwen/seafile-server-installer-cn/master/seafile-server-centos-7-amd64-http
        bash seafile-server-centos-7-amd64-http 6.3.3
    b.运行(配置SERVICE_URL、FILE_SERVER_ROOT)
        Server Address: http:/127.0.0.1
        Seafile Admin:[email protected]
        Admin Password:oDoac0xe

02.Docker
    a.镜像
        yum install -y yum-utils device-mapper-persistent-data lvm2
        yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
        yum install docker-ce -y
    b.配置(右边的端口号一定不要改,左边端口号的含义是Seafile占用的端口,例如修改为1234:80)
        docker run -d --name seafile \
        -e SEAFILE_SERVER_HOSTNAME=seafile.example.com \
        -e [email protected] \
        -e SEAFILE_ADMIN_PASSWORD=password \
        -v /opt/seafile-data:/shared \
        -p 80:80 \
        seafileltd/seafile:latest
    c.运行(配置SERVICE_URL、FILE_SERVER_ROOT)
        systemctl enable docker
        docker update --restart=always seafile

4.3 rssbot

01.Telegram
    a.创建机器人
        @BotFather -> /start -> /newbot -> RssBot、Bilihotbot
    b.创建命令
        rss       - 显示当前订阅的 RSS 列表,加 raw 参数显示链接
        sub       - 订阅一个 RSS: /sub http://example.com/feed.xml
        unsub     - 退订一个 RSS: /unsub http://example.com/feed.xml
        unsubthis - 使用此命令回复想要退订的 RSS 消息即可退订, 不支持 Channel
        export    - 导出为 OPML
    c.机器人对应的Token
        1513156079:AAG6RWpm_YbgaW1Nxq44_ukTwTzilPUf9gc
        1759838027:AAG2GdOOhDMeGsWOZbFnVMz7pycWNs2oo_Y      TELEGRAMBOTTOKEN
    d.Server酱·Turbo版
        SCT158050TEyUSPpKA2iMlpBtQGkVWKygC                  SendKey

02.安装RSSBot
    a.安装,DATAFILE为数据库保存路径,TELEGRAM-BOT-TOKEN对应创建的机器人对应的Token
        apt install unzip
        wget https://github.com/iovxw/rssbot/releases/download/v1.4.3/rssbot-v1.4.3-linux.zip
        unzip rssbot-v1.4.3-linux.zip
        ./rssbot DATAFILE TELEGRAM-BOT-TOKEN
    b.配置
        vi /etc/systemd/system/rssbot.service
        [Unit]
        Description=A RSS Bot
        After=network.target
        Wants=network.target
        [Service]
        Type=simple
        WorkingDirectory=/home/rss
        ExecStart=/home/rss/rssbot DATAFILE TELEGRAM-BOT-TOKEN
        Restart=on-failure
        RestartSec=10
        User=rss
        [Install]
        WantedBy=multi-user.target
    c.执行
        systemctl daemon-reload
        systemctl enable rssbot
        systemctl start rssbot

03.Bot命令示例
    个人订阅:/sub
    频道订阅:/sub @channelname
    查看个人订阅列表:/rss
    查看个人订阅列表并显示订阅链接:/rss raw
    如果需要把机器人加入频道,则机器人的身份需要为管理员

4.4 coolify

01.介绍
    Coolify 开源自托管的 Heroku/Netlify/Vercel 替代方案

02.特点
    自主托管:Coolify 允许部署资源到几乎任何服务器上,包括个人的服务器、树莓派等。只需要 SSH 连接,就能管理自己硬件资源。
    多语言多框架支持:Coolify 与各种编程语言、框架兼容,可以部署和管理各种类型的应用程序。不论静态网站、API 后端服务还是数据库,Coolify 都能提供强大的支持。
    SSL 证书和安全性:Coolify 会自动为自定义域名设置和更新 Let’s Encrypt 证书,确保应用程序的安全和加密连接。用户不需要担心证书繁琐设置和更新,Coolify 会自动处理这些问题。
    监控、通知:Coolify 会监控部署、服务器磁盘使用情况等,并在发生任何问题时通过电子邮件等渠道通知。

03.安装脚本
    curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
    注意:Coolify 支持通过源码及 Docker 等方式部署,上面是来自官方的一键部署脚本,可使用与生产环境。

04.运行要求
    a.支持操作系统
        基于 Debian 的 Linux 发行版(Debian/Ubuntu 等)
        基于 Redhat 的 Linux 发行版(CentOS/Fedora/Red Hat/AlmaLinux/Rocky 等)
        基于 SUSE 的 Linux 发行版(SLES/SUSE/openSUSE 等)
    b.支持系统架构
        AMD64 位架构
        ARM64 位架构
    c.所需的最低服务器配置
        2cpu
        2gb内存
        30+GB的存储空间

4.5 hugging

01.介绍
    a.You can create a repository from the CLI (skip if you created a repo from the website)
        $ pip install huggingface_hub
        # You already have it if you installed transformers or datasets
        $ huggingface-cli login
        # Log in using a token from huggingface.co/settings/tokens
        # Create a model or dataset repo from the CLI if needed
        $ huggingface-cli repo create repo_name --type {model, dataset, space}
    b.Clone your model, dataset or Space locally
        # Make sure you have git-lfs installed
        # (https://git-lfs.github.com)
        $ git lfs install
        $ git clone https://huggingface.co/username/repo_name
    c.Then add, commit and push any file you want, including larges files
        # save files via `.save_pretrained()` or move them here
        $ git add .
        $ git commit -m "commit from $USER"
        $ git push
    d.In most cases, if you're using one of the compatible libraries, your repo will then be accessible from code, through its identifier: username/repo_name
        For example for a transformers model, anyone can load it with:
        tokenizer = AutoTokenizer.from_pretrained("username/repo_name")
        model = AutoModel.from_pretrained("username/repo_name")

4.6 oneinstack

01.安装
    a.使用镜像下载oneinstack文件
        yum -y install wget screen curl python #for CentOS/Redhat
        # apt-get -y install wget screen curl python #for Debian/Ubuntu
        wget http://aliyun-oss.linuxeye.com/oneinstack-full.tar.gz #阿里云经典网络下载
        wget http://mirrors.linuxeye.com/oneinstack-full.tar.gz #包含源码,国内外均可下载
        wget http://mirrors.linuxeye.com/oneinstack.tar.gz #不包含源码,建议仅国外主机下载
    b.解压并安装
        tar xzf oneinstack-full.tar.gz
        cd oneinstack #如果需要修改目录(安装、数据存储、Nginx日志),请修改options.conf文件
        screen -S oneinstack #如果网路出现中断,可以执行命令`screen -R oneinstack`重新连接安装窗口
        ./install.sh #注:请勿sh install.sh或者bash install.sh这样执行
    c.一键配置
        a.更改ssh端口号,建议默认22,过程出现Default可直接回车
            22
        b.是否开启iptables,如果安全组开启,可关闭
            N
        c.是否安装Nginx、Apache、Tomcat(推荐:PHP使用LNMP模式,JAVA使用LNMT模式)
            LNMP:安装Nginx、不安装Apache、Tomcat
                (系统运行php-fpm进程)
            LAMP:安装Apache、不安装Nginx、Tomcat
                (无php-fpm进程,php以模块形式加载在Apache中)
            LNMPA:安装Nginx、Apache,不安装Tomcat
                (静态资源由Nginx处理,PHP由Apache处理,无php-fpm进程,php以模块形式加载在Apache中)
            LNMT:安装Nginx、Tomcat,不安装Apache
                (静态资源由Nginx处理,JAVA由Tomcat处理,可安装PHP,支持多语言环境,同时可运行PHP、JAVA)
        d.是否安装数据库
            Y

02.命令
    ./addons.sh                                                                 --添加附加组件
    ./vhost.sh                                                                  --添加虚拟主机
    ./vhost.sh del                                                              --删除虚拟主机
    ./pureftpd_vhost.sh                                                         --管理FTP账号
    ./backup_setup.sh                                                           --备份
    ./upgrade.sh                                                                --更新
    ./uninstall.sh                                                              --卸载

03.管理服务
    a.Nginx/Tengine/OpenResty
        service nginx {start|stop|status|restart|reload|configtest}
    b.MySQL/MariaDB/Percona
        service mysqld {start|stop|restart|reload|status}
    c.PostgreSQL
        service postgresql {start|stop|restart|status}
    d.MongoDB
        service mongod {start|stop|status|restart|reload}
    e.PHP
        service php-fpm {start|stop|restart|reload|status}
    f.HHVM
        service supervisord {start|stop|status|restart|reload}
    g.Apache
        service httpd {start|restart|stop}
    h.Tomcat
        service tomcat {start|stop|status|restart}
    i.Pure-Ftpd:
        service pureftpd {start|stop|restart|status}
    j.Redis
        service redis-server {start|stop|status|restart|reload}
    k.Memcached
        service memcached {start|stop|status|restart|reload}

04.ftp权限问题
    a.报错
        创建ftp账户后,远程连接出现550错误,提示没有权限。
    b.解决:网站根目录权限遵循:文件644、文件夹755、权限用户和用户组www
        chown -R www.www /data/wwwroot/
        find /data/wwwroot/ -type d -exec chmod 755 {} \;
        find /data/wwwroot/ -type f -exec chmod 644 {} \;

05.LNMT模式部署JAVA应用
    a.采用lnmt模式,即安装nginx、mysql、tomcat
        默认Nginx处理静态资源,Tomcat处理动态资源
    b.域名
        默认(未绑定域名)对应网站根目录/data/wwwroot/default(不是webapps),
        部署代码时建议将war包解压(比如example.war,解压命令:jar xf example.war ,注意权限必须为www),将其中代码放到对应网站根目录:
        如果上传代码之后目录结构为:/data/wwwroot/default/WEB-INF,访问地址为:http://IP
        如果上传代码之后目录结构为:/data/wwwroot/default/example/WEB-INF,访问网站地址为:http://IP/example
    c.war包
        war包也可以不解压即上传到对应网站根目录,但必须注意访问路径和静态资源目录问题。
        如果访问网站时,静态资源加载不了,可能是原因是做了动静分离静态资源直接有nginx处理,
        请确认nginx是否能找到相关静态资源(nginx网站根目录:/data/wwwroot/default)
    d.虚拟主机
        如果vhost.sh绑定了域名,如www.example.com,工具会自动生成对应根目录:/data/wwwroot/www.example.com ,请将代码放入此目录

06.切换php版本
    ./uninstall.sh php  #卸载
    ./install.sh #php选择y,其余选择n,即可

07.配置MySQL远程连接
    a.开启iptables中3306端口
        a.Centos7
            iptables -I INPUT 4 -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT
            service iptables save #保存iptables规则
        b.Ubuntu/Debian
            iptables -I INPUT 4 -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT
            iptables-save > /etc/iptables.up.rules #保存iptables规则
    b.授权数据库
        远程连接新建一个帐号(帐号名不能为root)
        如:添加一个用户名为db_user,密码为db_pass,授权为%,对db_name数据库所有权限,命令如下:
        # mysql -uroot -p
        MySQL [(none)]> grant all privileges on db_name.* to db_user@’%’ identified by ‘db_pass’;
        MySQL [(none)]> flush privileges;
        MySQL [(none)]> exit;

4.7 vaultwarden

01.VaultWarden
    a.安装docker
        yum update -y && yum install docker -y && systemctl start docker && systemctl enable docker && service docker status
    b.安装docker-compose
        curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose
    c.配置docker-compose.yml
        cd / && mkdir www && cd www && mkdir vaultwarden && cd /www/vaultwarden && vi docker-compose.yml
        version: "3"

        services:
          vaultwarden:
            image: vaultwarden/server:latest
            container_name: vaultwarden
            restart: always
            ports:
                - "127.0.0.1:6666:80" #将宿主机6666端口映射到docker的80端口
                - "127.0.0.1:3012:3012"
            volumes:
              - ./vw-data:/data
            environment:
              DOMAIN: 'https://myslayers.cn/'
              WEBSOCKET_ENABLED: "true" #是否开启WebSocket
              SIGNUPS_ALLOWED: "true"   #是否开启注册,自用的话自己搭建好注册后改成false
              WEB_VAULT_ENABLED: "true" #是否开启Web客户端
              #ADMIN_TOKEN: "xxxxxx"         #后台登陆密码,建议openssl rand -base64 48 生成ADMIN_TOKEN确保安全
    d.启动docker-compose
        cd /www/vaultwarden
        docker-compose up -d                                                    --启动服务
        docker-compose down                                                     --关闭服务
        docker-compose restart                                                  --重启服务
        docker-compose down && docker pull vaultwarden/server:latest            --更新镜像,需要先停止服务
        docker ps -a                                                            --查看运行
        docker rm -f 80576e5ea74a                                               --移除容器
        docker images                                                           --查看镜像
        docker rmi -f d55229deb03e                                              --移除镜像
        docker start 80576e5ea74a                                               --启动容器
        docker stop 80576e5ea74a                                                --停止容器
        docker restart 80576e5ea74a                                             --重启容器
        docker rm 80576e5ea74a                                                  --移除容器
        docker logs 80576e5ea74a                                                --查看日志
        docker exec -it vaultwarden /bin/bash                                   --内部环境
    e.数据备份
        yum install sqlite-devel -y && sqlite3 -version && sqlite3 /www/vaultwarden/vm-data/d.sqlite3 ".backup '/root/db-$(date '+%Y%m%d-%H%M').sqlite3'"

02.Let’s Encrypt
    a.安装
        curl https://get.acme.sh | sh && chmod -R 777 /root/.acme.sh/
    b.自动续签,开启自动同步更新
        cd /root/.acme.sh && alias acme.sh=~/.acme.sh/acme.sh && echo 'alias acme.sh=~/.acme.sh/acme.sh' >>/etc/profile
        00 00 * * * root /root/.acme.sh/acme.sh --cron --home /root/.acme.sh &>/var/log/acme.sh.logs
        /root/.acme.sh/acme.sh --upgrade --auto-upgrade
    c.申请证书
        export xxxxx="xxxxxxxxxxxxxxxxxxxxxxxxxx"
        export xxxxx="xxxxxxxxxxxxxxxxxxxxxxxxxxx"
        acme.sh --issue --dns dns_ali -d myslayers.cn -d www.myslayers.cn
    d.申请证书(Nginx创建ssl文件夹,生成dhparam.pem文件,acme将证书克隆到ssl文件夹)
        yum update -y && yum install -y epel-release && yum install -y nginx && cat /etc/nginx/nginx.conf && mkdir /etc/nginx/ssl && openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048 && acme.sh --installcert -d myslayers.cn --key-file /etc/nginx/ssl/myslayers.cn.key --fullchain-file /etc/nginx/ssl/fullchain.cer --reloadcmd  "service nginx force-reload"

03.Nginx
    a.配置(cat /etc/nginx/nginx.conf)
        server {
            listen       443 ssl http2 default_server;
            listen       [::]:443 ssl http2 default_server;
            server_name  myslayers.cn www.myslayers.cn;
            root         /usr/share/nginx/html;

            ssl_certificate "/etc/nginx/ssl/fullchain.cer";
            ssl_certificate_key "/etc/nginx/ssl/myslayers.cn.key";

            ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
            ssl_prefer_server_ciphers on;
            ssl_dhparam /etc/nginx/ssl/dhparam.pem;

            # Load configuration files for the default server block.
            include /etc/nginx/default.d/*.conf;

            location / {
                proxy_pass http://127.0.0.1:6666;
                proxy_http_version    1.1;
                proxy_cache_bypass    $http_upgrade;
                proxy_set_header Upgrade            $http_upgrade;
                proxy_set_header Connection         "upgrade";
                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_set_header X-Forwarded-Host   $host;
                proxy_set_header X-Forwarded-Port   $server_port;
            }

            location /notifications/hub {
                proxy_pass http://127.0.0.1:3012;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
            }

            location /notifications/hub/negotiate {
                proxy_pass http://127.0.0.1:6666;
            }

            location /admin {
                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:6666;
            }

            error_page 404 /404.html;
            location = /404.html {
            }

            error_page 500 502 503 504 /50x.html;
            location = /50x.html {
            }
        }
    b.启动
        nginx                                                           --打开服务
        nginx -v                                                        --查看版本
        nginx -t                                                        --检查配置
        nginx -p prefix                                                 --默认前缀(/usr/share/nginx/)
        nginx -c filename                                               --默认配置(/etc/nginx/nginx.conf)
        nginx -s reopen                                                 --主进程发送信号(重启服务)
        nginx -s reload                                                 --主进程发送信号(重载配置)
        nginx -s stop                                                   --主进程发送信号(强制停止)
        nginx -s quit                                                   --主进程发送信号(优雅退出)
        ss -ntlp| grep -i nginx                                         --查看软件是否正常运行
        systemctl enable | start | stop | restart nginx                 --systemctl命令

04.启动
    a.访问
        https://myslayers.cn/
    b.二次验证
        https://myslayers.cn/admin -> SMTP Email Settings、Email 2FA Settings
        Enabled                         Default: true(勾选)
        Host                            smtp.163.com(填写)
        Enable Secure SMTP              Default: true(勾选)
        Force TLS                       Default: false(勾选)
        Port                            465(填写)
        From Address                    [email protected](填写)
        From Name                       Vaultwarden(填写)
        Username                        [email protected](填写)
        Password                        RBMWIHQZJTMYOLNG
        SMTP Auth mechanism             无
        SMTP connection timeout         15
        Server name sent during HELO    无
        Enable SMTP debugging (Know the risks!)     无
        Accept Invalid Certs (Know the risks!)      无
        Accept Invalid Hostnames (Know the risks!)  无
        Test SMTP                                   [email protected] -> Send test mail

4.8 lookingglass

01.利用Oneinstack安装nginx、php7.2
    wget -c http://mirrors.linuxeye.com/oneinstack-full.tar.gz && tar xzf oneinstack-full.tar.gz && ./oneinstack/install.sh --nginx_option 1 --php_option 7

02.由于LookingGlass需要PHP中某些禁用的函数,因此需要配置PHP
    vi /usr/local/php/etc/php.ini
    :set nu -> 311行 -> disable_functions代表禁用函数 -> 删除proc开头的函数,以及函数后面的逗号
    service php-fpm restart

03.安装LookingGlass
    a.下载
        wget https://github.com/ILLKX/LookingGlass/archive/master.zip && unzip master.zip
    b.运行脚本
        rm -f /data/wwwroot/default/index.html
        mv LookingGlass-master/* /data/wwwroot/default/
        bash /data/wwwroot/default/LookingGlass/configure.sh
    c.填写规范
        如果项目放于Nginx目录下时,http://xxx.com(最后不要加"/")
        如果项目放于Nginx目录下的某个文件夹时,http://xxx.com/xxx(最后不要加"/")
        Enter your website name (Header/Logo) []: SpeedTest
        Enter the public URL to this LG (including http://) []: http://halavah.buzz
        Enter the servers location []: Tokyo, Japan
        Enter the test IPv4 address []: 202.182.112.34
        Enter the test IPv6 address (Re-enter everytime this script is run) []:
        Enter the size of test files in MB (Example: 25 50MB 100) []: 100MB
        Do you wish to enable rate limiting of network commands? (y/n): n
        Enter the username of your webserver (E.g. www-data): root
        Enter the user group of your webserver (E.g. www-data): root

04.测试
    http://halavah.buzz

5 blogger

5.1 hexo

00.汇总
    a.Gitee Pages
        仅支持 Jekyll、Hugo、Hexo编译静态资源
        -----------------------------------------------------------------------------------------------------
        如何创建一个首页访问地址不带二级目录的 pages,如ipvb.gitee.io?
        答:如果你想你的 pages 首页访问地址不带二级目录,如ipvb.gitee.io,你需要建立一个与自己个性地址同名的仓库,
        如 https://gitee.com/ipvb 这个用户,想要创建一个自己的站点,但不想以子目录的方式访问,
        想以ipvb.gitee.io直接访问,那么他就可以创建一个名字为ipvb的仓库 https://gitee.com/ipvb/ipvb 部署完成后,
        就可以以 https://ipvb.gitee.io 进行访问了。
    b.私有仓库支持性
        Vercel Pages支持连接私有仓库
        Netlify Pages支持连接私有仓库
        Cloudflare Pages不能连接私有仓库
        GitHub的私有仓库开启GitHub Pages需要升级为Pro用户($4/mon)
    c.gihtub page
        a.前提
            必须仓库为公有public
        b.不使用Action
            settings -> pages -> Build and deployment -> Deploy from a branch -> master、/docs
        c.使用Action
            .github/workflows/deploy.yml,该文件指定构建目录,如public;指定构建分支,如master
            settings -> pages -> Build and deployment -> GitHub Actions
            GitHub Actions -> 查看构建情况

01.Hexo托管
    a.托管方式(Gitee)-> 手动更新
        名称:myslayers
        描述:勿因喜而轻诺!
        插件:d: && cd D:\software_ware\workspace_blog && cnpm install hexo-deployer-git --save
        邮箱:git config --global user.email "[email protected]"  && git config --global user.name "myslayers"
        开启Gitee Pages服务:Branch(master)、整个目录
        站点_config.yml文件:
            title: 个人博客
            subtitle: ''
            description: '勿因喜而轻诺'
            keywords:
            author: myslayers
            language: zh-CN
            timezone: 'Asia/Shanghai'
            ----------------------------------------------------------------------
            url: https://myslayers.gitee.io/
            root: /
            permalink: :title.html
            ----------------------------------------------------------------------
            public_dir: public
            ----------------------------------------------------------------------
            theme: keep
            ----------------------------------------------------------------------
            deploy:
                type: 'git'
                repo: 'https://gitee.com/myslayers/myslayers.git'
                branch: master
                message:
    b.托管方式(Github)-> 自动更新
        名称:myslayers.github.io
        描述:勿因喜而轻诺!
        插件:d: && cd D:\software_ware\workspace_blog && cnpm install hexo-deployer-git --save
        邮箱:git config --global user.email "[email protected]"  && git config --global user.name "myslayers"
        开启Github Pages服务:Branch(master)、docs目录
        站点_config.yml文件:
            title: Halavah's Blog
            subtitle: ''
            description: '勿因喜而轻诺!'
            keywords:
            author: Halavah
            language: zh-CN
            timezone: 'Asia/Shanghai'
            ----------------------------------------------------------------------
            url: https://halavah.github.io/halavah
            root: /halavah/
            permalink: :title.html
            ----------------------------------------------------------------------
            public_dir: docs
            ----------------------------------------------------------------------
            theme: Chic
            ----------------------------------------------------------------------
            deploy:
                type: 'git'
                repo: 'https://github.com/halavah/halavah.git'
                branch: master
                message:
    c.自定义域名(Github)
        a.Cloudflare
            类型      名称          内容                  TTL      代理状态
            A         @            185.199.108.153      自动      仅限 DNS
            A         @            185.199.109.153      自动      仅限 DNS
            A         @            185.199.110.153      自动      仅限 DNS
            A         @            185.199.111.153      自动      仅限 DNS
            CNAME     www          halavah.github.io    自动      仅限 DNS
        b.Settings
            master  /docs
            halavah.tk
            Enforce HTTPS   Please allow 24 hours for this process to complete
        c._config.yml
            url: https://halavah.tk
            root: /
        d.防止删除CNAME文件
            将CNAME文件放到source文件夹下,那么在hexo generate在编译时,也会将CNAME编译进docs文件夹中
        e.docs放CNAME
            https://halavah.github.io/halavah

02.Hexo部署
    a.部署方式(git push)(每次提交需要add、commit、ppush,同时需要手动输入邮箱、密码)
        a.创建本地仓库、远程仓库
            git init                                        --创建本地仓库
            [email protected]:myslayers/myslayers.github.io.git--创建远程仓库
        b.关联本地仓库与远程仓库地址
            git remote add origin https://github.com/myslayers/myslayers.github.io.git
        c.保留线上的readme文件(如果本地分支版本大于远程版本,则强制提交)
            git pull origin master
        d.关联本地分支与远程分支地址
            git add .
            git commit -m "my first commit"
            git push origin master -f                       --强制提交:舍弃线上文件进行强制推送(不推荐)
            git push origin master                          --正常提交:保留线上的readme文件
    b.部署方式(hexo deploy)
        hexo clean && hexo generate && hexo deploy
        hexo clean && hexo generate && hexo s -p 9999

03.Hexo使用(NexT、Keep、目前Chic、yilia、Concise、Fluid、Flui、Inside)(Typecho-handsome)(Typecho)
    a.环境(Nodejs、Git、hexo-cli)(在Disk中默认Nodejs编译cnpm、hexo-cli,默认Git,因此可以忽略此步骤)
        D:\software\Linux\Window\Git
        D:\software\JavaScript\Nodejs
        npm install -g cnpm --registry=https://registry.npm.taobao.org && cnpm install -g hexo-cli
    b.安装
        d: && mkdir D:\software_ware\workspace_hexo                                 --创建blog文件夹
        d: && cd D:\software_ware\workspace_hexo && hexo init                       --初始化hexo框架
    c.命令
        hexo init [folder]                                  --初始化命令,[folder]表示初始化的文件夹
        hexo new [layout] <title>                           --新建文章或页面,[layout]表示页面, <title>表示标题
        hexo s -p 9999                                      --本地查看网站
        hexo generate                                       --生成网站静态文件,网页默认保存在“public文件夹”
        hexo clean                                          --清空“public文件夹的内容”
        hexo deploy                                         --部署网站,将“public文件夹的内容”进行部署
        hexo version                                        --当前hexo版本号
    d.启动
        git clone [email protected]:halavah/PicGo.git workspace_hexo   --第1步:克隆仓库
        git pull --rebase                                           --第2步:更新仓库
        hexo clean && hexo generate && hexo s -p 9999               --第3步:查看本地(check.bat)(重新生成docs)
        hexo clean && hexo generate && hexo deploy                  --第4步_无:远程部署(deploy.bat)(删除配置)
        git add . && git commit -m 'v1.0' && git push               --第5步:手动提交
        git tag v1.0 && git push origin v1.0                        --第6步:手动提交
    e.Keep主题
        a.功能
            Post_top(文章顶置)
            base_info(网站名称、作者昵称、网站域名)
            style(网站主题色、文章内容页的图片排列位置、左侧TOC目录结构模块的宽度、设置鼠标悬浮时的样式、首屏模块)
            social_contact(社交网络链接,仅在首屏下生效)
            menu(导航菜单)
            rss(订阅)
            comment(Gitalk评论)
            website_count(计数项)
            local_search(本地搜索)
            post_wordcount(文章字数统计和阅读时长统计功能)
            home_article(首页文章块底部的显示设置)
            code_copy(代码复制)
            side_tools(右下角工具)
            back2top(一键快速 回到顶部和到达底部)
            toc(查看文章结构和跳转)
            copyright_info(文章内容页的版权信息模块)
            cdn(开启资源CDN加速)
            footer(网站最底部的信息展示设置)
            MathJax(数学公式)
            lazyload(懒加载)
            pjax(Ajax部分更新)
        b.写作
            ---
            title: 第一篇文章
            date: 2020-04-07 21:55:14
            tags: 标签一
            categories: 分类一
            comment: true                                       --评论
            mathjax: true                                       --MathJax数学公式
            sticky: 9999                                        --sticky值越大,顶置的文章越靠前
            ---
    f.Chic主题
        a.安装
            cd your-blog/themes
            git clone https://github.com/Siricee/hexo-theme-Chic.git Chic
            hexo new page tag
            hexo new page category
            hexo new page about
        b.写作
            ---
            title: 第一篇文章
            date: 2020-04-07 21:55:14
            tags: 标签一
            categories: 分类一
            mathjax: true                                       --MathJax数学公式
            ---

5.2 hugo

01.命令(PaperMod、Even、MemE、LoveIt)
    hugo new site myslayers -f yml                      --初始化,文件夹myslayers,站点http://myslayers.com
    hugo new --kind post archetypes/post.md             --归档
    hugo new --kind post tags/post.md                   --标签
    hugo server -D                                      --本地查看网站(http://localhost:1313/)

02.主题
    https://themes.gohugo.io/hugo-papermod/
    https://github.com/adityatelange/hugo-PaperMod

03.发布
    a.第一次发布
        cd public
        git init
        git remote add origin https://github.com/Showfom/showfom.github.io.git
        git add .
        git commit -m "first commit"
        git push -u origin master
    b.后续发布
        cd public
        git add .
        git status
        git commit -m "add blog post"
        git push

5.3 picgo

01.GitHub
    仓库名     halavah/PicGo
    分支名     master
    Token     5ef48dd7ead044453f7606442ce8d04ccc365c23
    存储路径   avatar/      background/
    自定义域名 https://halavah.buzz

02.默认路径
    https://raw.githubusercontent.com/[username]/[仓库名]/[分支名]/[文件路径]
    https://raw.githubusercontent.com/halavah/PinGo/master/background/22.jpg

03.加速路径
    https://cdn.jsdelivr.net/gh/[username]/[仓库名]@[分支名]/[文件路径]
    https://cdn.jsdelivr.net/gh/halavah/PinGo@master/background/22.jpg

04.域名路径
    https://halavah.buzz/[文件路径]
    https://halavah.buzz/background/22.jpg

5.4 quartz1

00.起源
    a.分类1
        TroyeKK小站
        TroyeKK World
    b.分类2
        TroyeHub、TroyeVibe、KKZone、TroyeNest、KKSpot、TroyeWorld、TroyeBox、KKLink、TroyeX、TroyeHQ
    c.World换个词
        Realm、Horizon、Sphere、Domain、Territory、Kingdom、Vista、Universe、Oasis、Empire
    d.版本说明
        quartz-v0_没有防护码
        quartz-v1_仅适配域名_如vercel_session:采用sessionStorage来实现,可以通过绕开验证,通过【会话存储】使用【verified】设置为【true】
        quartz-v1_仅适配域名+仓库_如github_session:采用sessionStorage来实现,可以通过绕开验证,通过【会话存储】使用【verified】设置为【true】
        quartz-v2_仅适配域名_如vercel_token:采用sessionStorage来实现,但是token分为3个部分,localStorage存储一部分、sessionStorage 存储另一部分、cookie存储第三部分,但是【ChatGPT】可推测出密码
        quartz-v3_仅适配域名_如vercel_不可逆加密:采用sessionStorage来实现,但是token分为3个部分,localStorage存储一部分、sessionStorage 存储另一部分、cookie存储第三部分,但是【不可逆加密】,【ChatGPT】不能推测出密码
    e.启动
        $ npx quartz build --verbose ,构建到public,但不运行
        $ npx quartz build --serve,默认监听在 8080 端口,支持热重载,但是不支持网络文件系统的热重载。
    f.硬链接
        mklink /d "D:\software_xare\workspace_open\quartz-pro_screen\content" "D:\software_ware\04.Directory04"
        mklink /d "D:\software_ware\99.Directory01\content" "D:\software_ware\01.Directory01"
        mklink /d "D:\software_ware\99.Directory02\content" "D:\software_ware\02.Directory02"
        mklink /d "D:\software_ware\99.Directory03\content" "D:\software_ware\03.Directory03"
        mklink /d "D:\software_ware\99.Directory04\content" "D:\software_ware\04.Directory04"
        mklink /d "D:\software_ware\99.Directory05\content" "D:\software_ware\05.Directory05"
    g.git检查Aliyun Key
        搜索accessKey、secretKey、accessKeyId、accessKeySecret
        00.project1
        02.backend2
        06.cangqiong
        07.jiankang

01.使用
    a.下载
        https://github.com/jackyzha0/quartz
    b.安装和初始化
        [[quartz]] 支持利用 nodejs 直接部署,以及利用 docker 部署。
        # nodejs 部署和初始化
        $ git clone https://github.com/jackyzha0/quartz.git
        $ cd quartz
        $ npm i
        $ npx quartz create
        $ npx quartz build --serve
        ---------------------------------------------------------------------------------------------------------
        # docker部署
        $ git clone https://github.com/jackyzha0/quartz.git
        $ docker run --rm -itp 8080:8080 $(docker build -q .)
    c.配置quartz.config.ts 和quartz.layout.ts文件
        quartz.config.ts 文件主要是配置网站信息,主题自定义以及插件系统,默认基本不用动,只需要更改一下网站信息即可,具体参考Configuration (jzhao.xyz)。
        quartz.layout.ts 文件是配置布局,默认有 3 个布局样式可以自定义:
            sharedPageComponents :这个是配置分享页面内容的,主要是配置页脚信息。
            defaultContentPageLayout:这个是配置文档页面布局的,注意主页也属于文档。
            defaultListPageLayout :这个是配置标签页和文件夹页面布局的。
            布局参考:Layout (jzhao.xyz)
            组件参考:Components (jzhao.xyz)
    d.生成和预览
        $ npx quartz build --verbose ,构建到public,但不运行
        $ npx quartz build --serve,默认监听在 8080 端口,支持热重载,但是不支持网络文件系统的热重载。
    e.同步内容
        文档内容全部在content目录,该文件夹下应该有index.md 作为主页,content 中的文档结构会默认的渲染成路径。
    f.启动脚本:start.bat
        @echo off

        :: Navigate to the directory where the script is located
        cd /d "%~dp0"

        :: Delete all contents in the "public" folder but keep the folder itself
        if exist "public" (
            echo Deleting all contents in the "public" folder...
            del /q /f "public\*.*"
            for /d i"
            echo Deletion completed.
        ) else (
            echo "The public folder does not exist."
        )

        npx quartz build --serve
    g.命令说明
        npx quartz build --serve
        其中大多数都有合理的默认值,但如果您有自定义设置,则可以覆盖它们:
        -d或--directory:内容文件夹。这通常只是content
        -v或者--verbose:打印额外的日志信息
        -o或--output:输出文件夹。这通常只是public
        --serve:运行本地热重载服务器来预览你的 Quartz
        --port:在哪个端口上运行本地预览服务器
        --concurrency:解析笔记需要使用多少个线程

02.配置样式
    a.根目录
        a.网址:quartz.config.ts
            a.11行
                pageTitle: "TroyeKK小站",
                pageTitle: "TroyeKK World",
                pageTitle: "Halavah's Blog",
            b.19行
                baseUrl: "halavah.github.io",
                ignorePatterns: ["private", "templates", ".obsidian", ".obsidian_android", ".trash", "_assets"],
            c.20241220
                import { QuartzConfig } from "./quartz/cfg"
                import * as Plugin from "./quartz/plugins"

                /**
                 * Quartz 4.0 Configuration
                 *
                 * See https://quartz.jzhao.xyz/configuration for more information.
                 */
                const config: QuartzConfig = {
                  configuration: {
                    pageTitle: "TroyeKK World",
                    pageTitleSuffix: "",
                    enableSPA: true,
                    enablePopovers: true,
                    analytics: {
                      provider: "plausible",
                    },
                    locale: "en-US",
                    baseUrl: "halavah.github.io",
                    ignorePatterns: ["private", "templates", ".obsidian", ".obsidian_android", ".trash", "_assets"],
                    defaultDateType: "created",
                    generateSocialImages: false,
                    theme: {
                      fontOrigin: "googleFonts",
                      cdnCaching: true,
                      typography: {
                        header: "Schibsted Grotesk",
                        body: "Source Sans Pro",
                        code: "IBM Plex Mono",
                      },
                      colors: {
                        lightMode: {
                          light: "#faf8f8",
                          lightgray: "#e5e5e5",
                          gray: "#b8b8b8",
                          darkgray: "#4e4e4e",
                          dark: "#2b2b2b",
                          secondary: "#284b63",
                          tertiary: "#84a59d",
                          highlight: "rgba(143, 159, 169, 0.15)",
                          textHighlight: "#fff23688",
                        },
                        darkMode: {
                          light: "#161618",
                          lightgray: "#393639",
                          gray: "#646464",
                          darkgray: "#d4d4d4",
                          dark: "#ebebec",
                          secondary: "#7b97aa",
                          tertiary: "#84a59d",
                          highlight: "rgba(143, 159, 169, 0.15)",
                          textHighlight: "#b3aa0288",
                        },
                      },
                    },
                  },
                  plugins: {
                    transformers: [
                      Plugin.FrontMatter(),
                      Plugin.CreatedModifiedDate({
                        priority: ["frontmatter", "filesystem"],
                      }),
                      Plugin.SyntaxHighlighting({
                        theme: {
                          light: "github-light",
                          dark: "github-dark",
                        },
                        keepBackground: false,
                      }),
                      Plugin.ObsidianFlavoredMarkdown({ enableInHtmlEmbed: false }),
                      Plugin.GitHubFlavoredMarkdown(),
                      Plugin.TableOfContents(),
                      Plugin.CrawlLinks({ markdownLinkResolution: "shortest" }),
                      Plugin.Description(),
                      Plugin.Latex({ renderEngine: "katex" }),
                    ],
                    filters: [Plugin.RemoveDrafts()],
                    emitters: [
                      Plugin.AliasRedirects(),
                      Plugin.ComponentResources(),
                      Plugin.ContentPage(),
                      Plugin.FolderPage(),
                      Plugin.TagPage(),
                      Plugin.ContentIndex({
                        enableSiteMap: true,
                        enableRSS: true,
                      }),
                      Plugin.Assets(),
                      Plugin.Static(),
                      Plugin.NotFoundPage(),
                    ],
                  },
                }

                export default confige
        b.友链:quartz.layout.ts
            a.11行
                // GitHub: "https://github.com/halavah",
                // BiliBili: "https://space.bilibili.com/71393128/",
            b.32行
                right: [
                  // Component.Graph(),
                  Component.DesktopOnly(Component.TableOfContents()),
                  // Component.Backlinks(),
                ],
            c.20241220
                import { PageLayout, SharedLayout } from "./quartz/cfg"
                import * as Component from "./quartz/components"

                // components shared across all pages
                export const sharedPageComponents: SharedLayout = {
                  head: Component.Head(),
                  header: [],
                  afterBody: [],
                  footer: Component.Footer({
                    links: {
                      // GitHub: "https://github.com/halavah",
                      // BiliBili: "https://space.bilibili.com/71393128/",
                    },
                  }),
                }

                // components for pages that display a single page (e.g. a single note)
                export const defaultContentPageLayout: PageLayout = {
                  beforeBody: [
                    Component.Breadcrumbs(),
                    Component.ArticleTitle(),
                    Component.ContentMeta(),
                    Component.TagList(),
                    Component.MobileOnly(Component.TableOfContents()),
                  ],
                  left: [
                    Component.PageTitle(),
                    Component.MobileOnly(Component.Spacer()),
                    Component.Search(),
                    Component.DesktopOnly(Component.Explorer()),
                    Component.DesktopOnly(Component.About()),
                    Component.MobileOnly(Component.Darkmode()),
                  ],
                  right: [
                    Component.Graph(),
                    Component.DesktopOnly(Component.TableOfContents()),
                    // Component.Backlinks(),
                  ],
                }

                // components for pages that display lists of pages  (e.g. tags or folders)
                export const defaultListPageLayout: PageLayout = {
                  beforeBody: [
                    Component.Breadcrumbs(),
                    Component.ArticleTitle(),
                    Component.ContentMeta(),
                  ],
                  left: [
                    Component.PageTitle(),
                    Component.MobileOnly(Component.Spacer()),
                    Component.Search(),
                    Component.DesktopOnly(Component.Explorer()),
                    Component.DesktopOnly(Component.About()),
                    Component.MobileOnly(Component.Darkmode()),
                  ],
                  right: [

                  ],
                }
    b.css
        a.基础CSS:quartz/styles/base.scss
            a.181行
                & .sidebar {
                  gap: 2rem;
                  top: 0;
                  box-sizing: border-box;
                  padding: $topSpacing 2rem 2rem 2rem;
                  display: flex;
                  height: 100vh;
                  position: sticky;
                }
            b.546行
                ul.overflow,
                ol.overflow {
                  max-height: 100%;
                  //overflow-y: auto;

                  // clearfix
                  content: "";
                  clear: both;

                  & > li:last-of-type {
                    margin-bottom: 30px;
                  }
                  /*&:after {
                    pointer-events: none;
                    content: "";
                    width: 100%;
                    height: 50px;
                    position: absolute;
                    left: 0;
                    bottom: 0;
                    opacity: 1;
                    transition: opacity 0.3s ease;
                    background: linear-gradient(transparent 0px, var(--light));
                  }*/
                }
            c.229行
                & .page-header,
                & .page-footer {
                  margin-top: 1rem;
                }
        b.变量CSS:quartz/styles/variables.scss
            a.18行
                $sidePanelWidth: 280px; //380px;
            b.19行
                $topSpacing: 1rem;
            c.21行
                $semiBoldWeight: 470;
    c.TroyeKK小站
        a.quartz/components/PageTitle.tsx,16行
            PageTitle.css = `
            .page-title {
              font-size: 1.75rem;
              margin: 0;
            }
            `
    d.搜索
        a.quartz/components/Search.tsx,23行
            前
            <p>{i18n(cfg.locale).components.search.title}</p>
            -------------------------------------------------------------------------------------------------
            后
            <p>搜索</p>
    e.大纲
        a.quartz/components/TableOfContents.tsx,36行
            前
            <h3>{i18n(cfg.locale).components.tableOfContents.title}</h3>
            -------------------------------------------------------------------------------------------------
            后
            <h3>大纲</h3>
        b.quartz/components/styles/toc.scss,3行
            前
            .toc {
              display: flex;
              flex-direction: column;

              &.desktop-only {
                max-height: 40%;
              }
            }
            -------------------------------------------------------------------------------------------------
            后
            .toc {
              display: flex;
              flex-direction: column;

              &.desktop-only {
                max-height: 50%;
              }
            }
        c.quartz/components/styles/toc.scss,45行
            前:大纲滚动条
            //#toc-content {
            //  list-style: none;
            //  overflow: hidden;
            //  overflow-y: auto;
            //  max-height: 100%;
            //  transition:
            //    max-height 0.35s ease,
            //    visibility 0s linear 0s;
            //  position: relative;
            //  visibility: visible;
            //
            //  &.collapsed {
            //    max-height: 0;
            //    transition:
            //      max-height 0.35s ease,
            //      visibility 0s linear 0.35s;
            //    visibility: hidden;
            //  }
            //
            //  &.collapsed > .overflow::after {
            //    opacity: 0;
            //  }
            //
            //  & ul {
            //    list-style: none;
            //    margin: 0.5rem 0;
            //    padding: 0;
            //    & > li > a {
            //      color: var(--dark);
            //      opacity: 0.35;
            //      transition:
            //        0.5s ease opacity,
            //        0.3s ease color;
            //      &.in-view {
            //        opacity: 0.75;
            //      }
            //    }
            //  }
            //  > ul.overflow {
            //    max-height: none;
            //    width: 100%;
            //  }
            //
            //  @for $i from 0 through 6 {
            //    & .depth-#{$i} {
            //      padding-left: calc(1rem * #{$i});
            //    }
            //  }
            //}
            -------------------------------------------------------------------------------------------------
            后:大纲滚动条
            #toc-content {
              list-style: none;
              overflow: hidden;
              overflow-y: auto;
              max-height: 100%;
              transition:
                  max-height 0.35s ease,
                  visibility 0s linear 0s;
              position: relative;
              visibility: visible;

              // 自定义滚动条样式
              &::-webkit-scrollbar {
                width: 6px; // 滚动条宽度
                height: 6px; // 滚动条高度(对于横向滚动条)
              }

              &::-webkit-scrollbar-thumb {
                background: var(--secondary); // 滚动条滑块颜色
                border-radius: 3px; // 圆角滑块
              }

              &::-webkit-scrollbar-thumb:hover {
                background: var(--tertiary); // 滑块悬停时颜色
              }

              &::-webkit-scrollbar-track {
                background: var(--light); // 滚动条轨道颜色
                border-radius: 3px; // 圆角轨道
              }

              &.collapsed {
                max-height: 0;
                transition:
                    max-height 0.35s ease,
                    visibility 0s linear 0.35s;
                visibility: hidden;
              }

              &.collapsed > .overflow::after {
                opacity: 0;
              }

              & ul {
                list-style: none;
                margin: 0.5rem 0;
                padding: 0;
                & > li > a {
                  color: var(--dark);
                  //opacity: 0.35;
                  transition:
                      0.5s ease opacity,
                      0.3s ease color;
                  &.in-view {
                    opacity: 0.75;
                  }
                }
              }
              > ul.overflow {
                max-height: none;
                width: 100%;
              }

              @for $i from 0 through 6 {
                & .depth-#{$i} {
                  padding-left: calc(1rem * #{$i});
                }
              }
            }
    f.目录
        a.quartz/components/Explorer.tsx,99行
            前
            <h2>{opts.title ?? i18n(cfg.locale).components.explorer.title}</h2>
            -------------------------------------------------------------------------------------------------
            后
            <h2>目录</h2>
        b.quartz/components/styles/explorer.scss,67行
            前
            //#explorer-content {
            //  list-style: none;
            //  overflow: hidden;
            //  overflow-y: auto;
            //  max-height: 100%;
            //  transition:
            //    max-height 0.35s ease,
            //    visibility 0s linear 0s;
            //  margin-top: 0.5rem;
            //  visibility: visible;
            //
            //  &.collapsed {
            //    max-height: 0;
            //    transition:
            //      max-height 0.35s ease,
            //      visibility 0s linear 0.35s;
            //    visibility: hidden;
            //  }
            //
            //  & ul {
            //    list-style: none;
            //    margin: 0.08rem 0;
            //    padding: 0;
            //    transition:
            //      max-height 0.35s ease,
            //      transform 0.35s ease,
            //      opacity 0.2s ease;
            //    & li > a {
            //      color: var(--dark);
            //      opacity: 0.75;
            //      pointer-events: all;
            //    }
            //  }
            //  > #explorer-ul {
            //    max-height: none;
            //  }
            //}
            ---------------------------------------------------------------------------------------------
            后
            #explorer-content {
              list-style: none;
              overflow: hidden;
              overflow-y: auto;
              max-height: 100%;
              transition:
                  max-height 0.35s ease,
                  visibility 0s linear 0s;
              margin-top: 0.5rem;
              visibility: visible;

              /* 自定义滚动条样式 */
              &::-webkit-scrollbar {
                width: 6px; /* 滚动条宽度 */
                height: 6px; /* 滚动条高度(对于横向滚动条) */
              }

              &::-webkit-scrollbar-thumb {
                background: var(--secondary); /* 滚动条滑块颜色 */
                border-radius: 3px; /* 圆角滑块 */
              }

              &::-webkit-scrollbar-thumb:hover {
                background: var(--tertiary); /* 滑块悬停时颜色 */
              }

              &::-webkit-scrollbar-track {
                background: var(--light); /* 滚动条轨道颜色 */
                border-radius: 3px; /* 圆角轨道 */
              }

              &.collapsed {
                max-height: 0;
                transition:
                    max-height 0.35s ease,
                    visibility 0s linear 0.35s;
                visibility: hidden;
              }

              & ul {
                list-style: none;
                margin: 0.08rem 0;
                padding: 0;
                transition:
                    max-height 0.35s ease,
                    transform 0.35s ease,
                    opacity 0.2s ease;
                & li > a {
                  color: var(--dark);
                  opacity: 0.75;
                  pointer-events: all;
                }
              }

              > #explorer-ul {
                max-height: none;
              }

              /* 深度缩进 */
              @for $i from 0 through 6 {
                & .depth-#{$i} {
                  padding-left: calc(1rem * #{$i});
                }
              }
            }
    g.关于我
        a.quartz/components/About.tsx
            // @ts-ignore: this is safe, we don't want to actually make darkmode.inline.ts a module as
            // modules are automatically deferred and we don't want that to happen for critical beforeDOMLoads
            // see: https://v8.dev/features/modules#defer
            import darkmodeScript from "./scripts/darkmode.inline"
            import styles from "./styles/about.scss"
            import {QuartzComponent, QuartzComponentConstructor, QuartzComponentProps} from "./types"
            import {i18n} from "../i18n"
            import {classNames} from "../util/lang"

            const About: QuartzComponent = ({displayClass, cfg}: QuartzComponentProps) => {
              return (
                <div className={classNames(displayClass, "about")}>
                  <div className="link-container">
                    <ul>
                      <li>
                        <a href="https://github.com/halavah" target="_blank">
                          <svg t="1734574903988" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1446" width="25" height="25">
                            <path d="M498.894518 100.608396c-211.824383 0-409.482115 189.041494-409.482115 422.192601 0 186.567139 127.312594 344.783581 295.065226 400.602887 21.13025 3.916193 32.039717-9.17701 32.039717-20.307512 0-10.101055 1.176802-43.343157 1.019213-78.596056-117.448946 25.564235-141.394311-49.835012-141.394311-49.835012-19.225877-48.805566-46.503127-61.793368-46.503127-61.793368-38.293141-26.233478 3.13848-25.611308 3.13848-25.611308 42.361807 2.933819 64.779376 43.443441 64.779376 43.443441 37.669948 64.574714 98.842169 45.865607 122.912377 35.094286 3.815909-27.262924 14.764262-45.918819 26.823925-56.431244-93.796246-10.665921-192.323237-46.90017-192.323237-208.673623 0-46.071292 16.498766-83.747379 43.449581-113.332185-4.379751-10.665921-18.805298-53.544497 4.076852-111.732757 0 0 35.46063-11.336186 116.16265 43.296085 33.653471-9.330506 69.783343-14.022365 105.654318-14.174837 35.869952 0.153496 72.046896 4.844332 105.753579 14.174837 80.606853-54.631248 116.00813-43.296085 116.00813-43.296085 22.935362 58.18826 8.559956 101.120049 4.180206 111.732757 27.052123 29.584806 43.443441 67.260893 43.443441 113.332185 0 162.137751-98.798167 197.850114-192.799074 208.262254 15.151072 13.088086 28.65155 38.804794 28.65155 78.17957 0 56.484456-0.459464 101.94381-0.459464 115.854635 0 11.235902 7.573489 24.381293 29.014824 20.2543C825.753867 867.330798 933.822165 709.10924 933.822165 522.700713c0-233.155201-224.12657-422.192601-434.927647-422.192601L498.894518 100.608396z" fill="#3F3F3F" p-id="1447"></path>
                          </svg>
                          <span style="position: relative; top: -5px;">GitHub</span>
                        </a>
                      </li>
                      <li>
                        <a href="https://space.bilibili.com/71393128/" target="_blank">
                          <svg t="1734575058981" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2445" width="25" height="25">
                            <path
                              d="M777.514667 131.669333a53.333333 53.333333 0 0 1 0 75.434667L728.746667 255.829333h49.92A160 160 0 0 1 938.666667 415.872v320a160 160 0 0 1-160 160H245.333333A160 160 0 0 1 85.333333 735.872v-320a160 160 0 0 1 160-160h49.749334L246.4 207.146667a53.333333 53.333333 0 0 1 75.392-75.434667l113.152 113.152c3.370667 3.370667 6.186667 7.04 8.448 10.965333h137.088c2.261333-3.925333 5.12-7.68 8.490667-11.008l113.109333-113.152a53.333333 53.333333 0 0 1 75.434667 0z m1.152 231.253334H245.333333a53.333333 53.333333 0 0 0-53.205333 49.365333l-0.128 4.010667v320c0 28.117333 21.76 51.114667 49.365333 53.162666l3.968 0.170667h533.333334a53.333333 53.333333 0 0 0 53.205333-49.365333l0.128-3.968v-320c0-29.44-23.893333-53.333333-53.333333-53.333334z m-426.666667 106.666666c29.44 0 53.333333 23.893333 53.333333 53.333334v53.333333a53.333333 53.333333 0 1 1-106.666666 0v-53.333333c0-29.44 23.893333-53.333333 53.333333-53.333334z m320 0c29.44 0 53.333333 23.893333 53.333333 53.333334v53.333333a53.333333 53.333333 0 1 1-106.666666 0v-53.333333c0-29.44 23.893333-53.333333 53.333333-53.333334z"
                              p-id="2446"></path>
                          </svg>
                          <span style="position: relative; top: -5px;">BiliBili</span>
                        </a>
                      </li>
                    </ul>
                  </div>
                  <div className="home-container">
                    <div className="about-container">
                      <a href="/">
                        <svg t="1734575352208" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3589" width="25" height="25">
                          <path
                            d="M452.266667 119.466667a99.555556 99.555556 0 0 1 119.466666 0l284.444445 213.333333c25.031111 18.773333 39.822222 48.355556 39.822222 79.644444v426.666667A99.555556 99.555556 0 0 1 796.444444 938.666667H227.555556a99.555556 99.555556 0 0 1-99.555556-99.555556v-426.666667c0-31.288889 14.791111-60.871111 39.822222-79.644444l284.444445-213.333333z m68.266666 68.266666a14.222222 14.222222 0 0 0-17.066666 0l-284.444445 213.333334a14.222222 14.222222 0 0 0-5.688889 11.377777v426.666667c0 7.850667 6.371556 14.222222 14.222223 14.222222h568.888888a14.222222 14.222222 0 0 0 14.222223-14.222222v-426.666667a14.222222 14.222222 0 0 0-5.688889-11.377777l-284.444445-213.333334z"
                            p-id="3590"></path>
                          <path d="M455.111111 668.444444a14.222222 14.222222 0 0 0-14.222222 14.222223v227.555555h-85.333333v-227.555555c0-54.954667 44.600889-99.555556 99.555555-99.555556h113.777778c54.954667 0 99.555556 44.600889 99.555555 99.555556v227.555555h-85.333333v-227.555555a14.222222 14.222222 0 0 0-14.222222-14.222223H455.111111z" p-id="3591"></path>
                        </svg>
                        <span style="position: relative; top: -5px;">Index</span>
                      </a>
                    </div>
                    <button class="changemode" id="changemode">
                      <svg
                        xmlns="http://www.w3.org/2000/svg"
                        xmlnsXlink="http://www.w3.org/1999/xlink"
                        version="1.1"
                        id="dayIcon"
                        x="0px"
                        y="0px"
                        viewBox="0 0 35 35"
                        style="enable-background:new 0 0 35 35"
                        xmlSpace="preserve"
                        aria-label={i18n(cfg.locale).components.themeToggle.darkMode}
                      >
                        <title>{i18n(cfg.locale).components.themeToggle.darkMode}明/暗</title>
                        <path
                          d="M6,17.5C6,16.672,5.328,16,4.5,16h-3C0.672,16,0,16.672,0,17.5    S0.672,19,1.5,19h3C5.328,19,6,18.328,6,17.5z M7.5,26c-0.414,0-0.789,0.168-1.061,0.439l-2,2C4.168,28.711,4,29.086,4,29.5    C4,30.328,4.671,31,5.5,31c0.414,0,0.789-0.168,1.06-0.44l2-2C8.832,28.289,9,27.914,9,27.5C9,26.672,8.329,26,7.5,26z M17.5,6    C18.329,6,19,5.328,19,4.5v-3C19,0.672,18.329,0,17.5,0S16,0.672,16,1.5v3C16,5.328,16.671,6,17.5,6z M27.5,9    c0.414,0,0.789-0.168,1.06-0.439l2-2C30.832,6.289,31,5.914,31,5.5C31,4.672,30.329,4,29.5,4c-0.414,0-0.789,0.168-1.061,0.44    l-2,2C26.168,6.711,26,7.086,26,7.5C26,8.328,26.671,9,27.5,9z M6.439,8.561C6.711,8.832,7.086,9,7.5,9C8.328,9,9,8.328,9,7.5    c0-0.414-0.168-0.789-0.439-1.061l-2-2C6.289,4.168,5.914,4,5.5,4C4.672,4,4,4.672,4,5.5c0,0.414,0.168,0.789,0.439,1.06    L6.439,8.561z M33.5,16h-3c-0.828,0-1.5,0.672-1.5,1.5s0.672,1.5,1.5,1.5h3c0.828,0,1.5-0.672,1.5-1.5S34.328,16,33.5,16z     M28.561,26.439C28.289,26.168,27.914,26,27.5,26c-0.828,0-1.5,0.672-1.5,1.5c0,0.414,0.168,0.789,0.439,1.06l2,2    C28.711,30.832,29.086,31,29.5,31c0.828,0,1.5-0.672,1.5-1.5c0-0.414-0.168-0.789-0.439-1.061L28.561,26.439z M17.5,29    c-0.829,0-1.5,0.672-1.5,1.5v3c0,0.828,0.671,1.5,1.5,1.5s1.5-0.672,1.5-1.5v-3C19,29.672,18.329,29,17.5,29z M17.5,7    C11.71,7,7,11.71,7,17.5S11.71,28,17.5,28S28,23.29,28,17.5S23.29,7,17.5,7z M17.5,25c-4.136,0-7.5-3.364-7.5-7.5    c0-4.136,3.364-7.5,7.5-7.5c4.136,0,7.5,3.364,7.5,7.5C25,21.636,21.636,25,17.5,25z"></path>
                      </svg>
                      <svg
                        xmlns="http://www.w3.org/2000/svg"
                        xmlnsXlink="http://www.w3.org/1999/xlink"
                        version="1.1"
                        id="nightIcon"
                        x="0px"
                        y="0px"
                        viewBox="0 0 100 100"
                        style="enable-background:new 0 0 100 100"
                        xmlSpace="preserve"
                        aria-label={i18n(cfg.locale).components.themeToggle.lightMode}
                      >
                        <title>{i18n(cfg.locale).components.themeToggle.lightMode}</title>
                        <path
                          d="M96.76,66.458c-0.853-0.852-2.15-1.064-3.23-0.534c-6.063,2.991-12.858,4.571-19.655,4.571  C62.022,70.495,50.88,65.88,42.5,57.5C29.043,44.043,25.658,23.536,34.076,6.47c0.532-1.08,0.318-2.379-0.534-3.23  c-0.851-0.852-2.15-1.064-3.23-0.534c-4.918,2.427-9.375,5.619-13.246,9.491c-9.447,9.447-14.65,22.008-14.65,35.369  c0,13.36,5.203,25.921,14.65,35.368s22.008,14.65,35.368,14.65c13.361,0,25.921-5.203,35.369-14.65  c3.872-3.871,7.064-8.328,9.491-13.246C97.826,68.608,97.611,67.309,96.76,66.458z"></path>
                      </svg>
                      <div className="text-container">
                        <a>Light/Dark</a>
                      </div>
                    </button>
                  </div>
                </div>
              )
            }

            About.beforeDOMLoaded = darkmodeScript
            About.css = styles

            export default (() => About) satisfies QuartzComponentConstructor
        b.quartz/components/styles/about.scss
            // div
            .about {
              position: absolute;
              bottom: 0.8rem;
              left: 0;
              right: 0;
            }

            // link
            .link-container {
              text-align: left;
              opacity: 0.7;
              margin-bottom: 0.6rem;

              ul {
                list-style: none;
                margin: 0;
                padding: 0;
                display: flex;
                flex-direction: row;
                gap: 1rem;
                margin-top: -1rem;

                li a {
                  text-decoration: none;
                  color: #4584a5;

                  &:hover {
                    opacity: 0.7;
                  }
                }
              }
            }

            // home
            .home-container {
              display: flex;
              align-items: center;
              justify-content: flex-start;
            }

            // about
            .about-container {
              margin-bottom: 2px;
              margin-right: 25px;

              a {
                text-decoration: none;
                color: #7B97AA;
                &:hover {
                  opacity: 0.7;
                }
              }
            }

            // changemode
            .changemode {
              cursor: pointer;
              padding: 0;
              position: relative;
              background: none;
              border: none;
              width: 100px;
              height: 30px;
              margin-left: 2px;
              margin-top: -6px;
              text-align: inherit;

              display: flex;
              align-items: center;  /* 垂直居中对齐 */
              justify-content: flex-start;  /* 水平左对齐,也可以根据需求调整 */

              & svg {
                position: absolute;
                width: 20px;
                height: 20px;
                top: calc(50% - 10px);
                fill: var(--darkgray);
                transition: opacity 0.1s ease;
              }
            }

            :root[saved-theme="dark"] {
              color-scheme: dark;
            }

            :root[saved-theme="light"] {
              color-scheme: light;
            }

            :root[saved-theme="dark"] .changemode {
              & > #dayIcon {
                display: none;
              }
              & > #nightIcon {
                display: inline;
              }
            }

            :root .changemode {
              & > #dayIcon {
                display: inline;
              }
              & > #nightIcon {
                display: none;
              }
            }

            // text
            .text-container {
              margin-bottom: -5px;
              margin-left: 22px;

              a {
                font-size: 14px;
                color: #7B97AA;
                &:hover {
                  opacity: 0.7;
                }
              }
            }
        c.quartz/components/scripts/darkmode.inline.ts
            const userPref = window.matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark"
            const currentTheme = localStorage.getItem("theme") ?? userPref
            document.documentElement.setAttribute("saved-theme", currentTheme)

            const emitThemeChangeEvent = (theme: "light" | "dark") => {
              const event: CustomEventMap["themechange"] = new CustomEvent("themechange", {
                detail: { theme },
              })
              document.dispatchEvent(event)
            }

            document.addEventListener("nav", () => {
              const switchTheme = (e: Event) => {
                const newTheme =
                  document.documentElement.getAttribute("saved-theme") === "dark" ? "light" : "dark"
                document.documentElement.setAttribute("saved-theme", newTheme)
                localStorage.setItem("theme", newTheme)
                emitThemeChangeEvent(newTheme)
              }

              const themeChange = (e: MediaQueryListEvent) => {
                const newTheme = e.matches ? "dark" : "light"
                document.documentElement.setAttribute("saved-theme", newTheme)
                localStorage.setItem("theme", newTheme)
                emitThemeChangeEvent(newTheme)
              }

              // Darkmode toggle
              const themeButton = document.querySelector("#darkmode") as HTMLButtonElement
              themeButton.addEventListener("click", switchTheme)
              window.addCleanup(() => themeButton.removeEventListener("click", switchTheme))

              // Changemode toggle
              const themeButton2 = document.querySelector("#changemode") as HTMLButtonElement
              themeButton2.addEventListener("click", switchTheme)
              window.addCleanup(() => themeButton2.removeEventListener("click", switchTheme))

              // Listen for changes in prefers-color-scheme
              const colorSchemeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)")
              colorSchemeMediaQuery.addEventListener("change", themeChange)
              window.addCleanup(() => colorSchemeMediaQuery.removeEventListener("change", themeChange))
            })
    h.备案
        a.quartz/components/Footer.tsx
            import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
            import style from "./styles/footer.scss"
            import { version } from "../../package.json"
            import { i18n } from "../i18n"

            interface Options {
              links: Record<string, string>
            }

            export default ((opts?: Options) => {
              const Footer: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => {
                const year = new Date().getFullYear()
                const links = opts?.links ?? []
                return (
                  <footer class={`${displayClass ?? ""}`}>
                    <p>
                      {i18n(cfg.locale).components.footer.createdWith}{" "}
                      <a href="https://github.com/halavah">halavah</a> © {year}
                    </p>
                    <p>
                      苏ICP备19059396号-1
                    </p>
                    <ul>
                      {Object.entries(links).map(([text, link]) => (
                        <li>
                          <a href={link}>{text}</a>
                        </li>
                      ))}
                    </ul>
                  </footer>
                )
              }

              Footer.css = style
              return Footer
            }) satisfies QuartzComponentConstructor
        b.quartz/components/styles/footer.scss
            footer {
              text-align: left;
              margin-bottom: 1rem;
              opacity: 0.7;

              & ul {
                list-style: none;
                margin: 0;
                padding: 0;
                display: flex;
                flex-direction: row;
                gap: 1rem;
                margin-top: -1rem;
              }
            }

03.启动锁【v1,代码不小心已丢弃】【最简单版本】【123456出现在html】
    a.提问
        你思考的方向有问题,目前 http://localhost:8080/verify 访问 还是处于 verify.md文件,而且是 内嵌在博客 布局(左边 explorer、右边大纲)里面,虽然verify.html存在,但并不是 @Verify.tsx 定义的 html。
        重新思考你的修改方向,然后把多种思路汇报给我。不要生成任何代码
        再对 你目前 对项目 所有改动的地方,对 verify 功能 进行检查
        你对之前的全部提问,去真正理解我想干什么
        先慢修改任何文件,你确定你写的 verifyPage.ts 最终可以生成我想要的 verify.html 页面,然后 http://localhost:8080/verify 可以路由到这个 验证页面吗
        现在功能是可以使用的。针对 启动保护页面 功能,现在对你 项目修改的全部文件 进行检查,将不属于这个功能的 冗余代码、文件 进行删除
        现在功能是可以使用的。再对 你目前 对项目 所有改动的地方,进行汇报
        现在密码是123456,帮我创建100个随机密码,放到页面中。密码长度为10,允许强密码
        -----------------------------------------------------------------------------------------------------
        布局替换方向:
        问题:当前的布局系统是基于 markdown 内容的,即使修改了 layout,仍然会套用基础布局
        思路:需要在更底层处理布局,而不是仅仅修改 layout 配置
        路由拦截方向:
        问题:现在的路由处理是先找到 markdown 文件,然后应用布局
        思路:在路由层面拦截 /verify 请求,直接返回 Verify 组件渲染的内容,绕过 markdown 处理流程
        组件渲染方向:
        问题:Verify.tsx 组件没有被正确地作为独立页面处理
        思路:创建一个专门的页面渲染器,用于处理特殊路由的组件渲染
        构建流程方向:
        问题:构建过程将所有 markdown 文件视为相同类型的内容
        思路:在构建时区分特殊页面,使用不同的构建流程
        插件系统方向:
        问题:当前的插件系统主要处理 markdown 内容
        思路:创建新的插件类型,专门处理特殊页面的渲染
        -----------------------------------------------------------------------------------------------------
        verifyPage.ts分析:
        优点:
        完全独立的页面
        不依赖博客布局
        包含所有必要的样式和脚本
        符合路由拦截的思路
    b.方案2:路由拦截方向
        1.访问任意页面
          ↓
        2.Content.tsx 检查验证状态
          ↓
        3.未验证则重定向到 /verify
          ↓
        4.handlers.js 拦截 /verify 请求
          ↓
        5.返回 verifyPage.ts 生成的页面
          ↓
        6.用户输入密码 (123456)
          ↓
        7.验证成功后重定向回原页面
    c.quartz/cli/handlers.js - 路由处理改动
        // 添加了验证页面路由处理
        if (fp === "/verify") {
          try {
            const { generateVerifyPage } = await import("../../quartz/.quartz-cache/verify-page.js")
            res.writeHead(200, { "Content-Type": "text/html" })
            res.end(generateVerifyPage())
            return
          } catch (err) {
            console.error("Error serving verify page:", err)
            res.writeHead(500)
            res.end("Internal Server Error")
            return
          }
        }
    d.quartz/build.ts - 构建配置改动
        // 添加了 buildVerifyPage 函数
        async function buildVerifyPage() {
          try {
            await esbuild.build({
              entryPoints: ['./quartz/util/verifyPage.ts'],
              outfile: './quartz/.quartz-cache/verify-page.js',
              bundle: true,
              format: 'esm',
              platform: 'node',
            })
            console.log('Verify page built successfully')
          } catch (err) {
            console.error('Error building verify page:', err)
          }
        }

        // 在 buildQuartz 函数中添加了构建验证页面的调用
        await buildVerifyPage()
    e.quartz/components/pages/Content.tsx - 添加验证脚本
        // 添加了验证检查脚本
        const verifyScript = `
          if(!sessionStorage.getItem('verified')) {
            const currentPath = window.location.pathname
            if(currentPath !== '/verify') {
              sessionStorage.setItem('intendedPath', currentPath)
              window.location.href = '/verify'
            }
          }
        `

        Content.beforeDOMLoaded = verifyScript
    f.新增文件 quartz/util/verifyPage.ts:
        export function generateVerifyPage(): string {
          const backgroundImages = [
            "/static/screen/01.jpg",
            "/static/screen/02.jpg",
            "/static/screen/03.jpg",
            "/static/screen/04.jpg",
            "/static/screen/05.jpg",
            "/static/screen/06.jpg",
            "/static/screen/07.jpg",
          ]

          const randomBackground = backgroundImages[Math.floor(Math.random() * backgroundImages.length)]

          const verifyStyles = `
            :root {
              --primary: #4a90e2;
              --secondary: #f5a623;
              --background: rgba(240, 244, 248, 0.8);
              --text: #333;
              --error: #e74c3c;
            }

            * {
              box-sizing: border-box;
              margin: 0;
              padding: 0;
            }

            body {
              font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
              color: var(--text);
              line-height: 1.6;
              overflow: hidden;
            }

            .background-container {
              position: fixed;
              top: 0;
              left: 0;
              width: 100%;
              height: 100%;
              background-image: url('${randomBackground}');
              background-size: cover;
              background-position: center;
              transform: scale(1.1);
              z-index: -1;
            }

            .verify-page {
              min-height: 100vh;
              display: flex;
              justify-content: center;
              align-items: center;
              padding: 20px;
              perspective: 1000px;
            }

            .verify-container {
              background-color: var(--background);
              padding: clamp(20px, 5vw, 40px);
              border-radius: 8px;
              box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
              text-align: center;
              max-width: min(90vw, 350px);
              width: 100%;
              backdrop-filter: blur(1px);
              transform-style: preserve-3d;
              animation: container-entrance 0.6s ease-out;
              margin: 0 auto;
            }

            @keyframes container-entrance {
              from {
                opacity: 0;
                transform: translateY(-50px) rotateX(10deg);
              }
              to {
                opacity: 1;
                transform: translateY(0) rotateX(0);
              }
            }

            .lock-icon {
              width: clamp(40px, 8vw, 50px);
              height: clamp(40px, 8vw, 50px);
              margin: 0 auto 15px;
              color: var(--primary);
              animation: icon-bounce 0.5s ease-out 0.3s both;
            }

            @keyframes icon-bounce {
              0% {
                transform: scale(0);
              }
              50% {
                transform: scale(1.2);
              }
              100% {
                transform: scale(1);
              }
            }

            h1 {
              color: var(--primary);
              margin-bottom: 8px;
              font-size: clamp(20px, 4vw, 24px);
              animation: text-fade-in 0.5s ease-out 0.5s both;
            }

            p {
              color: #666;
              margin-bottom: 15px;
              font-size: clamp(12px, 3vw, 14px);
              animation: text-fade-in 0.5s ease-out 0.7s both;
            }

            @keyframes text-fade-in {
              from {
                opacity: 0;
                transform: translateY(10px);
              }
              to {
                opacity: 1;
                transform: translateY(0);
              }
            }

            .input-group {
              position: relative;
              margin-bottom: 15px;
              animation: input-fade-in 0.5s ease-out 0.9s both;
            }

            @keyframes input-fade-in {
              from {
                opacity: 0;
                transform: translateX(-10px);
              }
              to {
                opacity: 1;
                transform: translateX(0);
              }
            }

            input {
              width: 100%;
              padding: clamp(8px, 2vw, 10px);
              border: 2px solid #ddd;
              border-radius: 4px;
              font-size: clamp(14px, 3vw, 16px);
              transition: border-color 0.3s, box-shadow 0.3s;
            }

            input:focus {
              outline: none;
              border-color: var(--primary);
              box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
            }

            label {
              position: absolute;
              left: 10px;
              top: 50%;
              transform: translateY(-50%);
              color: #999;
              pointer-events: none;
              transition: 0.3s ease all;
              font-size: clamp(12px, 2.5vw, 14px);
            }

            input:focus ~ label,
            input:not(:placeholder-shown) ~ label {
              top: 0;
              font-size: 12px;
              color: var(--primary);
              background-color: white;
              padding: 0 5px;
            }

            button {
              background-color: var(--primary);
              color: white;
              border: none;
              padding: clamp(8px, 2vw, 12px) clamp(15px, 4vw, 20px);
              border-radius: 4px;
              font-size: clamp(14px, 3vw, 16px);
              cursor: pointer;
              transition: background-color 0.3s, transform 0.3s;
              width: 100%;
              animation: button-fade-in 0.5s ease-out 1.1s both;
            }

            @keyframes button-fade-in {
              from {
                opacity: 0;
                transform: translateY(10px);
              }
              to {
                opacity: 1;
                transform: translateY(0);
              }
            }

            button:hover {
              background-color: #3a7bc8;
              transform: translateY(-2px);
            }

            button:active {
              transform: translateY(0);
            }

            @keyframes shake {
              0%, 100% { transform: translateX(0); }
              10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
              20%, 40%, 60%, 80% { transform: translateX(5px); }
            }

            .error {
              border-color: var(--error) !important;
              animation: shake 0.5s;
            }

            .error-message {
              color: var(--error);
              font-size: 14px;
              margin-top: 5px;
              display: none;
              animation: error-fade-in 0.3s ease-out;
            }

            @keyframes error-fade-in {
              from {
                opacity: 0;
                transform: translateY(-10px);
              }
              to {
                opacity: 1;
                transform: translateY(0);
              }
            }

            @media (max-width: 480px) {
              .verify-page {
                padding: 10px;
              }

              .verify-container {
                padding: 20px;
              }

              .background-container {
                transform: scale(1.05);
              }
            }
          `

          const verifyScript = `
            window.addEventListener('DOMContentLoaded', () => {
              const form = document.getElementById('verify-form');
              const passwordInput = document.getElementById('verify-password');
              const verifyContainer = document.querySelector('.verify-container');

              // 400个随机强密码
              const validPasswords = [
                "123456",
              ];

              if (!sessionStorage.getItem('verified')) {
                if (window.location.pathname !== '/verify') {
                  window.location.href = '/verify';
                }
              }

              form?.addEventListener('submit', (e) => {
                e.preventDefault();
                const password = passwordInput.value;

                if (validPasswords.includes(password)) {
                  sessionStorage.setItem('verified', 'true');
                  const intendedPath = sessionStorage.getItem('intendedPath') || '/';
                  window.location.href = intendedPath;
                } else {
                  passwordInput.classList.add('error');
                  const errorMessage = document.createElement('div');
                  errorMessage.className = 'error-message';
                  errorMessage.textContent = 'Incorrect password. Please try again.';
                  form.appendChild(errorMessage);
                  errorMessage.style.display = 'block';

                  setTimeout(() => {
                    passwordInput.classList.remove('error');
                    errorMessage.style.display = 'none';
                  }, 3000);
                }
              });

              passwordInput?.addEventListener('input', () => {
                passwordInput.classList.remove('error');
                const errorMessage = form.querySelector('.error-message');
                if (errorMessage) {
                  errorMessage.style.display = 'none';
                }
              });

              // Mouse movement effect
              document.addEventListener('mousemove', (e) => {
                const { clientX, clientY } = e;
                const centerX = window.innerWidth / 2;
                const centerY = window.innerHeight / 2;
                const moveX = (clientX - centerX) / centerX;
                const moveY = (clientY - centerY) / centerY;

                verifyContainer.style.transform = \`
                  perspective(1000px)
                  rotateY(\${moveX * 5}deg)
                  rotateX(\${-moveY * 5}deg)
                  translateZ(10px)
                \`;
              });
            });
          `

          return `
        <!DOCTYPE html>
        <html lang="en">
        <head>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Verify Page</title>
          <style>
            ${verifyStyles}
          </style>
        </head>
        <body>
          <div class="background-container">
            <div class="verify-page">
              <div class="verify-container">
                <div class="lock-icon">
                  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
                    <path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
                  </svg>
                </div>
                <h1>Welcome</h1>
                <p>Life drifts untethered, fleeting as a dream.</p>
                <form id="verify-form">
                  <div class="input-group">
                    <input type="password" id="verify-password" autofocus required>
                    <label for="verify-password">Password</label>
                  </div>
                  <button type="submit">Verify</button>
                </form>
              </div>
            </div>
          </div>
          <script>
            ${verifyScript}
          </script>
        </body>
        </html>
          `.trim()
        }

04.启动锁【v3_仅适配域名_如vercel_不可逆加密】
    a.思路
        1.访问任意页面
          ↓
        2.Content.tsx 检查验证状态
          ↓
        3.未验证则重定向到 /verify
          ↓
        4.handlers.js 拦截 /verify 请求
          ↓
        5.返回 verifyPage.ts 生成的页面,verify.html
          ↓
        6.用户输入密码 (123456)
          ↓
        7.验证成功后重定向回原页面
    b.方案
        Token 基于时间验证
        不直接存储 verified: true,而是存储一个基于密码和时间生成的token
        验证时同时验证token的有效性和时间戳
        缺点:仍然可以被复制token绕过,但增加了难度
        -----------------------------------------------------------------------------------------------------
        多层验证令牌
        将验证状态分成多个部分存储
        每个部分都是通过密码+随机盐值生成的hash
        需要所有部分都验证通过才能访问
        缺点:技术人员仍可以通过分析代码找到生成规则
        -----------------------------------------------------------------------------------------------------
        动态验证码
        基于密码和时间戳动态生成验证码
        定期检查验证码是否有效
        如果验证码过期需要重新验证
        缺点:增加了复杂度,可能影响用户体验
        -----------------------------------------------------------------------------------------------------
        浏览器指纹 + 验证信息绑定
        将验证信息与浏览器指纹绑定
        即使复制storage也无法在其他浏览器使用
        缺点:指纹可能变化,导致误判
        -----------------------------------------------------------------------------------------------------
        混淆与加密存储
        不直接存储验证状态
        将验证信息加密后分散存储在不同位置
        使用复杂的验证逻辑
        缺点:增加代码复杂度,仍可被破解
        -----------------------------------------------------------------------------------------------------
        需要注意的是,纯前端的安全方案都存在被破解的可能性,因为所有代码都在客户端。如果需要更高的安全性,建议:
        考虑使用后端验证
        使用 HTTPS 确保传输安全
        实现访问频率限制
        -----------------------------------------------------------------------------------------------------
        考虑添加其他验证方式(如邮箱验证码)
    c.采用
        根据您的项目结构和需求,我建议采用"Token 基于时间验证"和"混淆与加密存储"的组合方案,因为:
        实现相对简单
        不需要额外的后端支持
        可以在现有代码基础上扩展
        性能影响较小
        提供足够的安全性
        比单纯的 sessionStorage.setItem('verified', 'true') 更安全
        增加破解难度
        可以设置token过期时间
        -----------------------------------------------------------------------------------------------------
        验证成功后:
        // 不要直接存储 verified: true
        // 而是生成一个包含以下信息的token:
        - 时间戳
        - 密码的hash值
        - 随机盐值
        存储方式:
        // 将验证信息分散存储
        - localStorage 存储一部分
        - sessionStorage 存储另一部分
        - cookie 存储第三部分
        验证逻辑:
        // 定期检查:
        - token是否完整
        - 时间戳是否有效
        - hash值是否匹配
        -----------------------------------------------------------------------------------------------------
        这样即使有人知道需要设置storage,也很难知道:
        具体需要设置什么值
        值是如何生成的
        需要在哪些地方设置
    d.实现
        验证流程:
        Content.tsx 中的 verifyScript 在每个页面加载时检查 sessionStorage.getItem('verified')
        未验证时保存当前路径到 intendedPath 并重定向到 /verify
        handlers.js 处理 /verify 路由,返回验证页面
        -----------------------------------------------------------------------------------------------------
        关键问题:
        目前的验证状态只依赖 sessionStorage.setItem('verified', 'true')
        这个状态很容易被手动设置绕过验证
        -----------------------------------------------------------------------------------------------------
        改进思路:
        // 验证成功时:
        const generateToken = (password: string) => {
          const timestamp = Date.now()
          const salt = crypto.randomBytes(16).toString('hex')

          // 1. 生成一个包含密码hash、时间戳和salt的token
          const rawToken = `${hash(password)}:${timestamp}:${salt}`

          // 2. 对token进行加密
          const encryptedToken = encrypt(rawToken)

          // 3. 分散存储token的不同部分
          const [part1, part2, part3] = splitToken(encryptedToken)
          sessionStorage.setItem('v_p1', part1)
          localStorage.setItem('v_p2', part2)
          document.cookie = `v_p3=${part3}`

          return true
        }

        // 验证检查时:
        const checkVerification = () => {
          try {
            // 1. 收集所有部分
            const part1 = sessionStorage.getItem('v_p1')
            const part2 = localStorage.getItem('v_p2')
            const part3 = getCookie('v_p3')

            // 2. 重组并解密token
            const token = decrypt(joinToken(part1, part2, part3))

            // 3. 验证时间戳是否在有效期内
            const [hash, timestamp, salt] = token.split(':')
            if (Date.now() - parseInt(timestamp) > TOKEN_EXPIRE_TIME) {
              return false
            }

            // 4. 验证hash是否正确
            return verifyHash(hash)
          } catch {
            return false
          }
        }
        -----------------------------------------------------------------------------------------------------
        不能简单通过设置 storage 绕过
        token 有时效性
        验证信息分散存储
        即使找到存储位置也很难伪造正确的token
    e.BUG:闪一下
        不要生成任何代码,为什么 访问 @http://127.0.0.1:8080 会闪一下,然后才跳转 @http://127.0.0.1:8080/verify
        -----------------------------------------------------------------------------------------------------
        将验证脚本移到 <head> 标签中
        使用 defer 或 async 属性
        在 DOMContentLoaded 之前执行验证
    f.混淆加密(可逆向)
        当前的加密数据和盐值都是明文存储的
        可以将数据分散存储并引入干扰数据
        实现相对简单,不会增加太多复杂度
        -----------------------------------------------------------------------------------------------------
        将加密数据分散存储在多个变量或对象中
        使用字符串编码转换(如Base64、Unicode转换等)
        引入干扰数据,真实数据藏在其中
        使用多层加密,每层使用不同的算法
        -----------------------------------------------------------------------------------------------------
        当前的问题
        const AUTH = {
            SALT: "x9f#k2p$m5",
            DATA: "HFUMVxJWH1MDBAABWBlGA0sSUARNFRISWBlGA0sSUAQ="
        }
        盐值直接明文存储
        加密数据使用单一Base64编码
        数据结构过于简单直观
        -----------------------------------------------------------------------------------------------------
        改进思路
        A.数据分散存储:
        将SALT拆分成多段,分散在不同变量中
        使用动态计算组合真实盐值
        加入虚假的盐值干扰项
        B.多重编码:
        Base64 -> Unicode -> Hex 多层转换
        字符串反转或位移
        添加动态位移量
        C.干扰数据:
        在加密数据中插入随机干扰字符
        使用特定规则来提取真实数据
        构建虚假的验证路径
        D.数据存储结构:
        使用嵌套对象
        引入无关的配置数据
        使用动态计算的属性名
    g.简单加密(可逆向)
        a.思路
            1.后端验证方案
            这是最推荐的方案,将密码验证逻辑完全移到后端:
            前端只发送密码到后端API
            后端进行验证并返回token
            使用session或JWT来保持登录状态
            2.密码加密方案
            如果必须在前端做验证,可以:
            存储密码的哈希值而不是明文
            对用户输入进行相同的哈希处理后比较
            使用加盐哈希增加安全性
            3.混淆加密方案
            通过代码混淆和加密来增加破解难度:
            使用JavaScript混淆器处理代码
            将密码列表进行加密存储
            运行时动态解密
        b.采用【混淆加密方案】,加密过程是:
            每个密码先填充到32字符长度
            使用XOR(异或)运算加密每个字符:
            密码字符 XOR 密钥字符
            密钥是 salt("x9f#k2p$m5") + 当天日期
            将所有加密后的字符串拼接
            最后用base64编码整个结果
        c.解密方法
            function encryptPasswords(passwords: string[], salt: string): string {
              const key = salt + new Date().getUTCDate()
              const data = passwords
                .map((pwd) => {
                  return pwd
                    .padEnd(32, " ")
                    .split("")
                    .map((char, index) => {
                      return String.fromCharCode(char.charCodeAt(0) ^ key.charCodeAt(index % key.length))
                    })
                    .join("")
                })
                .join("")

              return btoa(data)
            }
    h.只能正向加密(采用)
        生成的密码 只能是正向的,不能是逆向的。
        而验证时,只能根据输入的密码来正向,最后比较2个最终的结果(比较方式,经过加密)

05.启动锁【废弃】,自动适配【域名】【域名/仓库】
    a.提问
        让我重新梳理思路:
        当前问题:
        访问根路径时出现 302 重定向
        验证成功后无法正确跳转回原始路径
        路径处理在不同环境下不一致
        可能的解决思路:

        思路A - 纯前端处理:
        在 Content.tsx 中检测未验证状态
        保存当前路径到 sessionStorage
        重定向到验证页面
        验证成功后从 sessionStorage 读取路径并跳转
        思路B - 服务端重定向:
        在 handlers.js 中拦截所有请求
        未验证时重定向到验证页面
        通过 URL 参数传递原始路径
        验证成功后从 URL 参数获取跳转路径
        思路C - 混合处理:
        服务端处理根路径访问的重定向
        前端处理其他页面的验证检查
        统一使用 sessionStorage 存储路径
        验证页面同时支持 URL 参数和 sessionStorage

        各思路的优缺点:
        思路A:
        优点:实现简单,完全前端控制
        缺点:可能出现闪烁,安全性较低
        思路B:
        优点:更安全,体验更流畅
        缺点:实现复杂,需要处理多种路径情况
        思路C:
        优点:兼顾安全性和用户体验
        缺点:逻辑分散,需要同步前后端状态
        你觉得哪个思路更适合?我可以详细展开任何一个思路。
        -----------------------------------------------------------------------------------------------------
        问题所在:
        sessionStorage 是前端存储
        服务端(handlers.js)无法访问 sessionStorage
        导致每次请求服务端都会认为是未验证状态
        结果就是不断302重定向

        验证流程:
        用户访问 http://127.0.0.1:8080/
        handlers.js 检查验证状态(但无法访问 sessionStorage)
        重定向到 /verify?from=/
        即使验证成功存储在 sessionStorage
        下次请求时服务端仍然无法知道验证状态
        继续重定向...形成循环
        所以思路B不可行,应该回到思路A或C:

        思路A(纯前端)更合理:
        1. 所有验证逻辑在前端处理
        Content.tsx 检查 sessionStorage
        未验证则保存路径并重定向
        4. 验证成功后直接从 sessionStorage 恢复路径
        这样避免了服务端重定向的问题,你觉得呢?
        -----------------------------------------------------------------------------------------------------
        // 对于 https://halavah.github.io/valut/verify
        // pathParts = ['valut', 'verify']
        // lastPath = 'verify'
        // repoPath = 'valut'
        // finalBasePath = '/valut'
        // 对于 https://valut.vercel.app/verify
        // pathParts = ['verify']
        // lastPath = 'verify'
        // repoPath = ''
        // finalBasePath = ''
        const pathParts = window.location.pathname.split('/').filter(Boolean)
        const lastPath = pathParts[pathParts.length - 1]
        const isVerifyPage = lastPath === 'verify'
        const repoPath = isVerifyPage && pathParts.length > 1 ? pathParts[pathParts.length - 2] : ''
        const finalBasePath = repoPath ? '/' + repoPath : ''
        访问 https://halavah.github.io/valut/ 跳转 https://halavah.github.io/valut/verify ,然后通过verify.html来验证
        访问 https://halavah.github.io 跳转 https://halavah.github.io/verify ,然后通过verify.html来验证
        访问 https://valut.vercel.app 跳转 https://valut.vercel.app/verify ,然后通过verify.html来验证
        访问 http://127.0.0.1:8080 跳转 http://127.0.0.1:8080/verify ,然后通过verify.html来验证
    b.实现
        放弃

5.5 quartz2

01.使用
    a.下载
        npx shadcn@latest add "https://v0.dev/chat/b/b_4X2vSJZ3iRk"
    b.安装
        npm install
    c.使用
        npm run dev                                                             --开发环境:启动
        -----------------------------------------------------------------------------------------------------
        npm run build                                                           --生产环境:构建
        npm run start                                                           --生产环境:启动

02.启动锁【Next.js后端服务】
    a.需求
        auth.ts 中需要移至后端的部分:
        密码加密函数 _encrypt
        密码哈希值 correctHashes
        Token 生成逻辑 generateToken
        Token 验证逻辑 verifyToken
        -----------------------------------------------------------------------------------------------------
        verifyPage.ts 中需要移至后端的部分:
        验证页面生成函数 generateVerifyPage
        页面模板可以转换为 Next.js 的页面组件
        -----------------------------------------------------------------------------------------------------
        Content.tsx 中需要移至后端的部分:
        验证状态检查逻辑
    b.认证相关 API
        POST /api/auth/verify
        - 功能:验证密码
        - 输入:password
        - 返回:token

        GET /api/auth/check
        - 功能:验证 token
        - 输入:token (从 cookie)
        - 返回:验证状态

        POST /api/auth/logout
        - 功能:登出
        - 输入:token
        - 返回:成功状态
    c.页面路由
        /verify
        - 登录页面
        - 使用 Next.js 页面组件
        - 包含表单和样式

        /api/protected/*
        - 受保护的内容 API
        - 需要验证 token
    d.中间件
        middleware.ts
        - 路由保护
        - token 验证
        - 重定向逻辑

03.启动锁【Next.js后端服务】【思路1】
    a.当前思路
        用户访问 Quartz 页面
        ↓
        Content.tsx 检查验证状态(调用 Next.js API)
        ↓
        未验证则重定向到 Next.js 验证页面
        ↓
        用户输入密码
        ↓
        Next.js 后端验证
        ↓
        验证成功返回 Quartz
    b.创建 Next.js 验证服务
        quartz-auth/                # Next.js 项目根目录
        ├── pages/
        │   ├── api/               # API 路由
        │   │   └── auth/         # 认证相关 API
        │   │       ├── verify    # 密码验证
        │   │       ├── check     # token 检查
        │   │       └── logout    # 登出
        │   └── verify.tsx        # 验证页面
        └── middleware.ts         # 路由中间件
    c.修改现有 Quartz 代码
        quartz-front/quartz/util/verifyPage.ts     # 整个文件移除
        quartz-front/public/verify.html            # 由 Next.js 的 verify.tsx 替代
        quartz-front/quartz/util/auth.ts           # 移除,逻辑移至 Next.js
    d.需要修改
        quartz-front/quartz/components/pages/Content.tsx
        # 修改验证逻辑,改为调用 Next.js API
    e.数据和资源迁移
        quartz-front/public/static/screen/*        # 背景图片迁移到 Next.js
        quartz-front/public/static/icon.png        # 图标迁移到 Next.js
    f.配置更新
        设置 Next.js 服务的域名和端口
        配置 CORS 策略
        设置环境变量
    g.部署流程
        部署 Next.js 服务到 Vercel
        更新 Quartz 配置指向新的验证服务
        确保域名和 SSL 证书配置正确

04.启动锁【Next.js后端服务】【思路2】
    a.当前思路
        用户访问 Quartz 页面
        ↓
        Content.tsx 检查验证状态(调用 Next.js API)
        ↓
        未验证则重定向到 Next.js 验证页面
        ↓
        用户输入密码
        ↓
        Next.js 后端验证
        ↓
        验证成功返回 Quartz
    b.密码验证接口(同时会生成令牌)
        curl --location 'http://localhost:3000/api/auth?action=verify' \
        --header 'Content-Type: application/json' \
        --data '{
            "password": "123456"
        }'
        -----------------------------------------------------------------------------------------------------
        成功响应示例:
        {
            "success": true,
            "tokens": {
                "session": "TUI5OEly",  // 存储到 sessionStorage
                "local": "MzNDU2Nz"     // 存储到 localStorage
            }
            // cookie 部分会自动设置到浏览器(v_p3=g5MDphYm)
        }
        -----------------------------------------------------------------------------------------------------
        前端调用示例:
        async function verifyPassword(password: string) {
          const response = await fetch('/api/auth?action=verify', {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({ password }),
            credentials: 'include', // 重要:允许设置cookie
          })

          const data = await response.json()
          if (data.success) {
            // 存储令牌的两个部分
            sessionStorage.setItem(AUTH_CONSTANTS.TOKEN_KEYS.SESSION, data.tokens.session)
            localStorage.setItem(AUTH_CONSTANTS.TOKEN_KEYS.LOCAL, data.tokens.local)
            // cookie部分已自动设置
            return true
          }
          return false
        }
    c.令牌检查接口
        curl --location 'http://localhost:3000/api/auth?action=check&session=TUI5OEly&local=MzNDU2Nz' \
        --header 'Cookie: v_p3=g5MDphYm'
        -----------------------------------------------------------------------------------------------------
        响应示例:
        {
            "isAuthenticated": true
        }
        -----------------------------------------------------------------------------------------------------
        前端调用示例:
        async function checkAuth() {
          const session = sessionStorage.getItem(AUTH_CONSTANTS.TOKEN_KEYS.SESSION)
          const local = localStorage.getItem(AUTH_CONSTANTS.TOKEN_KEYS.LOCAL)

          if (!session || !local) return false

          const response = await fetch(
            `/api/auth?action=check&session=${encodeURIComponent(session)}&local=${encodeURIComponent(local)}`,
            {
              credentials: 'include', // 重要:允许发送cookie
            }
          )

          const data = await response.json()
          return data.isAuthenticated
        }
    d.防止前端 JS 被篡改的几个思路:
        服务端验证为主
        所有关键验证逻辑都放在服务端
        前端验证只作为用户体验的补充
        服务端不信任任何前端传来的数据
        -----------------------------------------------------------------------------------------------------
        代码混淆和加密
        使用工具对 JS 代码进行混淆
        关键逻辑使用加密方式存储
        动态解密执行关键代码
        -----------------------------------------------------------------------------------------------------
        完整性校验
        计算 JS 文件的哈希值
        服务端验证文件完整性
        使用 SRI (Subresource Integrity) 属性
        -----------------------------------------------------------------------------------------------------
        动态代码注入
        核心验证逻辑由服务端动态生成
        每次请求生成不同的验证代码
        使用一次性的验证令牌
        -----------------------------------------------------------------------------------------------------
        环境检测
        检测开发者工具是否打开
        检测代码是否被修改
        检测运行环境的合法性
        -----------------------------------------------------------------------------------------------------
        多重验证机制
        多层验证逻辑组合
        验证步骤之间相互依赖
        使用多个加密密钥
        -----------------------------------------------------------------------------------------------------
        时间戳和有效期
        验证代码包含时间限制
        定期更新验证逻辑
        使用一次性的验证码
        -----------------------------------------------------------------------------------------------------
        请求签名
        对关键请求进行签名
        验证请求的来源和完整性
        使用 HMAC 等算法
        -----------------------------------------------------------------------------------------------------
        行为分析
        分析用户操作行为
        检测异常的请求模式
        建立风险控制机制
        -----------------------------------------------------------------------------------------------------
        硬件绑定
        绑定特定的硬件特征
        使用硬件级别的加密
        验证设备指纹
    e.存储对比
        sessionStorage:
        每次打开新标签页都会重置
        仅在当前标签页有效
        关闭标签页后数据就会消失
        所以 v_p1 确实会在新标签页中重置
        -----------------------------------------------------------------------------------------------------
        localStorage:
        数据会永久保存
        在所有标签页中共享
        除非手动清除,否则数据会一直存在
        所以 v_p2 和 v_p3 不会重置

5.6 quartz3

01.网站加速,halavah.us,github -> vercel -> cloudflare -> cdn(vercel.cdn.yt-blog.top)
    a.汇总
        a.DNS说明
            记录类型    解释
            A          用来指定域名的 IPv4 地址(如 8.8.8.8),如果需要将域名指向一个 IP 地址,就需要添加 A 记录。
            CNAME      如果需要将域名指向另一个域名,再由另一个域名提供 IP 地址,就需要添加 CNAME 记录。
            MX         如果需要设置邮箱,让邮箱能收到邮件,就需要添加 MX 记录。
            TXT        在这里可以填写任何东西,长度限制 255。绝大多数的 TXT 记录是用来做 SPF 记录(反垃圾邮件)
            NS         域名服务器记录,如果需要将子域名交给其他 DNS 服务商解析,就需要添加 NS 记录。
            AAAA       用来指定主机名(或域名)对应的 IPv6 地址(例如:ff06:0:0:0:0:0:0:c3)记录。
            SRV        记录了哪台计算机提供了哪个服务。格式为:服务的名字、点、协议的类型,例如:_xmpp-server_tcp。
            显性URL    从一个地址 301 重定向到另一个地址的时候,就需要添加显性 URL 记录(注:DNSPod 目前只支持 301 重定向)。
            隐性URL    类似于显性 URL,区别在于隐性 URL 不会改变地址栏的域名。
        b.HTTPS爆红
            当你访问一个 HTTPS URL(例如 https://172.17.10.80/)时,如果浏览器显示“爆红”警告(通常是一个红色的警告页面),这通常是因为存在以下几种常见的 SSL/TLS 证书问题:
            自签名证书:服务器使用的是自签名证书,而不是由受信任的证书颁发机构(CA)签发的证书。浏览器默认不信任自签名证书,因此会显示警告。
            证书过期:服务器的 SSL/TLS 证书已经过期。证书有一个有效期,如果超过了这个有效期,浏览器会认为证书不再安全。
            证书不匹配:证书的域名与访问的域名不匹配。例如,证书是为 example.com 签发的,但你访问的是 172.17.10.80。这种情况下,浏览器会认为证书不可信。
            证书被吊销:证书被证书颁发机构吊销。浏览器会检查证书的吊销状态,如果证书被吊销,浏览器会显示警告。
            证书链问题:证书链不完整或不正确。浏览器需要验证证书链中的所有证书,如果链中的任何一个证书无效或缺失,浏览器会显示警告。
        c.注意事项
            IP证书
            邮件服务器([email protected])
            域名解析跟DNS全球服务器有关系,和哪里来的域名没关系
    b.vercel
        a.添加二级域名
            https://vercel.com/halavahs-projects/valut/settings/domains
            valut.halavah.us
            -----------------------------------------------------------------------------------------------------
            CNAME (Recommended)
            Nameservers
            Set the following record on your DNS provider to continue:
            Type     Name   Value
            CNAME    valut  cname.vercel-dns.com.
        b.域名解析地址
            Vercel 官方默认线路:cname.vercel.com
            Vercel 官方对大陆优化线路: cname-china.vercel-dns.com
            Fgaoxing 提供针对 Vercel 优选的 DNS 线路:vercel.cdn.yt-blog.top
        c.示例
            一级域名 (example.com):
            名称:@
            类型:A
            IP:1.2.3.4
            -------------------------------------------------------------------------------------------------
            二级域名 (blog.example.com):
            名称:blog
            类型:A
            IP:1.2.3.4
            -------------------------------------------------------------------------------------------------
            泛解析 (*.example.com)
            名称:*
            类型:A
            IP:1.2.3.4
    c.CloudFlare
        a.第1步:仅DNS,是为了通过DNS记录,来验证vercel
            使用https://vercel.com/halavahs-projects/valut2/settings/domains查看解析情况
            -------------------------------------------------------------------------------------------------
            类型      名称        内容                      TTL       代理状态
            CNAME     valut       cname.vercel-dns.com.   仅DNS      自动
            CNAME     valut2      cname.vercel-dns.com.   仅DNS      自动
            CNAME     valut3      cname.vercel-dns.com.   仅DNS      自动
            CNAME     valut-end   cname.vercel-dns.com.   仅DNS      自动
            CNAME     picgo       cname.vercel-dns.com.   仅DNS      自动
        b.第2步:使用Fgaoxing提供的DNS线路
            类型      名称        内容                      TTL       代理状态
            CNAME     valut       vercel.cdn.yt-blog.top   仅DNS      自动
            CNAME     valut2      vercel.cdn.yt-blog.top   仅DNS      自动
            CNAME     valut3      vercel.cdn.yt-blog.top   仅DNS      自动
            CNAME     valut-end   vercel.cdn.yt-blog.top   仅DNS      自动
            CNAME     picgo       vercel.cdn.yt-blog.top   仅DNS      自动
        c.第3步:开启CDN代理
            类型      名称        内容                      TTL       代理状态
            CNAME     valut       vercel.cdn.yt-blog.top   已代理      自动
            CNAME     valut2      vercel.cdn.yt-blog.top   已代理      自动
            CNAME     valut3      vercel.cdn.yt-blog.top   已代理      自动
            CNAME     valut-end   vercel.cdn.yt-blog.top   已代理      自动
            CNAME     picgo       vercel.cdn.yt-blog.top   已代理      自动
            -------------------------------------------------------------------------------------------------
            SSL/TLS
            完全(严格)
        d.说明
            如果使用 Cloudflare 代理(橙色云朵),需要在 Cloudflare 中专门设置端口转发
            建议将代理状态设置为关闭(灰色云朵),这样可以直接访问原始端口
            Cloudflare 免费版本只支持特定的端口(如 80、443 等),对于 28575 这样的非标准端口,需要关闭 Cloudflare 代理
    d.访问
        a.备案
            【晋ICP备2025056343号】->quartz/util/verifyPage.ts
            【苏ICP备19059396号-1】->quartz/components/Footer.tsx
        b.链接
            https://valut.halavah.us            https://valut.vercel.app
            https://valut2.halavah.us           https://valut2.vercel.app
            https://valut3.halavah.us           https://valut3-sand.vercel.app
            https://valut-end.halavah.us        https://quartz-end.vercel.app
            https://picgo.halavah.us            https://picgo-pi.vercel.app
            https://tree.halavah.us             pintree-taupe-gamma.vercel.app
            https://cursor-api.halavah.us       https://cursor-api-halavahs-projects.vercel.app/
            -------------------------------------------------------------------------------------------------
            https://api.halavah.us
            https://chat.halavah.us
            https://nextra.halavah.us
        c.链接
            http://119.91.252.124:83/verify?token=troyekk
            api.kafuchino.online
            chat.kafuchino.online
            test.kafuchino.online
            valut.kafuchino.online
            valut2.kafuchino.online
            valut3.kafuchino.online
            -------------------------------------------------------------------------------------------------
            myslayers.top:2025-03-30至2035-03-30
            api.myslayers.top
            chat.myslayers.top
            test.myslayers.top
            valut.myslayers.top
            valut2.myslayers.top
            valut3.myslayers.top
            -------------------------------------------------------------------------------------------------
            ngrok.myslayers.top           100.64.0.8:48080
            ngrok-ui.myslayers.top        100.64.0.8:83
            -------------------------------------------------------------------------------------------------
            nat.myslayers.top             100.64.0.8:48080
            nat-ui.myslayers.top          100.64.0.8:83

02.日常维护
    a.gihtub page
        a.前提
            必须仓库为公有public
        b.不使用Action
            settings -> pages -> Build and deployment -> Deploy from a branch -> master、/docs
        c.使用Action
            .github/workflows/deploy.yml,该文件指定构建目录,如public;指定构建分支,如master
            settings -> pages -> Build and deployment -> GitHub Actions
            GitHub Actions -> 查看构建情况
    b.发布99.Directory01到valut
        a.public
            baseUrl: "halavah.github.io/valut",注意,不能设置为【halavah.github.io/99.Directory01】,有数字+小数点,会当作一个域
            public必须上传,而且内容不能为空,否则空文件夹无法上次github
        b.git上传前,必须生成public内容
            start.bat(npx quartz build --serve)
            git add . && git commit -m "my first commit" && git commit --amend -m "新的提交注释"
            git push origin master
            -------------------------------------------------------------------------------------------------
            git tag v1.0 && git push origin v1.0
        c.常用提交
            git clone https://github.com/halavah/valut.git 99.Directory01
            git clone https://github.com/halavah/valut2.git 99.Directory02
            git clone https://github.com/halavah/valut3.git 99.Directory03
            -------------------------------------------------------------------------------------------------
            git add . && git commit -m "20241222"
            git push origin master
            -------------------------------------------------------------------------------------------------
            git tag 20241222
            git push origin 20241222
            -------------------------------------------------------------------------------------------------
            git tag
            git tag -d 标签名
            -------------------------------------------------------------------------------------------------
            git branch                                                                --查看分支
            git status                                                                --查看状态
            git log --oneline                                                         --查看提交日志
            git reset --soft HEAD"^"                                                  --返回上一个commit状态,并保留当前修改的文件
            git push --force origin master                                            --忽略远程版本,强制提交
        d.定版提交
            git add . && git commit -m "v9.1_正式版本"
            git push origin master
            git tag v9.1_正式版本
            git push origin v9.1_正式版本
            -------------------------------------------------------------------------------------------------
            git add . && git commit -m "v9.2_校验nextjs适应国内外环境"
            git push origin master
            git tag v9.2_校验nextjs适应国内外环境
            git push origin v9.2_校验nextjs适应国内外环境
            -------------------------------------------------------------------------------------------------
            git add . && git commit -m "v10_适应子模块,vercel线上编译"
            git push origin master
            git tag v10_适应子模块,vercel线上编译
            git push origin v10_适应子模块,vercel线上编译
    c.修改忽略文件
        a.文件名:.gitignore
            node_modules

            .obsidian
            .obsidian_android
            .trash
            _assets/

            Chapter01/Quick.assets/
            Chapter01/Ready.assets/
            Chapter01/Remote.assets/
            Chapter01/StartUp.assets/
            Chapter02/Build.assets/
            Chapter02/Deploy.assets/
            Chapter02/Internet.assets/
            Chapter03/Balance.assets/
            Chapter03/Growth.assets/
            Chapter03/Symbol.assets/
            Chapter03/Traffic.assets/
        b.将原先Chapter01/Quick.assets/脱离版本控制
            git rm -r --cached "Chapter01/Quick.assets/"
            git rm -r --cached "Chapter01/Ready.assets/"
            git rm -r --cached "Chapter01/Remote.assets/"
            git rm -r --cached "Chapter01/StartUp.assets/"
            git rm -r --cached "Chapter02/Build.assets/"
            git rm -r --cached "Chapter02/Deploy.assets/"
            git rm -r --cached "Chapter02/Internet.assets/"
            git rm -r --cached "Chapter03/Balance.assets/"
            git rm -r --cached "Chapter03/Growth.assets/"
            git rm -r --cached "Chapter03/Symbol.assets/"
            git rm -r --cached "Chapter03/Traffic.assets/"
        c.注意
            .gitignore 添加 **/*.assets/                                   --失效
            git rm -r --cached "**/*.assets/"                              --失效

03.vercel部署
    a.普通部署content
        a.Framework Preset
            Other
        b.Root Directory
            空,代表根目录
        c.BuildandOutputSettings
            Build Command:npx quartz build --verbose
            Output Directory:public
            Install Command:npm install
            Environment Command:空
        d.EnvironmentVariables
            空
    b.以submodule子模块部署content
        a.参考
            https://stephenweiss.dev/vercel-private-submodules
        b.根目录./gitmodules
            [submodule "content"]
                path = content
                url = [email protected]:halavah/Directory01.git          --以前是https://github.com/halavah/Directory01
        c.git配置:.git/config
            [core]
                repositoryformatversion = 0
                filemode = false
                bare = false
                logallrefupdates = true
                symlinks = false
                ignorecase = true
            [remote "origin"]
                url = [email protected]:halavah/Directory01.git          --以前是https://github.com/halavah/Directory01
                fetch = +refs/heads/*:refs/remotes/origin/*
            [branch "master"]
                remote = origin
                merge = refs/heads/master
                rebase = true
        d.package.json
            "scripts": {
              "quartz": "./quartz/bootstrap-cli.mjs",
              "docs": "npx quartz build --serve -d docs",
              "check": "tsc --noEmit && npx prettier . --check",
              "format": "npx prettier . --write",
              "test": "tsx ./quartz/util/path.test.ts && tsx ./quartz/depgraph.test.ts",
              "profile": "0x -D prof ./quartz/bootstrap-cli.mjs build --concurrency=1"
              "vercel-build": "chmod u+x ./vercel-submodule-workaround.sh && ./vercel-submodule-workaround.sh && npx quartz build --verbose"
            },
        e.vercel
            a.Framework Preset
                Other
            b.Root Directory
                空,代表根目录
            c.BuildandOutputSettings
                Build Command:npm run vercel-build
                Output Directory:public
                Install Command:npm install
                Environment Command:空
            d.EnvironmentVariables
                GITHUB_ACCESS_TOKEN 对应 github的Token值
                设置 -> 开发者设置 -> 个人访问令牌
                生成新令牌
                设置到期日期
                确保检查 Repo 的完全访问权限:[x] repo - Full control of private repositories
        f.vercel-submodule-workaround.sh
            修改如下2点:
            MAIN_REPO       主仓库
            SUBMODULE_PATH  子模块项目路径,注意,不需要填写该 submodule子模块 具体项目路径,会自动读取 .gitmodules
            -------------------------------------------------------------------------------------------------
            # repo paths (supplied without the protocol prefix)
            # 定义主项目仓库地址
            MAIN_REPO=github.com/halavah/valut.git
            # 定义子模块在项目中的路径
            SUBMODULE_PATH=content

            # 检查 Vercel 环境变量 VERCEL_GIT_COMMIT_SHA 是否为空
            if [ "$VERCEL_GIT_COMMIT_SHA" == "" ]; then
              echo "Error: VERCEL_GIT_COMMIT_SHA is empty"
              exit 1
            fi

            # 检查 GITHUB_ACCESS_TOKEN 是否为空
            if [ "$GITHUB_ACCESS_TOKEN" == "" ]; then
              echo "Error: GITHUB_ACCESS_TOKEN is empty"
              exit 1
            fi

            # 遇到错误时停止脚本执行
            set -e

            # 设置一个临时工作目录,并清理之前可能存在的临时文件夹
            rm -rf vercel-tmp || true
            mkdir vercel-tmp
            cd vercel-tmp

            # 初始化一个新的 Git 仓库
            # 检出当前提交
            git init
            # 添加远程仓库地址并包含访问令牌
            git remote add origin https://$GITHUB_ACCESS_TOKEN@$MAIN_REPO
            # 获取指定提交的内容(深度为1以节省资源)
            git fetch --depth=1 origin $VERCEL_GIT_COMMIT_SHA
            # 检出指定提交
            git checkout $VERCEL_GIT_COMMIT_SHA

            # 修改 .gitmodules 文件中的子模块路径
            # 将 SSH 路径替换为 HTTPS 路径,以便使用访问令牌访问子模块
            mv .gitmodules .gitmodules.original
            cat .gitmodules.original | sed "s/[email protected]:/https:\/\/[email protected]\//" > .gitmodules

            # 同步子模块配置并初始化和更新子模块
            # 使用 sed 隐藏日志中可能暴露的访问令牌
            git submodule sync
            git submodule update --init --recursive 2>&1 | sed "s/$GITHUB_ACCESS_TOKEN/\*\*\*\*/"

            # 将子模块内容移动到主项目中定义的位置
            cd ..
            # 删除子模块中的 .git 文件夹(子模块本身是一个独立的 Git 仓库)
            rm -rf vercel-tmp/$SUBMODULE_PATH/.git
            # 如果子模块路径已经存在,则备份原来的内容
            if [ -d $SUBMODULE_PATH ]; then
              mv $SUBMODULE_PATH $SUBMODULE_PATH.original
            fi
            # 创建子模块目标路径的父目录
            mkdir -p $(dirname $SUBMODULE_PATH)
            # 将子模块移动到目标位置
            mv vercel-tmp/$SUBMODULE_PATH/ $SUBMODULE_PATH

            # 显示子模块路径的内容,以验证子模块是否被正确加载
            ls -l $SUBMODULE_PATH

            # 清理临时工作目录
            rm -rf vercel-tmp
    c.更新子仓库
        cd content
        git pull origin main  # 或其他分支名称
        git add .             # 若有更改
        git commit -m "Update content submodule"

04.更改submodule子模块
    查看【startup -> submodule单向:实战操作(定)】

05.自动化脚本
    a.参考
        Quick.assets/9998.vercel 加载私有子模块1.htm
        Quick.assets/9998.vercel 加载私有子模块2.png
        -----------------------------------------------------------------------------------------------------
        https://github.com/halavah/valut主仓库
        https://github.com/halavah/Directory01 子仓库
        [submodule "content"]
            path = content
            url = [email protected]:halavah/Directory01.git
        现在 要求,https://github.com/halavah/Directory01 提交内容后,
        https://github.com/halavah/valut 自动在 remote云端 更新最新内容
        现在的脚本部署在 Directory01 子仓库上,
        -----------------------------------------------------------------------------------------------------
        Windows(CR LF)、Unix(LF)
    b.子仓库,01.Directory01
        a.github/workflows/update-main-repo.yml
            name: Update Main Repo

            on:
              push:
                branches:
                  - master
                paths:
                  - '**'

            jobs:
              update-submodule:
                runs-on: ubuntu-latest

                steps:
                  - name: Checkout main repository
                    uses: actions/checkout@v3
                    with:
                      repository: halavah/valut                                                                                                          --第1处
                      token: ${{ secrets.MY_GITHUB_TOKEN }}
                      fetch-depth: 0

                  - name: Configure Git
                    run: |
                      git config --global user.email "[email protected]"
                      git config --global user.name "myslayers"

                      # 将子模块 URL 改为 HTTPS 格式
                      git config --file=.gitmodules submodule.content.url https://${{ secrets.MY_GITHUB_TOKEN }}@github.com/halavah/Directory01.git      --第2处
                      git submodule sync

                  - name: Update submodule
                    run: |
                      # 初始化并更新子模块
                      git submodule update --init --recursive

                      # 进入子模块目录并更新
                      cd content
                      git checkout master
                      git pull origin master

                      # 返回主仓库目录
                      cd ..

                      # 检查是否有更改
                      if git status | grep -q 'nothing to commit'; then
                        echo "No changes to commit"
                        exit 0
                      fi

                      # 提交更改
                      TIMESTAMP=$(date +'%Y%m%d_%H%M%S')
                      git add content
                      git commit -m "Update submodule reference at $TIMESTAMP"
                      git push https://${{ secrets.MY_GITHUB_TOKEN }}@github.com/halavah/valut.git HEAD:master                                           --第3处
        b.deploy.bat(无需更改)
            @echo off
            setlocal EnableDelayedExpansion

            :: Navigate to the directory where the script is located
            cd /d "%~dp0"

            :: Stage all changes first
            echo Staging all changes...
            git add .
            if !errorlevel! neq 0 (
                echo Failed to stage changes.
                pause
                exit /b 1
            )

            :: Check if there are changes to commit
            git diff --staged --quiet
            if !errorlevel! equ 0 (
                echo No changes to commit.

                :: If no changes, just pull and exit
                echo Pulling latest changes from origin/master...
                git pull origin master
                pause
                exit /b 0
            )

            :: Commit changes with timestamped message
            set "timestamp=%date:~0,4date:~8,2%_%time:~0,2time:~6,2%"
            set "timestamp=!timestamp: =0!"
            echo Committing changes with timestamp: !timestamp!...
            git commit -m "!timestamp!"
            if !errorlevel! neq 0 (
                echo Failed to commit changes.
                pause
                exit /b 1
            )

            :: Pull latest changes from the remote repository
            echo Pulling latest changes from origin/master...
            git pull origin master
            if !errorlevel! neq 0 (
                echo Failed to pull changes. Resolve conflicts if any, and rerun the script.
                pause
                exit /b 1
            )

            :: Push changes to the repository
            echo Pushing changes to origin/master...
            git push origin master
            if !errorlevel! neq 0 (
                echo Failed to push changes.
                pause
                exit /b 1
            )

            echo Changes successfully pulled, committed, and pushed.
            pause
            exit /b 0
    c.主仓库,99.Directory01
        a.github/workflows/deploy.yml
            name: Deploy Quartz site to GitHub Pages
            on:
              push:
                branches:
                  - v4                                                         --修改分支
            permissions:
              contents: read
              pages: write
              id-token: write
            concurrency:
              group: "pages"
              cancel-in-progress: false
            jobs:
              build:
                runs-on: ubuntu-22.04
                steps:
                  - uses: actions/checkout@v4
                    with:
                      fetch-depth: 0 # Fetch all history for git info
                  - uses: actions/setup-node@v4
                    with:
                      node-version: 22
                  - name: Install Dependencies
                    run: npm ci
                  - name: Build Quartz
                    run: npx quartz build
                  - name: Upload artifact
                    uses: actions/upload-pages-artifact@v3
                    with:
                      path: public                                             --构建文件夹
              deploy:
                needs: build
                environment:
                  name: github-pages
                  url: ${{ steps.deployment.outputs.page_url }}
                runs-on: ubuntu-latest
                steps:
                  - name: Deploy to GitHub Pages
                    id: deployment
                    uses: actions/deploy-pages@v4
        b.deploy.bat(无需更改)
            Deploy:
            cd /d "%~dp0"
            git add .
            git diff --staged --quiet
            git commit -m "!timestamp!"
            git pull origin master
            git submodule update --remote --merge
            git push origin master
            -------------------------------------------------------------------------------------------------
            Build
            cd /d "%~dp0content"
            git pull origin master
            cd /d "%~dp0"
            del /q /f "public\*.*"
            for /d i"
            mkdir public
            copy /y ".flag" "public\.flag"
            npm install
            call npx quartz build --verbose
            -------------------------------------------------------------------------------------------------
            Run
            cd /d "%~dp0content"
            git pull origin master
            cd /d "%~dp0"
            del /q /f "public\*.*"
            for /d i"
            mkdir public
            copy /y ".flag" "public\.flag"
            npm install
            call npx quartz build --serve
            -------------------------------------------------------------------------------------------------
            @echo off
            setlocal EnableDelayedExpansion

            :menu
            cls
            echo ====================================
            echo        Git and Build Manager
            echo ====================================
            echo 1. Deploy (Git operations)
            echo 2. Build (Quartz build)
            echo 3. Run (Quartz serve)
            echo 4. Exit
            echo ====================================
            set /p choice="Please enter your choice (1-4): "

            if "%choice%"=="1" goto deploy
            if "%choice%"=="2" goto build
            if "%choice%"=="3" goto run
            if "%choice%"=="4" goto end
            goto menu

            :deploy
            echo.
            echo Starting deployment process...
            :: Navigate to the directory where the script is located
            cd /d "%~dp0"

            :: Stage all changes first
            echo Staging all changes...
            git add .
            if !errorlevel! neq 0 (
                echo Failed to stage changes.
                pause
                goto menu
            )

            :: Check if there are changes to commit
            git diff --staged --quiet
            if !errorlevel! equ 0 (
                echo No changes to commit.

                :: If no changes, update submodule and pull
                echo Pulling latest changes from remote...
                git pull origin master

                echo Updating submodule...
                git submodule update --remote --merge
                pause
                goto menu
            )

            :: Commit local changes first
            set "timestamp=%date:~0,4date:~8,2%_%time:~0,2time:~6,2%"
            set "timestamp=!timestamp: =0!"
            echo Committing changes with timestamp: !timestamp!...
            git commit -m "!timestamp!"
            if !errorlevel! neq 0 (
                echo Failed to commit changes.
                pause
                goto menu
            )

            :: Now pull remote changes
            echo Pulling latest changes from remote...
            git pull origin master
            if !errorlevel! neq 0 (
                echo Failed to pull changes.
                pause
                goto menu
            )

            :: Update submodule
            echo Updating submodule...
            git submodule update --remote --merge
            if !errorlevel! neq 0 (
                echo Failed to update submodule.
                pause
                goto menu
            )

            :: Push changes to the repository
            echo Pushing changes to origin/master...
            git push origin master
            if !errorlevel! neq 0 (
                echo Failed to push changes.
                pause
                goto menu
            )

            echo Changes successfully committed and pushed.
            pause
            goto menu

            :build
            echo.
            echo Starting build process...
            :: Step 1: Navigate to the 'content' directory
            cd /d "%~dp0content"

            :: Step 2: Update submodule by pulling the latest changes
            echo Updating submodule...
            git pull origin master
            if !errorlevel! neq 0 (
                echo Failed to update submodule.
                pause
                goto menu
            )

            :: Step 3: Return to the root directory
            cd /d "%~dp0"

            :: Step 4: Delete all contents in the 'public' folder
            if exist "public" (
                echo Deleting all contents in the 'public' folder...
                del /q /f "public\*.*"
                for /d i"
                echo Deletion completed.
            ) else (
                echo Creating public folder...
                mkdir public
            )

            :: Step 5: Copy .flag file to public folder
            echo Copying .flag file to public folder...
            if exist ".flag" (
                copy /y ".flag" "public\.flag"
                echo .flag file copied successfully.
            ) else (
                echo Warning: .flag file not found in root directory.
            )

            :: Step 6: Check if node_modules exists and install dependencies if needed
            if not exist "node_modules" (
                echo Installing dependencies...
                npm install
                if !errorlevel! neq 0 (
                    echo Failed to install dependencies.
                    pause
                    goto menu
                )
            )

            :: Step 7: Build using Quartz
            echo Building site with Quartz...
            call npx quartz build --verbose
            if !errorlevel! neq 0 (
                echo Failed to build site. Error code: !errorlevel!
                echo Please check if Quartz is properly installed and configured.
                pause
                goto menu
            )

            echo Build completed successfully.
            pause
            goto menu

            :run
            echo.
            echo Starting server...
            :: Step 1: Navigate to the 'content' directory
            cd /d "%~dp0content"

            :: Step 2: Update submodule by pulling the latest changes
            echo Updating submodule...
            git pull origin master
            if !errorlevel! neq 0 (
                echo Failed to update submodule.
                pause
                goto menu
            )

            :: Step 3: Return to the root directory
            cd /d "%~dp0"

            :: Step 4: Delete all contents in the 'public' folder
            if exist "public" (
                echo Deleting all contents in the 'public' folder...
                del /q /f "public\*.*"
                for /d i"
                echo Deletion completed.
            ) else (
                echo Creating public folder...
                mkdir public
            )

            :: Step 5: Copy .flag file to public folder
            echo Copying .flag file to public folder...
            if exist ".flag" (
                copy /y ".flag" "public\.flag"
                echo .flag file copied successfully.
            ) else (
                echo Warning: .flag file not found in root directory.
            )

            :: Step 6: Check if node_modules exists and install dependencies if needed
            if not exist "node_modules" (
                echo Installing dependencies...
                npm install
                if !errorlevel! neq 0 (
                    echo Failed to install dependencies.
                    pause
                    goto menu
                )
            )

            :: Step 7: Run Quartz server
            echo Starting Quartz server...
            call npx quartz build --serve
            if !errorlevel! neq 0 (
                echo Failed to start server. Error code: !errorlevel!
                echo Please check if Quartz is properly installed and configured.
                pause
                goto menu
            )

            echo Server stopped.
            pause
            goto menu

            :end
            echo Goodbye!
            exit /b 0

06.nginx部署
    #user  nobody;
    worker_processes  1;

    #error_log  logs/error.log;
    #error_log  logs/error.log  notice;
    #error_log  logs/error.log  info;

    pid  logs/nginx.pid;

    events {
        worker_connections  1024;
    }

    http {
        include       mime.types;
        default_type  application/octet-stream;

        # 开启访问日志,使用自定义格式
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                         '$status $body_bytes_sent "$http_referer" '
                         '"$http_user_agent" "$http_x_forwarded_for" '
                         '"$proxy_host" "$upstream_addr"';  # 添加代理信息

        #access_log  logs/access.log  main;

        sendfile        on;
        #tcp_nopush     on;

        #keepalive_timeout  0;
        keepalive_timeout  65;

        # 开启gzip压缩
        gzip  on;
        # 设置gzip所需的http协议最低版本 (HTTP/1.1, HTTP/1.0)
        gzip_http_version 1.1;
        # 设置压缩级别,压缩级别越高压缩时间越长  (1-9)
        gzip_comp_level 4;
        # 设置压缩的最小字节数, 页面Content-Length获取
        gzip_min_length 1000;
        # 设置压缩文件的类型  (text/html)
        gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

        server {
            listen       83;
            server_name  localhost;

            #charset koi8-r;
            #access_log  logs/host.access.log  main;

            # verify 页面路由 - 放在最前面处理
            location = /verify {
                root   html/valut3;
                try_files /verify.html =404;
            }

            # 静态网站配置
            location / {
                root   html/valut3;
                index  index.html index.htm;

                # 修改 try_files 配置,添加更严格的路径匹配
                try_files $uri $uri.html $uri/index.html /index.html;

                # 添加重写规则,防止路径重复
                if ($request_uri ~* "^/(.*/)*([^/]+)/\2") {
                    rewrite ^/(.*) /$1 permanent;
                }
            }

            # API 接口代理配置
            location /api/auth {
                # 转发到实际的验证服务器
                proxy_pass http://localhost:3000/api/auth;
                # proxy_pass https://valut-end.halavah.us/api/auth;

                # 代理设置
                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;

                # Cookie 相关设置
                proxy_cookie_path / /;

                # 修改跨域配置 - 允许本地开发环境访问
                set $cors_origin "";
                if ($http_origin ~* "^(http://127\.0\.0\.1:83|http://localhost:83)$") {
                    set $cors_origin $http_origin;
                }

                add_header 'Access-Control-Allow-Origin' $cors_origin always;
                add_header 'Access-Control-Allow-Credentials' 'true' always;
                add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
                add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type' always;

                # 处理 OPTIONS 预检请求
                if ($request_method = 'OPTIONS') {
                    add_header 'Access-Control-Allow-Origin' $cors_origin always;
                    add_header 'Access-Control-Allow-Credentials' 'true' always;
                    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
                    add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type' always;
                    add_header 'Access-Control-Max-Age' 1728000;
                    add_header 'Content-Type' 'text/plain charset=UTF-8';
                    add_header 'Content-Length' 0;
                    return 204;
                }
            }

            # 静态资源缓存配置
            location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2)$ {
                root   html/valut3;
                expires 30d;
                add_header Cache-Control "public, no-transform";

                # 添加重写规则,防止路径重复
                if ($request_uri ~* "^/(.*/)*([^/]+)/\2") {
                    rewrite ^/(.*) /$1 permanent;
                }
            }

            # 错误页面配置
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
        }
    }

07.caddy部署
    a.方案1:caddy转发请求(放弃,得重写JS代码)
        a.前端修改
            // 使用相对路径
            const getApiEndpoint = () => {
              return '/api/auth';  // 让请求先到 Caddy
            };
        b.Caddy代理
            handle /api/auth {
              reverse_proxy https://valut-end.halavah.us
            }
        c.auth.ts验证
            验证 Origin
            处理 CORS
            返回响应
    b.方案2:caddy不转发请求(使用,20250311)
        a.前端修改
            // 使用相对路径
            const getApiEndpoint = () => {
              if (currentHost.includes('83')) {
                // 直接访问验证服务器
                return 'https://valut-end.halavah.us';
              }
            }
        b.Caddy只代理静态请求
            # verify 页面路由
            handle /verify {
                root * /etc/caddy/html/valut3
                try_files /verify.html
                file_server
            }

            # API 接口代理配置
            # handle /api/auth {
            #     reverse_proxy https://valut-end.halavah.us {
            #         header_up Host {http.request.host}
            #         header_up X-Real-IP {remote_host}
            #     }
            # }
        c.auth.ts验证
            验证 Origin
            处理 CORS
            返回响应
    c.方案2:配置过程
        a.quartz\util\verifyPage.ts => 生成到public\verify.html
            const getApiEndpoint = () => {
              const currentHost = window.location.host;
              if (currentHost.includes('halavah')) {
                return 'https://valut-end.halavah.us';
              } else if (currentHost.includes('vercel')) {
                return 'https://quartz-end.vercel.app';
              } else if (currentHost.includes('83')) {
                return 'https://valut-end.halavah.us';         // 配置该内容,会直接调用下面的axios请求
              }
              return 'http://localhost:3000';
            };
            form && form.addEventListener('submit', async (e) => {
              e.preventDefault();
              const password = passwordInput.value;
              try {
                const apiEndpoint = getApiEndpoint();
                const response = await fetch(\`\${apiEndpoint}/api/auth?action=verify\`, {       // axios请求
                  method: 'POST',
                  headers: {
                    'Content-Type': 'application/json',
                  },
                  body: JSON.stringify({ password }),
                  credentials: 'include',
                });
                const data = await response.json();
                if (data.success) {
                  sessionStorage.setItem('v_p1', data.tokens.session);
                  sessionStorage.setItem('v_p2', data.tokens.local);
                  sessionStorage.setItem('v_p3', data.tokens.cookie);

                  const intendedPath = sessionStorage.getItem('intendedPath') || '/';
                  window.location.href = intendedPath;
                } else {
                  throw new Error('Invalid password');
                }
              } catch (error) {
                passwordInput.classList.add('error');
                const errorMessage = document.createElement('div');
                errorMessage.className = 'error-message';
                errorMessage.textContent = 'Incorrect password. Please try again.';
                form.appendChild(errorMessage);
                errorMessage.style.display = 'block';

                setTimeout(() => {
                  passwordInput.classList.remove('error');
                  errorMessage.style.display = 'none';
                }, 3000);
              }
            });
        b.quartz\components\pages\Content.tsx => 生成到public\prescript.js
            const getApiEndpoint = () => {
              const currentHost = window.location.host;
              if (currentHost.includes('halavah')) {
                return 'https://valut-end.halavah.us';
              } else if (currentHost.includes('vercel')) {
                return 'https://quartz-end.vercel.app';
              } else if (currentHost.includes('83')) {
                return 'https://valut-end.halavah.us';         // 配置该内容,会直接调用下面的axios请求
              }
              return 'http://localhost:3000';
            };

            const apiEndpoint = getApiEndpoint();
            const response = await fetch(
              \`\${apiEndpoint}/api/auth?action=check&session=\${encodeURIComponent(part1)}&local=\${encodeURIComponent(part2)}&cookie=\${encodeURIComponent(part3)}\`,
              {
                credentials: 'include',
              }
            );
        c.Caddyfile
            gz.pingx241030.me {
                tls {
                    protocols tls1.2 tls1.3
                    curves x25519
                    alpn http/1.1 h2
                }
                reverse_proxy 100.64.0.4:82
            }

            # 将 :80 改为你的域名
            kafuchino.online {
                # 设置站点目录路径
                root * /usr/share/caddy
                # 启用静态文件服务器
                file_server
                # 如果需要,可以设置反向代理
                # reverse_proxy localhost:8080
                # 或者通过 php-fpm 提供 PHP 站点服务
                # php_fastcgi localhost:9000
            }

            :80 {
                # Set this path to your site's directory.
                root * /usr/share/caddy
                # Enable the static file server.
                file_server
                # Another common task is to set up a reverse proxy:
                # reverse_proxy localhost:8080
                # Or serve a PHP site through php-fpm:
                # php_fastcgi localhost:9000
            }

            :82 {
                reverse_proxy 100.64.0.8:82
            }

            :83 {
                # 开启 Gzip 压缩
                encode gzip {
                    minimum_length 1000
                    match {
                        header Content-Type text/*
                        header Content-Type application/json
                        header Content-Type application/javascript
                        header Content-Type application/xml*
                    }
                }

                # verify 页面路由
                handle /verify {
                    root * /etc/caddy/html/valut3
                    try_files /verify.html
                    file_server
                }

                # API 接口代理配置
                # handle /api/auth {
                #     reverse_proxy https://valut-end.halavah.us {
                #         header_up Host {http.request.host}
                #         header_up X-Real-IP {remote_host}
                #     }
                # }

                # 静态资源处理
                handle {
                    # 静态资源缓存配置
                    @static_files path *.js *.css *.png *.jpg *.jpeg *.gif *.ico *.svg *.woff2
                    handle @static_files {
                        header Cache-Control "public, no-transform, max-age=2592000"
                    }

                    # 根目录配置
                    root * /etc/caddy/html/valut3
                    try_files {path} {path}.html {path}/index.html /index.html
                    file_server
                }

                # 错误页面配置
                handle_errors {
                    root * html
                    rewrite * /50x.html
                    file_server
                }
            }

08.大纲+图谱
    a.原
        a.quartz.layout.ts,34行
            export const defaultContentPageLayout: PageLayout = {
              beforeBody: [
                Component.Breadcrumbs(),
                Component.ArticleTitle(),
                Component.ContentMeta(),
                Component.TagList(),
                Component.MobileOnly(Component.TableOfContents()),
              ],
              left: [
                Component.PageTitle(),
                Component.MobileOnly(Component.Spacer()),
                Component.Search(),
                Component.DesktopOnly(Component.Explorer()),
                Component.DesktopOnly(Component.About()),
                Component.MobileOnly(Component.Darkmode()),
              ],
              right: [
                Component.Graph(),                                                 --开启
                Component.DesktopOnly(Component.TableOfContents()),
                // Component.Backlinks(),
              ],
            }
        b.quartz/components/styles/toc.scss,8行
            .toc {
              display: flex;
              flex-direction: column;

              &.desktop-only {
                max-height: 50%;                                                   --原本为50%
              }
            }
    b.20250321
        a.quartz.layout.ts,34行
            export const defaultContentPageLayout: PageLayout = {
              beforeBody: [
                Component.Breadcrumbs(),
                Component.ArticleTitle(),
                Component.ContentMeta(),
                Component.TagList(),
                Component.MobileOnly(Component.TableOfContents()),
              ],
              left: [
                Component.PageTitle(),
                Component.MobileOnly(Component.Spacer()),
                Component.Search(),
                Component.DesktopOnly(Component.Explorer()),
                Component.DesktopOnly(Component.About()),
                Component.MobileOnly(Component.Darkmode()),
              ],
              right: [
                // Component.Graph(),                                                 --关闭
                Component.DesktopOnly(Component.TableOfContents()),
                // Component.Backlinks(),
              ],
            }
        b.quartz/components/styles/toc.scss,8行
            .toc {
              display: flex;
              flex-direction: column;

              &.desktop-only {
                max-height: 100%;                                                     --变为100%
              }
            }

5.7 textlint

01.安装(pangu.js)(autocorrect)
    cnpm install textlint -g

02.规则包列表
    cnpm install textlint-rule-ja-space-between-half-and-full-width -g

03.使用(默认情况下,只支持.txt和.md的自动检查和修复,其余后缀结尾的文件会被忽略)
    a.将某个文件夹加入textlint管理
        textlint --init
    b.配置.textlintrc
        {
            "filters": {},
            "rules": {
                "ja-space-between-half-and-full-width": {
                    "space": "always"
                }
            }
        }
    c.命令
        textlint .                          --对该目录及子目录下任意文本文件的格式检查
        textlint demo.md                    --具体检查
        textlint --fix demo.md              --具体修复
        textlint *.md                       --模糊检查
        textlint --fix *.md                 --模糊修复

04.其他
    a.只要文件通过文本形式储存,无论其后缀如何,均可以使用textlint进行检查
        {
            "filters": {},
            "rules": {
                "ja-space-between-half-and-full-width": {
                "space": "always"
                }
            },
            "plugins": {
                "@textlint/markdown": {
                    "extensions": [".ipynb"]
                }
            }
        }
    b.白名单和过滤,可以将白名单词汇表allow.json文件添加到配置文件中
        {
            "filters": {
                "whitelist": {
                    "whitelistConfigPaths": [
                    "./allow.json"
                    ]
                }
            }
        }
    c.规则介绍
        textlint-rule-no-dead-link:检查外部链接是否有效
        textlint-rule-max-comma:用于检查一个长句子中限制的短句数量,如果逗号超过设定会进行提示
        textlint-rule-max-number-of-lines:用于检查文档中的行数,如果超出了规定的行数即会进行提示
        textlint-rule-no-exclamation-question-mark:强制修正问号和感叹号的使用

5.8 coding

01.登录
    团队:https://halavah.coding.net/
    邮箱:myslayers163.com
    手机:15135890769
    密码:XXXXXXXXX
    腾讯云:100015247713

02.DevOps项目
    DevOps项目(halavah) -> 持续部署 -> 名称blog、示例仓库、Hexo类型、北京 -> 部署
    DevOps项目(halavah) -> 代码仓库(blog) -> 设置 -> 访问设置 -> 公开源代码
    个人账号 -> 访问令牌 -> 令牌用户名(eTZrRAlbvz)、令牌(8d2ab38b92c68e06c9abb6253c77aa7945a60de4)
    开源代码仓库 -> https://halavah.coding.net/public/

03.Gridea、Publii
    平台          Coding Pages
    域名          https://
    仓库名称      halavah/blog
    分支          master
    仓库用户名     Halavah
    邮箱          [email protected]
    令牌用户名     eTZrRAlbvz
    令牌          8d2ab38b92c68e06c9abb6253c77aa7945a60de4
    CNAME         halavah.buzz

04.Github搜索方式
    in:name React stars:>5000 forks:>3000 language:python pushed:>2020-01-01
    in:readme React stars:>5000 forks:>3000 language:python pushed:>2020-01-01
    in:description React stars:>5000 forks:>3000 language:python pushed:>2020-01-01

5.9 vuepress

01.安装(vuepress 1.8.2)
    yarn add global vuepress

02.配置
    a.package.json
        {
          "name": "docs",
          "version": "1.0.0",
          "main": "index.js",
          "license": "MIT",
          "scripts": {
            "docs:dev": "vuepress dev docs",                --默认
            "docs:build": "vuepress build docs"             --默认
          }
        }
     b./docs/README.md
        # Introduction
        ## 项目介绍
        练习项目:前后端不分离的博客

03.改造后
    a.打开
        cd D:\software_ware\workspace_picgo\vuepress
    b.启动
        git clone [email protected]:halavah/PicGo.git workspace_picgo   --第1步:克隆仓库
        git pull --rebase                                            --第2步:更新仓库
        vuepress dev vuepress --no-cache                             --第3步:查看本地,不会生成docs,支持预览
        vuepress build vuepress                                      --第4步:远程部署,生成docs,无法预览
        git add . && git commit -m 'v1.0' && git push                --第5步:手动提交
        git tag v1.0 && git push origin v1.0                         --第6步:手动提交

04.vercel
    a.Framework Preset
        VuePress
    b.Root Directory
        vuepress
    c.BuildandOutputSettings
        Build Command:vuepress build vuepress
        Output Directory:../docs
        Install Command:yarn add global vuepress
        EnvironmentVariables:vuepress dev vuepress --port $PORT