<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/scripts/pretty-feed-v3.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:h="http://www.w3.org/TR/html4/"><channel><title>DJ王大海</title><description>好运马上就要来了</description><link>https://djdog.cc</link><item><title>批量下载 Cloudflare R2 中的文件</title><link>https://djdog.cc/blog/2025/r2-download</link><guid isPermaLink="true">https://djdog.cc/blog/2025/r2-download</guid><description>使用 Python 脚本批量下载 Cloudflare R2 中的文件</description><pubDate>Fri, 10 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这里给出使用 AWS SDK for Python（Boto3）的示例，以便后续使用。&lt;/p&gt;
&lt;h2&gt;准备工作&lt;/h2&gt;
&lt;p&gt;下载 Boto3 库，这里以 &lt;code&gt;uv&lt;/code&gt; 作为 Python 的包管理器：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;uv add boto3
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;运行脚本&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import boto3
import os

# 显式设置R2的访问凭证和配置
s3_client = boto3.client(
    &apos;s3&apos;,
    aws_access_key_id=&apos;YOUR_ACCESS_KEY&apos;,
    aws_secret_access_key=&apos;YOUR_SECRET_KEY&apos;,
    endpoint_url=&apos;https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com&apos;,
    region_name=&apos;auto&apos;
)

# R2存储桶名称
bucket_name = &apos;YOUR_BUCKET_NAME&apos;

# 本地存储路径
local_dir = &apos;./files&apos;

def download_files(bucket_name, local_dir):
    # 列出存储桶中的所有对象
    response = s3_client.list_objects_v2(Bucket=bucket_name)

    if &apos;Contents&apos; in response:
        for obj in response[&apos;Contents&apos;]:
            file_key = obj[&apos;Key&apos;]
            local_file_path = os.path.join(local_dir, file_key)

            # 创建本地目录
            os.makedirs(os.path.dirname(local_file_path), exist_ok=True)

            # 下载文件
            s3_client.download_file(bucket_name, file_key, local_file_path)
            print(f&apos;Downloaded {file_key} to {local_file_path}&apos;)
    else:
        print(&apos;No files found in the bucket.&apos;)

# 调用下载函数
download_files(bucket_name, local_dir)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中的 &lt;code&gt;YOUR_ACCESS_KEY&lt;/code&gt; 等需要替换成自己所需要的。&lt;/p&gt;</content:encoded><h:img src="/_astro/cloudflare-cover.PCLBwheV.png"/><enclosure url="/_astro/cloudflare-cover.PCLBwheV.png"/></item><item><title>如何知道自己的 Arch Linux 需要哪些 firmware</title><link>https://djdog.cc/blog/2025/arch-firmware</link><guid isPermaLink="true">https://djdog.cc/blog/2025/arch-firmware</guid><description>当然是全都装上</description><pubDate>Fri, 27 Jun 2025 23:45:30 GMT</pubDate><content:encoded>&lt;p&gt;import { Steps } from &apos;astro-pure/user&apos;&lt;/p&gt;
&lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;先在引导器配置中的内核 cmdline 加上：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;dyndbg=&quot;func fw_log_firmware_info +p&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;重启后运行命令：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;journalctl -b | sed -n &apos;s;.*Loaded FW: \(.*\),.*;/usr/lib/firmware/\1.zst;p&apos; | xargs pacman -Qoq | sort -u
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;恢复配置：&lt;/p&gt;
&lt;p&gt;删除掉第一步加上的 &lt;code&gt;dyndbg&lt;/code&gt; 参数，避免产生多余的日志。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;详细步骤&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;修改内核启动参数：&lt;/p&gt;
&lt;p&gt;在引导器配置中（这里以 GRUB 为例），找到内核的 cmdline 配置，进行如下修改：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# GRUB boot loader configuration

GRUB_DEFAULT=0
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR=&quot;Arch&quot;
GRUB_CMDLINE_LINUX_DEFAULT=&quot;loglevel=3 quiet resume=UUID=0c38e0e8-c02a-4e17-8dfa-0e33ea12e457 resume_offset=533760&quot;
GRUB_CMDLINE_LINUX=&quot;dyndbg=&apos;func fw_log_firmware_info +p&apos;&quot; # 添加在这里即可 # [!code ++]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;由于上面的 &lt;code&gt;dyndbg&lt;/code&gt; 参数自带空格和双引号，所以我们把其中的双引号改为单引号确保 GRUB 能够正确解析。&lt;/p&gt;
&lt;p&gt;这将启用内核的动态调试功能，以便记录加载的固件信息。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;更新 GRUB 配置：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo grub-mkconfig -o /boot/grub/grub.cfg
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;重启系统：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo reboot
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;检查内核参数是否正确添加：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cat /proc/cmdline
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在一长串的输出中应该会包含 &lt;code&gt;dyndbg=&apos;func fw_log_firmware_info +p&apos;&lt;/code&gt; 参数。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;运行分析命令：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;journalctl -b | sed -n &apos;s;.*Loaded FW: \(.*\),.*;/usr/lib/firmware/\1.zst;p&apos; | xargs pacman -Qoq | sort -u
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行后预期得到类似于下面这样的输出：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;linux-firmware-amdgpu
linux-firmware-cirrus
linux-firmware-mediatek
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这表示系统加载了这些固件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;恢复内核参数配置：&lt;/p&gt;
&lt;p&gt;删除掉第一步加上的 &lt;code&gt;dyndbg&lt;/code&gt; 参数，避免产生多余的日志。&lt;/p&gt;
&lt;p&gt;然后再次更新 GRUB 配置：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo grub-mkconfig -o /boot/grub/grub.cfg
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下次重启时，内核将不再记录固件加载信息。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;分析命令解释&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;journalctl -b | sed -n &apos;s;.*Loaded FW: \(.*\),.*;/usr/lib/firmware/\1.zst;p&apos; | xargs pacman -Qoq | sort -u
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;获取当前引导的日志，-b参数表示只显示自本次启动以来的日志，这其中就会包含我们通过 `dyndbg` 启用的内核 firmware 加载信息。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2. &lt;code&gt;sed -n &apos;s;.*Loaded FW: \(.*\),.*;/usr/lib/firmware/\1.zst;p&apos;&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;这是整个流程中最核心的文本处理步骤。

sed: 用于对输入的文本进行过滤和转换。
  - -n: 禁止默认输出。sed 通常会打印每一行，-n 告诉它保持安静，只在明确指示时（通过 p 命令）才打印。
  - &apos;s;...;...;p&apos;: 这是 sed 的替换命令。
    - s: 表示替换 (substitute)。
    - ;: 用作分隔符。通常用 /，但这里日志内容可能包含 /，所以用 ; 是个好习惯。
    - .*Loaded FW: \(.*\),.*: 这是要匹配的模式。
    - .*Loaded FW:  匹配任何字符 (.*) 直到 &quot;Loaded FW: &quot; 这个固定的字符串。
    - \(.*\) 是一个捕获组。它匹配并“捕获”（记住）&quot;Loaded FW: &quot; 之后到下一个逗号之前的所有字符。这正是我们想要的固件文件名 (例如 i915/adlp_dmc.bin)。
    - ,.* 匹配文件名后面的逗号以及该行剩余的所有内容。
    - /usr/lib/firmware/\1.zst: 这是替换后的内容。
    - /usr/lib/firmware/ 是 Arch Linux 系统上固件文件的标准路径。
    - \1 是一个反向引用，它会被替换为前面第一个捕获组 \(.*\) 捕获到的内容，也就是固件文件名。
  - p: 表示如果替换成功，就打印替换后的结果。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3. &lt;code&gt;xargs pacman -Qoq&lt;/code&gt;
- xargs: 从标准输入读取内容（这里是 sed 输出的文件路径列表），并将其作为参数传递给另一个命令（这里是 pacman）。
- pacman -Qoq: 查询已安装的软件包。&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;sort -u&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;对输出的行进行排序，并移除重复的行。最终得到一个已排序的系统实际需要的 linux-firmware-* 包列表。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/archlinux/comments/1li9zoa/how_to_know_which_firmware_packages_do_i_need/&quot;&gt;Reddit - How to know which firmware packages do I need? :r/archlinux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="/_astro/windowsserver.BE0Iu2TO.webp"/><enclosure url="/_astro/windowsserver.BE0Iu2TO.webp"/></item><item><title>如何免 Root 使用微x模块“优化”手机微信</title><link>https://djdog.cc/blog/2023/wexposed</link><guid isPermaLink="true">https://djdog.cc/blog/2023/wexposed</guid><description>使用 Shizuku 免 Root 使用微x模块</description><pubDate>Mon, 03 Jul 2023 13:01:42 GMT</pubDate><content:encoded>&lt;p&gt;import { Aside } from &apos;astro-pure/user&apos;&lt;/p&gt;
&lt;p&gt;谨以此文，纪念微x模块，以及表达对作者的感谢。&lt;/p&gt;
&lt;h2&gt;微x模块&lt;/h2&gt;
&lt;p&gt;微x模块是一款的用于微信安卓版的辅助插件，可以实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;防止微信撤回消息&lt;/li&gt;
&lt;li&gt;转发微信聊天里的图片和小视频到朋友圈&lt;/li&gt;
&lt;li&gt;转发语音给朋友&lt;/li&gt;
&lt;li&gt;转发收藏内容&lt;/li&gt;
&lt;li&gt;自动查找僵尸粉&lt;/li&gt;
&lt;li&gt;自动领取红包、转账&lt;/li&gt;
&lt;li&gt;自定义表情最高限额&lt;/li&gt;
&lt;li&gt;等等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但是注意，它也会引起以下问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用自动领红包功能会有极大的封号风险&lt;/li&gt;
&lt;li&gt;使用其他辅助功能也有可能被误杀&lt;/li&gt;
&lt;li&gt;免 Root 使用需要用到 LSPatch 改包，安装后的微信不能被其他应用调起&lt;/li&gt;
&lt;li&gt;待发现&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;前期准备&lt;/h2&gt;
&lt;p&gt;使用模块需要用到 &lt;a href=&quot;https://shizuku.rikka.app/zh-hans/&quot;&gt;Shizuku&lt;/a&gt;、&lt;a href=&quot;https://github.com/LSPosed/LSPatch&quot;&gt;LSPatch&lt;/a&gt;、&lt;a href=&quot;https://modules.lsposed.org/module/com.fkzhang.wechatxposed&quot;&gt;WeXposed&lt;/a&gt; 和版本较低的&lt;a href=&quot;https://weixin.qq.com/&quot;&gt;微信&lt;/a&gt;。这些都可以在我的&lt;a href=&quot;https://pan.djdoge.top/%E8%BD%AF%E4%BB%B6/Android/&quot;&gt;狗盘&lt;/a&gt;里下载到，但是毕竟我个人精力有限，没办法实时对狗盘里的安装包进行更新，所以如果发现这些安装包的版本过低，还是建议从官网上下载。&lt;/p&gt;
&lt;p&gt;将 Shizuku、LSPatch、Wexposed 安装到手机上，刚刚下载的微信安装包暂时不用安装，记住它下载到的路径即可。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://shizuku.rikka.app/zh-hans/guide/setup/&quot;&gt;Shizuku&lt;/a&gt; 提供了三种启动方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;通过 root 启动&lt;/li&gt;
&lt;li&gt;通过无线调试启动&lt;/li&gt;
&lt;li&gt;通过连接电脑启动&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我们这里推荐使用第二种或第三种方式，但如果在后续的安装时遇到了&lt;code&gt;INSTALL_FAILED_UPDATE_INCOMPATIBLE: Existing package com.xxxx.xxxx signatures do not match newer version; ignoring!&lt;/code&gt; 的提示，就只能使用第三种方式了。而第三种方式就需要在电脑上安装&lt;a href=&quot;https://developer.android.google.cn/studio/command-line/adb?hl=zh-cn&quot;&gt;Android 调试桥 (adb)&lt;/a&gt;了。&lt;/p&gt;
&lt;h3&gt;通过无线调试启动 Shizuku&lt;/h3&gt;
&lt;p&gt;通过无线调试启动适用于 Android 11 或以上版本。这种启动方式无需连接电脑。由于系统限制，每次重新启动后都需要再次进行启动步骤。&lt;/p&gt;
&lt;h4&gt;启动无线调试&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;在网络上搜索如何为您的机型启用“开发者选项”（以下图示均以 One UI 5.1 为例）&lt;/li&gt;
&lt;li&gt;启用“开发者选项”和“USB 调试”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;./wireless_debugging.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;进入并启用“无线调试”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;./wireless_debugging2.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h4&gt;配对（只需一次）&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;在 Shizuku 内开始配对&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;./Shizuku-pairing.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://vaoo.cc/blog/2023/wexposed#%E5%90%AF%E5%8A%A8%E6%97%A0%E7%BA%BF%E8%B0%83%E8%AF%95&quot;&gt;启用无线调试&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;点按“无线调试”中的“使用配对码配对设备”&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;./wireless_debugging2.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;在 Shizuku 的通知中填入配对码&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;./pairing-code.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h4&gt;启动 Shizuku&lt;/h4&gt;
&lt;p&gt;如果无法启动，尝试禁用并重新启用无线调试。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./run-shizuku.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;通过连接电脑启动&lt;/h3&gt;
&lt;p&gt;该启动方式适用于未 root 且运行 Android 10 及以下版本的设备。很不幸，该启动方式需要连接电脑。由于系统限制，每次重新启动后都需要再次进行启动步骤。&lt;/p&gt;
&lt;h4&gt;什么是Android 调试桥 (adb)&lt;/h4&gt;
&lt;p&gt;Android 调试桥 (&lt;code&gt;adb&lt;/code&gt;) 是一个通用命令行工具，其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利，如安装和调试应用，并提供对 Unix shell（可用来在模拟器或连接的设备上运行各种命令）的访问。&lt;/p&gt;
&lt;h4&gt;Android 调试桥 (adb)的安装&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;下载由 Google 提供的“SDK 平台工具”并解压至任意文件夹&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dl.google.com/android/repository/platform-tools-latest-windows.zip&quot;&gt;Windows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dl.google.com/android/repository/platform-tools-latest-linux.zip&quot;&gt;Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dl.google.com/android/repository/platform-tools-latest-darwin.zip&quot;&gt;Mac&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;打开文件夹，右键选择&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows 10：在此处打开 PowerShell 窗口（需要按住 Shift 才会显示该选项）&lt;/li&gt;
&lt;li&gt;Windows 7：在此处打开命令行窗口（需要按住 Shift 才会显示该选项）&lt;/li&gt;
&lt;li&gt;Mac 或 Linux：打开 Terminal（终端）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;输入 adb 如果可以看到一长串内容而不是提示找不到 adb 则表示成功&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;设置 adb&lt;/h4&gt;
&lt;p&gt;要使用 adb 你首先需要在设备上打开 USB 调试功能，通常需要经过以下步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开系统设置，进入关于&lt;/li&gt;
&lt;li&gt;连续数次点击 &quot;Build number&quot; 后看到类似 &quot;You are a developer&quot; 的提示&lt;/li&gt;
&lt;li&gt;此时你应该可以在设置中找到“开发者选项”，进入后开启“USB 调试”&lt;/li&gt;
&lt;li&gt;连接设备到电脑，在终端中输入 adb devices&lt;/li&gt;
&lt;li&gt;此时设备上会出现“是否允许调试”的对话框，勾选“总是允许”后确认&lt;/li&gt;
&lt;li&gt;再次在终端中输入 adb devices，如无问题将会看到类似如下内容&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;List of devices attached
XXX      device
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;启动 Shizuku&lt;/h4&gt;
&lt;p&gt;复制下面指令并粘贴到终端中，如无问题你将会在 Shizuku 中看到已启动成功。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;adb shell sh /sdcard/Android/data/moe.shizuku.privileged.api/start.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;常见问题&lt;/h4&gt;
&lt;p&gt;通过无线调试启动/通过连接电脑启动：adb 权限受限
ColorOS（OPPO &amp;#x26; OnePlus）：
在“开发者选项”中关闭“权限监控”。&lt;/p&gt;
&lt;h2&gt;备份聊天记录&lt;/h2&gt;
&lt;p&gt;通过微信自带的备份就可以，把需要留下的记录备份到电脑，很简单不作赘述，写在这里就是怕有人会忘记。&lt;/p&gt;
&lt;h2&gt;修补微信并安装&lt;/h2&gt;
&lt;p&gt;Shizuku 成功启动后，打开 LSPatch。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在下面选择从左数第二个选项卡&lt;code&gt;管理&lt;/code&gt;，点击加号新建修补。
从弹出的选项中选择&lt;code&gt;从存储目录中选择（多个）apk&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;./LSPatch-new-patch.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;在文件管理器里找到刚刚下载的旧版微信的安装包&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;修补模式选择便携模式&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;./portable-mode.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;并点击&lt;code&gt;嵌入模块&lt;/code&gt;，勾选微x模块，点击 √ 确认&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./select-app.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;开始修补后点击安装&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;教程结束&lt;/h2&gt;
&lt;p&gt;安装后，正常登录微信。在&lt;code&gt;我 - 设置&lt;/code&gt;里既可找到微x模块的设置，按照自己的喜好进行配置就可以了。&lt;/p&gt;</content:encoded><h:img src="/_astro/微信.CJsmoei9.png"/><enclosure url="/_astro/微信.CJsmoei9.png"/></item><item><title>使用 UV 来管理使用 Python</title><link>https://djdog.cc/blog/2024/uv-python</link><guid isPermaLink="true">https://djdog.cc/blog/2024/uv-python</guid><description>UV 简明入门指南</description><pubDate>Thu, 12 Dec 2024 22:46:45 GMT</pubDate><content:encoded>&lt;p&gt;import { Aside } from &apos;astro-pure/user&apos;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;uv&lt;/code&gt; 是由 Astral 开发的一个极其快速的 Python 包和项目管理工具，使用 Rust 编写。它旨在统一和简化 Python 的包管理、项目管理、Python 版本管理等多个方面，提供类似于 Rust 语言中 &lt;code&gt;Cargo&lt;/code&gt; 的功能。&lt;/p&gt;
&lt;h2&gt;主要功能&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;包管理&lt;/strong&gt;：&lt;code&gt;uv&lt;/code&gt; 可以替代 &lt;code&gt;pip&lt;/code&gt;、&lt;code&gt;pip-tools&lt;/code&gt; 等工具，提供更高效的包安装和解析功能，速度提升可达 10 至 100 倍。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;项目管理&lt;/strong&gt;：支持使用 &lt;code&gt;pyproject.toml&lt;/code&gt; 文件管理项目依赖，生成跨平台的锁定文件，确保项目环境的一致性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工具管理&lt;/strong&gt;：类似于 &lt;code&gt;pipx&lt;/code&gt;，&lt;code&gt;uv&lt;/code&gt; 可以在隔离的虚拟环境中安装和运行命令行工具，并支持一次性运行无需显式安装的命令。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Python 版本管理&lt;/strong&gt;：&lt;code&gt;uv&lt;/code&gt; 能够安装和管理不同版本的 Python，支持快速切换，简化 Python 版本的管理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;脚本支持&lt;/strong&gt;：&lt;code&gt;uv&lt;/code&gt; 可以管理带有内联依赖元数据的单文件脚本，确保脚本在隔离的环境中运行，避免依赖冲突。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;安装方法&lt;/h2&gt;
&lt;h3&gt;独立安装程序&lt;/h3&gt;
&lt;p&gt;Mac 和 Linux：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;curl -LsSf https://astral.sh/uv/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Windows：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;powershell -ExecutionPolicy ByPass -c &quot;irm https://astral.sh/uv/install.ps1 | iex&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;包管理器安装&lt;/h3&gt;
&lt;p&gt;在 Windows 上更推荐使用 Scoop 来进行安装：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;scoop install uv
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果不知道什么是 scoop 可以通过&lt;a href=&quot;https://djdog.cc/blog/2024/scoop-win&quot;&gt;这篇文章&lt;/a&gt;来了解。&lt;/p&gt;
&lt;p&gt;除了上面的方式以外，&lt;code&gt;uv&lt;/code&gt; 还可以通过 &lt;code&gt;PyPI&lt;/code&gt; 安装：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;pipx install uv # 装到隔离环境里
pip install uv
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;使用指南&lt;/h2&gt;
&lt;h3&gt;Python 版本管理&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;查看支持的 Python 版本&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;使用以下命令可以查看 &lt;code&gt;uv&lt;/code&gt; 支持的 Python 版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;uv python list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这将显示可用的 Python 版本列表，包括不同的主次版本。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;安装特定版本的 Python&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;使用以下命令安装特定版本的 Python，例如安装 Python 3.13：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;uv python install 3.13
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这会下载并安装 Python 3.11 到 &lt;code&gt;uv&lt;/code&gt; 的管理路径中。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;切换 Python 版本&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;使用以下命令切换到某个已经安装的 Python 版本，例如 Python 3.13：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;uv python pin 3.13
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;项目管理&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;初始化一个新项目&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;可以通过以下命令初始化一个名为 &lt;code&gt;my_project&lt;/code&gt; 的项目&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;uv init my_project
cd my_project
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以得到一个这样的文件夹：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;❯ tree  
.  
├── hello.py  
├── pyproject.toml  
└── README.md
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中 &lt;code&gt;pyproject.toml&lt;/code&gt; 是这个 Python 项目中的配置文件，可以包含以下内容：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;[build-system]&lt;/strong&gt;: 定义构建项目所需的系统和工具。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[tool]&lt;/strong&gt;: 配置各种工具的选项，如格式化工具、测试工具等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[project]&lt;/strong&gt;: 描述项目的元数据，如项目名称、版本、描述等。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;添加依赖&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;以添加依赖 &lt;code&gt;requests&lt;/code&gt; 为例：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# 默认安装最新版本的依赖
uv add requests

# 安装指定版本的依赖
uv add requests@1.0.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个命令会在 &lt;code&gt;pyproject.toml&lt;/code&gt; 中的 &lt;code&gt;dependencies&lt;/code&gt; 部分添加类似以下内容：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;[project]
name = &quot;my-project&quot;
version = &quot;0.1.0&quot;
description = &quot;Add your description here&quot;
readme = &quot;README.md&quot;
requires-python = &quot;&gt;=3.13&quot;
dependencies = [
    &quot;requests&gt;=2.32.3&quot; # [!code ++]
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当从已有的 &lt;code&gt;pyproject.toml&lt;/code&gt; 恢复环境时，则需运行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;uv sync
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;删除依赖&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;以删除依赖 &lt;code&gt;requests&lt;/code&gt; 为例：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;uv remove requests
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;运行项目&lt;/h3&gt;
&lt;p&gt;以演示中所创建的 &lt;code&gt;my_project&lt;/code&gt; 为例：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;uv run hello.py
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="/_astro/python-cover.B0z3k3Fe.avif"/><enclosure url="/_astro/python-cover.B0z3k3Fe.avif"/></item><item><title>通过容器搭建伪分布式 Hadoop 环境</title><link>https://djdog.cc/blog/2025/hadoop-podman</link><guid isPermaLink="true">https://djdog.cc/blog/2025/hadoop-podman</guid><description>更加方便快捷地构建 Hadoop 环境</description><pubDate>Fri, 04 Apr 2025 20:25:54 GMT</pubDate><content:encoded>&lt;p&gt;import { GithubCard } from &apos;astro-pure/advanced&apos;
import { Collapse } from &apos;astro-pure/user&apos;&lt;/p&gt;
&lt;p&gt;Hadoop 是一个开源框架，它使用分布式存储和并行处理来管理和处理大量数据。它主要用于解决海量数据的存储与计算问题。这里演示一下如何在 Podman 容器中简单地部署 Hadoop 环境。&lt;/p&gt;
&lt;h2&gt;Podman 的安装&lt;/h2&gt;
&lt;p&gt;Podman 背靠 Redhat，各大发行版的仓库中几乎都有，所以直接用包管理器安装即可。&lt;/p&gt;
&lt;p&gt;但由于 Podman 在拉取镜像时，不能省略前面的 &lt;code&gt;docker.io/&lt;/code&gt; 前缀，每次都手动添加当然也是可以的，但这里还是推荐在 podman config file 里设置好。&lt;/p&gt;
&lt;p&gt;修改全局或是用户的 config file：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo nvim /etc/containers/registries.conf # 全局
nvim ~/.config/containers/registries.conf # 用户
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;新增如下内容：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;unqualified-search-registries = [&quot;docker.io&quot;] # [!code ++]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;由于一些众所周知的原因，目前 Docker 的国内代理都不是很稳定，本文就不进行相关的配置了。&lt;/p&gt;
&lt;h2&gt;构建镜像&lt;/h2&gt;
&lt;p&gt;克隆仓库：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git clone https://github.com/Invisibox/Hadoop-docker-compose.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;项目树状结构如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;❯ tree
.
├── config
│   ├── hadoop
│   │   ├── core-site.xml
│   │   ├── hadoop-env.sh
│   │   ├── hdfs-site.xml
│   │   └── workers
│   └── hbase
│       ├── hbase-env.sh
│       └── hbase-site.xml
├── Containerfile
├── docker-compose.yml
├── LICENSE
├── README.md
└── scripts
    └── entrypoint.sh

5 directories, 11 files
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Containerfile&lt;/code&gt; 内容如下，可根据自身需求进行修改：&lt;/p&gt;
&lt;h1&gt;环境变量：非交互安装&lt;/h1&gt;
&lt;p&gt;ENV DEBIAN_FRONTEND=noninteractive&lt;/p&gt;
&lt;h1&gt;更新并安装基础依赖&lt;/h1&gt;
&lt;h1&gt;1. openssh-server：SSH服务&lt;/h1&gt;
&lt;h1&gt;2. openjdk-8-jdk：Java 8（Hadoop通常与Java 8配合得更好）&lt;/h1&gt;
&lt;h1&gt;3. vim、curl、wget 等常用工具（可按需添加或删除）&lt;/h1&gt;
&lt;p&gt;RUN apt-get update &amp;#x26;&amp;#x26; &lt;br&gt;
apt-get install -y --no-install-recommends &lt;br&gt;
openssh-server &lt;br&gt;
openjdk-8-jdk &lt;br&gt;
vim &lt;br&gt;
ssh &lt;br&gt;
rsync &lt;br&gt;
curl &lt;br&gt;
wget &lt;br&gt;
&amp;#x26;&amp;#x26; rm -rf /var/lib/apt/lists/*&lt;/p&gt;
&lt;h1&gt;设置 JAVA_HOME&lt;/h1&gt;
&lt;p&gt;ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64&lt;/p&gt;
&lt;h1&gt;创建运行Hadoop的用户 hadoop，并设置家目录&lt;/h1&gt;
&lt;p&gt;RUN useradd -m -s /bin/bash hadoop&lt;/p&gt;
&lt;h1&gt;设置 hadoop 用户的环境变量&lt;/h1&gt;
&lt;p&gt;RUN echo &apos;export HADOOP_HOME=/usr/local/hadoop&apos; &gt;&gt; /home/hadoop/.profile &amp;#x26;&amp;#x26; &lt;br&gt;
echo &apos;export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin&apos; &gt;&gt; /home/hadoop/.profile&lt;/p&gt;
&lt;h1&gt;下载并解压 Hadoop （示例以 3.3.2 为例，链接请自行替换为你需要的版本）&lt;/h1&gt;
&lt;p&gt;WORKDIR /usr/local
RUN wget https://archive.apache.org/dist/hadoop/common/hadoop-3.3.2/hadoop-3.3.2.tar.gz &amp;#x26;&amp;#x26; &lt;br&gt;
tar -xzf hadoop-3.3.2.tar.gz &amp;#x26;&amp;#x26; &lt;br&gt;
mv hadoop-3.3.2 hadoop &amp;#x26;&amp;#x26; &lt;br&gt;
rm -f hadoop-3.3.2.tar.gz&lt;/p&gt;
&lt;h1&gt;设置 Hadoop 环境变量&lt;/h1&gt;
&lt;p&gt;ENV HADOOP_HOME=/usr/local/hadoop
ENV PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin&lt;/p&gt;
&lt;h1&gt;设置 Hadoop 的 JAVA_HOME&lt;/h1&gt;
&lt;p&gt;RUN echo &quot;export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64&quot; &gt;&gt; $HADOOP_HOME/etc/hadoop/hadoop-env.sh&lt;/p&gt;
&lt;h1&gt;准备 SSH 目录，并配置 SSH 无密码登录（在容器内使用 su - hadoop 执行集群脚本）&lt;/h1&gt;
&lt;p&gt;RUN mkdir /var/run/sshd&lt;/p&gt;
&lt;h1&gt;为 hadoop 用户生成 SSH Key 并配置无密码登录&lt;/h1&gt;
&lt;h1&gt;注意：此处只在容器内部无密码互联，真实生产环境下不要用这种方法暴露SSH&lt;/h1&gt;
&lt;p&gt;RUN mkdir -p /home/hadoop/.ssh &amp;#x26;&amp;#x26; &lt;br&gt;
chown -R hadoop:hadoop /home/hadoop/.ssh &amp;#x26;&amp;#x26; &lt;br&gt;
chmod 700 /home/hadoop/.ssh &amp;#x26;&amp;#x26; &lt;br&gt;
&lt;br&gt;
# 以 hadoop 用户身份生成密钥
su - hadoop -c &quot;ssh-keygen -t rsa -P &apos;&apos; -f /home/hadoop/.ssh/id_rsa&quot; &amp;#x26;&amp;#x26; &lt;br&gt;
&lt;br&gt;
# 将公钥加入 authorized_keys
cat /home/hadoop/.ssh/id_rsa.pub &gt;&gt; /home/hadoop/.ssh/authorized_keys &amp;#x26;&amp;#x26; &lt;br&gt;
chmod 600 /home/hadoop/.ssh/authorized_keys&lt;/p&gt;
&lt;h1&gt;拷贝自定义脚本 start.sh 到 /usr/local/bin，并赋予执行权限&lt;/h1&gt;
&lt;p&gt;COPY start.sh /usr/local/bin/start.sh
RUN chmod +x /usr/local/bin/start.sh&lt;/p&gt;
&lt;h1&gt;暴露常见的 Hadoop 端口（可根据需求增减）&lt;/h1&gt;
&lt;h1&gt;22：SSH&lt;/h1&gt;
&lt;h1&gt;9870：NameNode Web UI (Hadoop 3.x)&lt;/h1&gt;
&lt;h1&gt;8088：ResourceManager Web UI&lt;/h1&gt;
&lt;h1&gt;8020 / 9000：HDFS 交互端口&lt;/h1&gt;
&lt;p&gt;EXPOSE 22 9870 8088 8020 9000&lt;/p&gt;
&lt;h1&gt;启动容器默认执行 start.sh&lt;/h1&gt;
&lt;p&gt;CMD [&quot;/usr/local/bin/start.sh&quot;]&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;#x3C;/Collapse&gt;

在 `./scripts` 目录下存有 `entrypoint.sh` 启动脚本，这里可以根据你的实际需求微调：

&amp;#x3C;Collapse title=&apos;entrypoint.sh&apos;&gt;
```sh
#!/bin/bash

# ==========
# start.sh
# ==========

# 1. 如果尚未生成 SSH Host Key，则生成（容器首次启动时需要）
if [ ! -f /etc/ssh/ssh_host_rsa_key ]; then
    ssh-keygen -A
fi

# 2. 启动SSH服务
/usr/sbin/sshd

# 3. 根据配置环境变量设置 Namenode 的存储目录（可自行修改）
#    也可以在 core-site.xml/hdfs-site.xml 配置 dfs.namenode.name.dir = /data/hdfs/namenode
#    这里只是示例做法：如果不存在 VERSION 文件，说明未格式化过，需要进行格式化
HDFS_NAME_DIR=${HDFS_NAME_DIR:-/data/hdfs/namenode}
if [ ! -f &quot;$HDFS_NAME_DIR/current/VERSION&quot; ]; then
    echo &quot;===&gt; Detected namenode not formatted. Now formatting...&quot;
    su - hadoop -c &quot;hdfs namenode -format -force&quot;
fi

# 4. 启动 HDFS 和 YARN
echo &quot;===&gt; Starting HDFS...&quot;
su - hadoop -c &quot;$HADOOP_HOME/sbin/start-dfs.sh&quot;

echo &quot;===&gt; Starting YARN...&quot;
su - hadoop -c &quot;$HADOOP_HOME/sbin/start-yarn.sh&quot;

# 5. （可选）让容器日志输出 Hadoop 日志文件，方便观察
# 如果你习惯在容器里 bash 进入查看日志，也可以改成 tail -f /dev/null
echo &quot;===&gt; Tail Hadoop logs (Press Ctrl+C to stop tail in foreground)...&quot;
tail -F $HADOOP_HOME/logs/*.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;切换到项目目录，下载必要的软件包：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd Hadoop-docker-compose

mkdir -p packages
cd packages

# 下载Java 1.8 JDK
wget https://repo.huaweicloud.com/java/jdk/8u201-b09/jdk-8u201-linux-x64.tar.gz

# 下载Hadoop 3.3.6
wget https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz

# 下载HBase 2.5.11
wget https://mirrors.tuna.tsinghua.edu.cn/apache/hbase/2.5.11/hbase-2.5.11-hadoop3-bin.tar.gz

cd ..
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;构建镜像并启动容器：&lt;/p&gt;
&lt;p&gt;使用 Podman:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;podman-compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或使用 Docker:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;访问服务&lt;/h2&gt;
&lt;p&gt;构建完成后，可通过以下地址访问各服务：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HDFS Web UI: http://localhost:9870&lt;/li&gt;
&lt;li&gt;YARN Web UI: http://localhost:8088&lt;/li&gt;
&lt;li&gt;HBase Web UI: http://localhost:16010&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;运行容器&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;podman exec -it hadoop-hbase bash
# 或
docker exec -it hadoop-hbase bash
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;数据持久化&lt;/h2&gt;
&lt;p&gt;数据通过 Docker volumes 进行持久化：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;hadoop-data: &lt;code&gt;/usr/local/hadoop/tmp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;hbase-data: &lt;code&gt;/usr/local/hbase/data&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;用户信息&lt;/h2&gt;
&lt;p&gt;容器默认使用 hadoop 用户，密码 hadoop，可无密码执行 sudo。&lt;/p&gt;</content:encoded><h:img src="/_astro/hadoop-cover.fcKw1ZzS.webp"/><enclosure url="/_astro/hadoop-cover.fcKw1ZzS.webp"/></item><item><title>微软 Azure 学生免费服务器申请指南</title><link>https://djdog.cc/blog/2025/azure-student</link><guid isPermaLink="true">https://djdog.cc/blog/2025/azure-student</guid><description>Azure 学生订阅里的免费服务器申请避坑指南</description><pubDate>Sun, 06 Apr 2025 15:42:16 GMT</pubDate><content:encoded>&lt;p&gt;微软为学生提供 Azure 的&lt;a href=&quot;https://azure.microsoft.com/zh-cn/free/students&quot;&gt;学生订阅&lt;/a&gt;。其中包含 100 美金的赠金，所以也被大家称作 az100。&lt;/p&gt;
&lt;p&gt;相较于新用户的 200 美金赠金，学生订阅的有效期为 12 个月且可以续期，不需要验证信用卡；但 az200 的赠金有效期只有 30 天，而且需要验证信用卡。在 2025 年 3 月 31 日之前，az200 还是可以在赠金过期前转成按量计费来免费使用 12 个月的服务器的。但是根据微软官方的&lt;a href=&quot;https://azure.microsoft.com/zh-cn/updates/upgrade-to-standard-sku-public-ip-addresses-in-azure-by-30-september-2025-basic-sku-will-be-retired/&quot;&gt;通告&lt;/a&gt;，2025 年 3 月 31 日将停止基本 SKU 的创建，已经创建的将在 9 月 30 日废弃掉。这样就无法将服务器 ip 设为动态，而标准 SKU 的价格则高达 &lt;a href=&quot;https://azure.microsoft.com/zh-cn/pricing/details/ip-addresses&quot;&gt;$0.005/小时&lt;/a&gt;，也就是一年 $43.8。&lt;/p&gt;
&lt;p&gt;不过好在学生订阅的赠金有效期为一整年，续期时还会刷新赠金，如果不打算在 Azure 部署其他服务的话，100 刀的赠金恰好够抵消这一年两台服务器标准 SKU 的租金。&lt;/p&gt;
&lt;h2&gt;学生订阅申请&lt;/h2&gt;
&lt;p&gt;根据微软的&lt;a href=&quot;https://azure.microsoft.com/zh-cn/pricing/offers/ms-azr-0170p/&quot;&gt;学生订阅要求&lt;/a&gt;，申请学生订阅需要满足以下条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;必须经证实已满 18 岁，并且以全日制学生的身份在公认的具有学位颁发资格的两年或四年制教育机构就读。&lt;/li&gt;
&lt;li&gt;必须通过组织的电子邮件地址验证学业状况。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果不满足这些条件的话，就要各显神通了。~~闲鱼~~&lt;/p&gt;
&lt;p&gt;满足以上条件的可以直接在 &lt;a href=&quot;https://azure.microsoft.com/zh-cn/free/students/&quot;&gt;Azure 学生订阅&lt;/a&gt;的网页里申请。&lt;/p&gt;
&lt;h2&gt;创建虚拟机&lt;/h2&gt;
&lt;p&gt;现在的学生免费优惠中包含 Windows服务器 B1、B2pts v2（基于 Arm）和 B2ats v2（基于 AMD）三种架构各 750 小时每月的免费时长，还有Linux 服务器 B1、B2pts v2（基于 Arm）和 B2ats v2（基于 AMD）三种架构各 750 小时每月的免费时长，总共六种机型。但由于免费的硬盘只有两块 64G 的 P6，所以要是不想在硬盘上花钱就只能最多创建两个服务器，在加上上面提过的 SKU 的钱，其实最多就能免费用两台服务器了。&lt;/p&gt;
&lt;p&gt;获得订阅后登录到 &lt;a href=&quot;https://portal.azure.com/#home&quot;&gt;Azure 门户&lt;/a&gt;，点击上面的创建资源，点击虚拟机下面的创建。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://djdog.cc/_image?href=%2F_astro%2Fazure-creat-vps.ChvQjH7V.webp&amp;#x26;w=1280&amp;#x26;h=776&amp;#x26;f=webp&quot; alt=&quot;创建资源&quot;&gt;&lt;/p&gt;
&lt;p&gt;在创建虚拟机界面将订阅改为 &lt;code&gt;Azure for Students&lt;/code&gt;，可用性选项选择&lt;code&gt;无须基础结构冗余&lt;/code&gt;，大小选择 B1、B2pts v2（基于 Arm）和 B2ats v2（基于 AMD）三者之一。区域可以参考 &lt;a href=&quot;https://www.azurespeed.com/Azure/Latency&quot;&gt;Azure Latency Test&lt;/a&gt;](https://www.azurespeed.com/Azure/Latency) 这个网站上的测速结果，选择一个延迟比较低的即可。不过这一步也需要考虑你所部署的服务类型，比如 OpenAI 的相关服务在EastAsia 也就是香港，可能就无法正常运行。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://djdog.cc/_image?href=%2F_astro%2Fvps-creat.CRUL5RGM.webp&amp;#x26;w=846&amp;#x26;h=698&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;硬盘要选择64GiB（P6），避免额外扣费。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://djdog.cc/_image?href=%2F_astro%2Fdisks.GxISvgUm.webp&amp;#x26;w=845&amp;#x26;h=698&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;网络部分，现在已经不能选择基本 SKU 了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://djdog.cc/_image?href=%2F_astro%2Fnetwork.Cqkmj7Ji.webp&amp;#x26;w=1280&amp;#x26;h=698&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;连接到服务器&lt;/h2&gt;
&lt;p&gt;这里以 Linux 服务器为例，创建过程中，会下载到一个&lt;code&gt;*.pem&lt;/code&gt;，第一次连接可以将该文件移动到 &lt;code&gt;~/.ssh/&lt;/code&gt; 下，然后使用下面的命令连接到服务器。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh -i .\.ssh\密钥文件名.pem 用户名@公网IP地址
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后可以参考这篇文章：&lt;a href=&quot;https://djdog.cc/blog/2024/sshkey&quot;&gt;SSH-keygen 用法 • DJ王大海&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;生成一个本机的 SSH key，将其添加到服务器的 &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; 中，实现免密登录。&lt;/p&gt;
&lt;p&gt;若需要使用到 &lt;code&gt;root&lt;/code&gt; 权限，可以直接运行 &lt;code&gt;sudo -i&lt;/code&gt; 来切换用户。&lt;/p&gt;
&lt;h2&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://djdog.cc/_image?href=%2F_astro%2Ftks.DacgzpOg.webp&amp;#x26;w=424&amp;#x26;h=180&amp;#x26;f=webp&quot; alt=&quot;🙏&quot;&gt;&lt;/p&gt;</content:encoded><h:img src="/_astro/azure-cover.DLut6zrR.jpg"/><enclosure url="/_astro/azure-cover.DLut6zrR.jpg"/></item><item><title>在特殊日期里把网站变为黑白色</title><link>https://djdog.cc/blog/2024/grayscale</link><guid isPermaLink="true">https://djdog.cc/blog/2024/grayscale</guid><description>在公祭日或其他特殊日子里，将网站变为黑白色以表哀悼</description><pubDate>Thu, 19 Dec 2024 22:30:13 GMT</pubDate><content:encoded>&lt;p&gt;一般为了纪念重要人物或事件、表达悼念、反思历史，一些网站在特定日子会变成黑白色。&lt;/p&gt;
&lt;h2&gt;实现方案&lt;/h2&gt;
&lt;p&gt;这里以这个个人站为例，给出一个简单的 CSS 实现方案。&lt;/p&gt;
&lt;p&gt;直接在网站的 html 文件中的 head 里引入这段代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;#x3C;style&gt;
    html {
      -webkit-filter: grayscale(100%);
      -moz-filter: grayscale(100%);
      -ms-filter: grayscale(100%);
      -o-filter: grayscale(100%);
      filter: grayscale(100%);
      filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
      filter: gray;
    }
  &amp;#x3C;/style&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;补充，感谢评论区&lt;a href=&quot;https://www.tjsky.net&quot;&gt;秋风于渭水&lt;/a&gt;这位朋友，给出了一个能够实现在对应的日期自动变颜色的 JS 实现方案。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;#x3C;body&gt;
&amp;#x3C;!-- 其他 body 内容 --&gt;
	&amp;#x3C;script&gt;
		(function() {
			const e = window.MOURNING_MODEDATE_LIST || [&quot;7/7&quot;, &quot;9/18&quot;, &quot;12/13&quot;];
			window.addEventListener(&quot;load&quot;, function() {
				const n = `${(new Date).getMonth() + 1}/${(new Date).getDate()}`;
				e.some(e =&gt; e === n) &amp;#x26;&amp;#x26; (function() {
					if (&apos;grayscale&apos; in document.body.style) {
						// 支持filter的浏览器
						document.body.style.filter = &quot;grayscale(1)&quot;;
					} else { // 旧版IE浏览器
						document.body.style.filter = &apos;progid:DXImageTransform.Microsoft.BasicImage(grayscale=1)&apos;;
					}
				})();
			});
		})();
		if (typeof define === &quot;function&quot; &amp;#x26;&amp;#x26; define.amd) {
			define(e);
		} else {
			e();
		}
	&amp;#x3C;/script&gt;
&amp;#x3C;/body&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;代码中还使用了 &lt;code&gt;window.addEventListener(&quot;load&quot;, ...)&lt;/code&gt;，使这个脚本会在页面完全加载后执行，不会影响页面的加载过程，非常周到。&lt;/p&gt;
&lt;p&gt;不过为了方便后续的维护，还是推荐大家放在外部的 &lt;code&gt;.js&lt;/code&gt; 文件里去 。&lt;/p&gt;
&lt;h2&gt;属性解析&lt;/h2&gt;
&lt;p&gt;其中各个属性分别代表：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;-webkit-filter&lt;/code&gt;&lt;/strong&gt;: 适用于基于 WebKit 的浏览器（如 Chrome、Safari）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;-moz-filter&lt;/code&gt;&lt;/strong&gt;: 适用于 Mozilla 浏览器（如 Firefox）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;-ms-filter&lt;/code&gt;&lt;/strong&gt;: 适用于基于 Microsoft 的浏览器（如老版 Edge）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;-o-filter&lt;/code&gt;&lt;/strong&gt;: 适用于 Opera 浏览器（旧版）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;filter: grayscale(100%)&lt;/code&gt;&lt;/strong&gt;: 标准 CSS 属性，支持现代浏览器，将页面完全转为灰度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);&lt;/code&gt;&lt;/strong&gt;: 针对老版 IE 浏览器的滤镜，启用灰度效果。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;filter: gray;&lt;/code&gt;&lt;/strong&gt;: 旧的非标准灰度实现，部分早期浏览器支持。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果只需要支持现代浏览器，可以仅保留以下代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;filter: grayscale(100%);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;效果图&lt;/h2&gt;
&lt;p&gt;如图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://djdog.cc/_image?href=%2F_astro%2FScreenshot-gray.DPtIuqZp.webp&amp;#x26;w=3882&amp;#x26;h=2124&amp;#x26;f=webp&quot; alt=&quot;实例截图&quot;&gt;&lt;/p&gt;</content:encoded><h:img src="/_astro/memorial.CgHZdG2B.webp"/><enclosure url="/_astro/memorial.CgHZdG2B.webp"/></item><item><title>Firefox 火狐不完全配置手册</title><link>https://djdog.cc/blog/2024/firefox-tweak</link><guid isPermaLink="true">https://djdog.cc/blog/2024/firefox-tweak</guid><description>Firefox 火狐不完全配置手册</description><pubDate>Wed, 03 Apr 2024 22:57:02 GMT</pubDate><content:encoded>&lt;h2&gt;外观修改&lt;/h2&gt;
&lt;h3&gt;ArcWTF&lt;/h3&gt;
&lt;p&gt;2024-12-12 更新，由于 VerticalFox 项目更新频率较低，这里推荐一个类似 &lt;a href=&quot;https://arc.net/&quot;&gt;Arc浏览器&lt;/a&gt; 的主题，而且它的更新方式也更加简单些。&lt;/p&gt;
&lt;p&gt;效果图参照 &lt;a href=&quot;https://github.com/KiKaraage/ArcWTF&quot;&gt;ArcWTF&lt;/a&gt; 项目：&lt;/p&gt;
&lt;h4&gt;安装教程&lt;/h4&gt;
&lt;p&gt;按照作者的&lt;a href=&quot;https://github.com/KiKaraage/ArcWTF?tab=readme-ov-file#applying-the-theme&quot;&gt;安装教程&lt;/a&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;1/3） 安装插件并选择主题&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;安装 &lt;a href=&quot;https://github.com/mbnuqw/sidebery&quot;&gt;Sidebery&lt;/a&gt; 和 &lt;a href=&quot;https://addons.mozilla.org/firefox/addon/userchrome-toggle/&quot;&gt;Userchrome Toggle&lt;/a&gt; 。&lt;/li&gt;
&lt;li&gt;打开 &lt;code&gt;about:addons&lt;/code&gt;，点击 &apos;Userchrome Toggle&apos;，进入 &apos;Options&apos; 选项卡。&lt;/li&gt;
&lt;li&gt;禁用 &apos;Display a notification&apos;，转到 &apos;Style Toggle 1&apos;，将 &lt;code&gt;||&lt;/code&gt; IN 前缀（也应具有结束空格）并应用更改。&lt;/li&gt;
&lt;li&gt;单击扩展按钮（拼图图标），右键单击 Userchrome 切换图标，单击“固定到工具栏”。&lt;/li&gt;
&lt;li&gt;打开 Sidebery 设置，转到样式编辑器并粘贴 &lt;a href=&quot;https://github.com/KiKaraage/ArcWTF/blob/main/sidebery-css-style&quot;&gt;CSS 配置&lt;/a&gt; ，或转到帮助部分并单击导入 &lt;a href=&quot;https://github.com/KiKaraage/ArcWTF/blob/main/sidebery-ArcWTF.json&quot;&gt;我的备份 JSON 文件&lt;/a&gt; 。转到 导航栏 设置，然后添加选项卡面板以根据您的喜好用作空间。 &lt;em&gt;就个人而言，我使用“历史记录”面板作为第一个项目来模拟 Arc 上的“最近关闭”按钮，因此在 CSS 配置上应用自定义图标会更容易。&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;（2/3） 应用 CSS 主题&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;下载 - &lt;a href=&quot;https://github.com/KiKaraage/ArcWTF/archive/refs/heads/main.zip&quot;&gt;适用于 Firefox&lt;/a&gt; ; &lt;a href=&quot;https://github.com/KiKaraage/ArcWTF/archive/refs/heads/floorp.zip&quot;&gt;for Floorp&lt;/a&gt; - 或在本地克隆此存储库&lt;/li&gt;
&lt;li&gt;转到 &lt;code&gt;about:profiles&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;选中“根目录”，然后单击“打开文件夹”/“在 Finder 中显示”&lt;/li&gt;
&lt;li&gt;点击并打开“chrome”文件夹（如果文件夹尚不存在，请创建该文件夹）&lt;/li&gt;
&lt;li&gt;将此存储库中的文件夹和文件粘贴到 chrome 文件夹&lt;/li&gt;
&lt;li&gt;转到 &lt;code&gt;about:config&lt;/code&gt;糊 &lt;code&gt;toolkit.legacyUserProfileCustomizations.stylesheets&lt;/code&gt; 进入栏并将其值设置为 true/选择 布尔值 ，然后单击 +（加号）图标。&lt;/li&gt;
&lt;li&gt;之后，粘贴 &lt;code&gt;svg.context-properties.content.enabled&lt;/code&gt; 进入栏并将其值设置为 true/选择 布尔值 ，然后单击 +（加号）图标。&lt;/li&gt;
&lt;li&gt;重新启动 Firefox&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;（3/3） 如何使用这个主题？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将鼠标悬停在浏览器左上角以显示垂直选项卡。&lt;/li&gt;
&lt;li&gt;右键单击导航工具栏，然后单击 &apos;Customize Toolbar&apos;。将 Userchrome Toggle 按钮移动到左侧位置，在 back-forward-reload 按钮之前。在 URL 栏前后放置灵活的空格。查看下面的屏幕截图以获取指南&lt;/li&gt;
&lt;li&gt;使用 Userchrome Toggle 打开（固定位置）或关闭侧边栏（自动隐藏，悬停显示选项卡）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3&gt;VerticalFox&lt;/h3&gt;
&lt;p&gt;效果图参照 &lt;a href=&quot;https://github.com/christorange/VerticalFox&quot;&gt;VerticalFox&lt;/a&gt; 项目：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://djdog.cc/_image?href=%2F_astro%2Fdark_mode.B-LHLfUH.webp&amp;#x26;w=987&amp;#x26;h=676&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h4&gt;安装教程&lt;/h4&gt;
&lt;p&gt;按照作者的&lt;a href=&quot;https://github.com/christorange/VerticalFox/blob/main/readme_ch.md&quot;&gt;中文安装指南&lt;/a&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;安装 &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/sidebery/&quot;&gt;Sidebery&lt;/a&gt; 插件。&lt;/li&gt;
&lt;li&gt;根据你所使用的操作系统，下载 release 中的压缩包并解压。（如果你熟悉 Firefox 自定义，你可以直接在源码中找到你要的文件）&lt;/li&gt;
&lt;li&gt;在地址栏中输入 &lt;code&gt;about:config&lt;/code&gt; 并前往，接受风险提示。&lt;/li&gt;
&lt;li&gt;搜索 &lt;code&gt;toolkit.legacyUserProfileCustomizations.stylesheets&lt;/code&gt; 并双击设置为 true。&lt;/li&gt;
&lt;li&gt;在地址栏中输入 &lt;code&gt;about:support&lt;/code&gt; 并前往，在 &lt;strong&gt;应用程序概要&lt;/strong&gt; 中找到 &lt;strong&gt;配置文件夹&lt;/strong&gt; 并打开。&lt;/li&gt;
&lt;li&gt;在打开的目录下新建 &lt;code&gt;chrome&lt;/code&gt; 文件夹，名称必须全部小写。&lt;/li&gt;
&lt;li&gt;复制下载好的 &lt;code&gt;userChrome.css&lt;/code&gt; 到 &lt;code&gt;chrome&lt;/code&gt; 文件夹中，重启浏览器。&lt;/li&gt;
&lt;li&gt;打开 Sidebery 的设置，前往 &lt;strong&gt;Styles Editor&lt;/strong&gt;，在右侧复制粘贴 &lt;code&gt;sidebery_styles.css&lt;/code&gt; 中的代码。&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;作者已经写的很清晰了，详情请点击上面的指南链接自行查看，这里不多做赘述。&lt;/p&gt;
&lt;p&gt;如果 Github 访问缓慢，无法下载  release，也可以从&lt;a href=&quot;pan.djdog.cc&quot;&gt;狗盘&lt;/a&gt;中进行下载：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://pan.djdog.cc/%E6%B5%8F%E8%A7%88%E5%99%A8%E6%8B%93%E5%B1%95/mac_VerticalFox_1.4.0.zip&quot;&gt;mac_VerticalFox_1.4.0.zip&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pan.djdog.cc/%E6%B5%8F%E8%A7%88%E5%99%A8%E6%8B%93%E5%B1%95/win_VerticalFox_1.4.0.zip&quot;&gt;win_VerticalFox_1.4.0.zip&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但是可能没有办法及时进行更新，还请大家谅解。&lt;/p&gt;
&lt;p&gt;这里介绍一下什么是 &lt;code&gt;about:config&lt;/code&gt; 、&lt;code&gt;about:support&lt;/code&gt;，以及为什么要在火狐浏览器的配置文件夹下放置 &lt;code&gt;chrome&lt;/code&gt; 文件夹。&lt;/p&gt;
&lt;h3&gt;什么是 about:config&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;about:config&lt;/code&gt; 页面，即配置编辑器。会列出名为“首选项”的 Firefox 设置项目，这些设置从 Firefox 用户配置文件中的 &lt;code&gt;prefs.js&lt;/code&gt; 和 &lt;code&gt;user.js&lt;/code&gt; 文件或程序的默认设置中读取。由于这些首选项属于高级设置项目，它们不会在 &lt;code&gt;设置&lt;/code&gt; 面板中出现。&lt;/p&gt;
&lt;p&gt;换句话说，&lt;code&gt;about:config&lt;/code&gt; 就是一个特殊的设置页面，里面包含了各种高级设置，可以在这里对火狐进行各种设置，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;启用或禁用功能&lt;/strong&gt;： 您可以找到各种功能的开关，从页面加载到 JavaScript 引擎的配置等。通过修改这些设置，您可以自定义浏览器的行为，以满足您的偏好。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网络设置&lt;/strong&gt;： 您可以调整网络相关的参数，例如代理设置、DNS 缓存等。这些设置可以影响浏览器的网络性能和安全性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;界面定制&lt;/strong&gt;： 您可以修改浏览器的外观和行为，例如修改地址栏的默认搜索引擎、更改界面语言等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安全和隐私设置&lt;/strong&gt;： 您可以调整浏览器的安全和隐私设置，例如修改 TLS 版本支持、启用跟踪保护等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高级配置&lt;/strong&gt;： 您还可以找到一些更加高级的设置，例如调整浏览器的性能参数、修改 SSL/TLS 协议的配置等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些功能会在接下来的 性能设置 部分提到，其中的 &lt;code&gt;prefs.js&lt;/code&gt; 和 &lt;code&gt;user.js&lt;/code&gt; 则会在每次火狐启动时被读取，从而自动调整火狐的 &lt;code&gt;about:config&lt;/code&gt; 。&lt;/p&gt;
&lt;h3&gt;什么是 about:support&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;about:support &lt;/code&gt;是火狐浏览器中的另一个特殊页面，提供了有关当前安装的火狐浏览器的详细信息。当访问 &lt;code&gt;about:support&lt;/code&gt; 时，将看到一个包含各种浏览器相关信息的页面。&lt;/p&gt;
&lt;p&gt;其中的 &lt;strong&gt;配置文件夹&lt;/strong&gt; 则是可以看到你当前使用的和已经拥有的火狐的配置文件，我们就可以将 &lt;code&gt;chrome&lt;/code&gt; 文件夹放在你当前使用的配置文件中了。&lt;/p&gt;
&lt;h3&gt;chrome 文件夹是做什么的&lt;/h3&gt;
&lt;p&gt;Firefox 浏览器的配置文件夹中可以包含一个名为 &lt;code&gt;chrome&lt;/code&gt; 的文件夹。在这个文件夹中，我们可以放置一些自定义的用户界面元素，以修改浏览器的外观和行为。这些自定义元素可以是用户样式表 (userChrome.css)、用户脚本 (userChrome.js) 或者用户界面元素 (userChrome.xml) 等。&lt;/p&gt;
&lt;p&gt;其中，最常见的是用户样式表 (userChrome.css)，就是我们这次使用到的东西，它可以通过 CSS 样式来修改浏览器的界面元素，包括修改菜单栏、工具栏、标签栏等的外观和行为。通过编辑 &lt;code&gt;userChrome.css&lt;/code&gt; 文件，您可以实现一些个性化的界面定制，例如隐藏或显示特定的工具栏按钮、修改标签栏的样式等。&lt;/p&gt;
&lt;h2&gt;性能设置&lt;/h2&gt;
&lt;p&gt;这里就需要用到上面提到过的 &lt;code&gt;user.js&lt;/code&gt; 了。参照 &lt;a href=&quot;https://github.com/yokoffing/Betterfox&quot;&gt;Betterfox &lt;/a&gt; 项目：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Simple configs&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Fastfox&lt;/code&gt;, &lt;code&gt;Securefox&lt;/code&gt;, &lt;code&gt;Peskyfox&lt;/code&gt;, and &lt;code&gt;Smoothfox&lt;/code&gt; are guides to settings within Firefox.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;user.js&lt;/code&gt; — a configuration file that controls Firefox settings — is curated from these guides.&lt;/p&gt;
&lt;p&gt;|                                    List                                    | Description                                                                                    |
| :------------------------------------------------------------------------: | ---------------------------------------------------------------------------------------------- |
|   &lt;a href=&quot;https://github.com/yokoffing/Betterfox/blob/main/Fastfox.js&quot;&gt;Fastfox&lt;/a&gt;   | Increase Firefox&apos;s browsing speed. Give Chrome a run for its money!                            |
| &lt;a href=&quot;https://github.com/yokoffing/Betterfox/blob/main/Securefox.js&quot;&gt;Securefox&lt;/a&gt; | Protect user data without causing site breakage.                                               |
|  &lt;a href=&quot;https://github.com/yokoffing/Betterfox/blob/main/Peskyfox.js&quot;&gt;Peskyfox&lt;/a&gt;  | Provide a clean, distraction-free browsing experience.                                         |
| &lt;a href=&quot;https://github.com/yokoffing/Betterfox/blob/main/Smoothfox.js&quot;&gt;Smoothfox&lt;/a&gt; | Get Edge-like smooth scrolling on your favorite browser — or choose something more your style. |
|    &lt;a href=&quot;https://github.com/yokoffing/Betterfox/blob/main/user.js&quot;&gt;user.js&lt;/a&gt;     | All the essentials. None of the breakage. This is your &lt;code&gt;user.js&lt;/code&gt;.                              |&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;根据官方 README，这个项目大致分为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yokoffing/Betterfox/blob/main/Fastfox.js&quot;&gt;Fastfox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yokoffing/Betterfox/blob/main/Securefox.js&quot;&gt;Securefox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yokoffing/Betterfox/blob/main/Peskyfox.js&quot;&gt;Peskyfox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yokoffing/Betterfox/blob/main/Smoothfox.js&quot;&gt;Smoothfox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每一步部分都有各自的功能，具体还请大家自行去翻译查看，根据自己的需求定制一个属于自己的火狐。&lt;/p&gt;
&lt;p&gt;但是要注意的是，修改 &lt;code&gt;user.js&lt;/code&gt; 就是在修改 &lt;code&gt;about:config&lt;/code&gt; 中的设置，这样可能会对浏览器的稳定性和安全性产生影响，所以除非真的知道自己在做什么，否则不建议随意更改这些设置。如果不确定某个设置的含义或影响，请在更改之前先进行适当的研究和了解。&lt;/p&gt;
&lt;p&gt;编辑好以后自行进入 &lt;strong&gt;配置文件夹&lt;/strong&gt; 将 &lt;code&gt;user.js&lt;/code&gt; 粘贴进去就好了。&lt;/p&gt;
&lt;h2&gt;额外设置&lt;/h2&gt;
&lt;p&gt;对于 Windows 用户，火狐浏览器的内存占用似乎一直比 Edge 要大得多。这个问题可以通过 &lt;a href=&quot;https://www.rizonesoft.com/downloads/firemin/&quot;&gt;Firemin&lt;/a&gt; 这个软件解决。&lt;/p&gt;
&lt;p&gt;它是通过修改 Firefox 的配置参数，以调整其内存管理策略，从而使 Firefox 更加高效地利用系统内存资源。它会尝试最大程度地减少 Firefox 对系统内存的占用，以降低浏览器运行时出现卡顿、崩溃或内存泄漏等问题的可能性。&lt;/p&gt;
&lt;p&gt;虽然不太清楚它具体的原理，不过它的效果确实很是显著。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://djdog.cc/_image?href=%2F_astro%2F202404032351126.BraGZYQc.webp&amp;#x26;w=937&amp;#x26;h=40&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;放一个狗盘链接在这里方便大家下载：&lt;a href=&quot;https://pan.djdog.cc/%E8%BD%AF%E4%BB%B6/Windows/Firemin_8398_Setup.exe&quot;&gt;Firemin_8398_Setup.exe&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;最后还是要和大家说，即使我们做了这么多的设置，可能最后也会发现自己的火狐并没有 Edge 或是 Chrome 那么好用，这很大一部分原因是出在大部分网站是对 Chrome 内核的浏览器做了优化，但火狐并没有，这个问题我们可以通过修改浏览器的 UA 来解决。让自己的浏览器在网页看来就是 Chrome。这点可以使用扩展 &lt;a href=&quot;https://addons.mozilla.org/zh-CN/firefox/addon/user-agent-string-switcher/&quot;&gt;User-Agent Switcher and Manager&lt;/a&gt; 来做到。&lt;/p&gt;</content:encoded><h:img src="/_astro/firefox.BBnHu5IG.webp"/><enclosure url="/_astro/firefox.BBnHu5IG.webp"/></item><item><title>Windows 上的第三方包管理器 —— Scoop</title><link>https://djdog.cc/blog/2024/scoop-win</link><guid isPermaLink="true">https://djdog.cc/blog/2024/scoop-win</guid><description>或许体验略胜于 WinGet</description><pubDate>Tue, 22 Oct 2024 23:23:32 GMT</pubDate><content:encoded>&lt;p&gt;如果曾使用过 Linux 、macOS，或是使用过 Python 中的 pip 等工具，再回头来使用 Windows 系统时，最想要的可能就是一个好用的&lt;code&gt;包管理器&lt;/code&gt;。毕竟相较于在浏览器里面搜索官网再下载，直接在命令行里面通过一行指令去安装软件还是非常舒适的，而且在后续的维护上，包管理器要明显方便得多。&lt;/p&gt;
&lt;p&gt;举个例子：&lt;/p&gt;
&lt;p&gt;如果你打算在自己的 Windows 电脑上安装 MinGW 环境，首先就要先打开浏览器搜索 MinGW-w64，点开 &lt;a href=&quot;https://www.mingw-w64.org/&quot;&gt;MinGW&lt;/a&gt; 官网下载最新的安装包（如果恰好你使用的搜索引擎是百某度之类的，那这一步大概就会困难重重），而且他们的官网发布的 Release 已经停留在 v8.1.0 很久了，要是想下载到更新的版本，还要去找 Github 里面自动打包的二进制版本发布&lt;a href=&quot;https://github.com/niXman/mingw-builds-binaries/releases&quot;&gt;仓库&lt;/a&gt;。下载好后，再去双击安装，自行配置环境变量。&lt;/p&gt;
&lt;p&gt;但如果你使用了包管理器，那么你只需要：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;scoop install mingw
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果安装的是一些有自我更新功能的软件倒还好，比如微信、QQ、浏览器什么的。但是要是 MinGW 这样的软件，要是哪天想要升级一下，就只能把上述流程重复一遍。&lt;/p&gt;
&lt;p&gt;但如果你使用了包管理器，那么你只需要：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;scoop update mingw
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;为什么是 Scoop&lt;/h2&gt;
&lt;p&gt;现在的 Windows 11 在安装时会自带一个 &lt;a href=&quot;https://github.com/microsoft/winget-cli&quot;&gt;WinGet&lt;/a&gt;，除此之外常见的包管理器还有 Chocolatey 和 Scoop等。Chocolatey 目前大部分功能都可以直接通过 WinGet 来替代，这里就不再多说。WinGet 使用起来也没什么 Bug，但就是有一些小问题让人难以忍受，包括但不限于：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;安装部分软件会直接从 Github 里面下载，在境内大部分时候都不能成功下载&lt;/li&gt;
&lt;li&gt;没有办法像手动安装那样灵活的调整一些选项，自启动、快捷方式、安装位置之类的都没法自选&lt;/li&gt;
&lt;li&gt;主要用于安装 .msi、.exe 与 .appx，目前不支持 .zip，有的软件在下载安装包后还需要手动点击安装。与其说是一个包管理器，更像是把GUI installer 变成 CLI installer 的小工具&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于上面的问题，Scoop 就能很好地解决。&lt;/p&gt;
&lt;p&gt;首先 Scoop 自身有 proxy 的设置，不用担心软件下载失败，在下面会详细介绍。而且，Scoop 比较重视 portable，它会把所有的软件以一种类似于“绿色软件”的方式安装在 scoop 文件夹之下。但也正因为这样的设计， Scoop 存在着一些问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://jp.v2ex.com/t/1030930&quot;&gt;2024 年,使用 Scoop 的问题 - V2EX&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.v2ex.com/t/950041&quot;&gt;时至 2023 的今天， winget 还是 scoop？ - V2EX&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总得来说，是因为 Scoop 更新软件时，会在 scoop/app 文件夹下的软件目录里同时保存着新老版本的软件。这里以 git 为例：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;git
├── 2.47.0.2
├── 2.47.0.1
└── current
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中的 &lt;code&gt;current&lt;/code&gt; 是一个硬链接，始终指向最新版本的 git。正因如此，如果将老版本的应用固定在任务栏，在升级软件后点击任务栏上的快捷方式，就会出现在旁边另开了一个图标的情况。也会使得 7zip 这样的软件在升级后与已经关联的 .rar、.zip 等文件失去关联（这种一般会在安装后给出提示导入注册表，复制指令执行后就不会出现这样的问题）。&lt;/p&gt;
&lt;p&gt;总的来说，没有自动更新功能的命令行软件更适合通过 Scoop 安装，而有自动更新功能的GUI 软件则更适合通过 WinGet 或是自行下载安装程序的方式安装。&lt;/p&gt;
&lt;h2&gt;安装 Scoop&lt;/h2&gt;
&lt;p&gt;此部分参考 Scoop 官方文档 &lt;a href=&quot;https://github.com/ScoopInstaller/Scoop/wiki/Quick-Start&quot;&gt;Scoop Wiki&lt;/a&gt;，本文可能无法及时更新。&lt;/p&gt;
&lt;h3&gt;准备工作&lt;/h3&gt;
&lt;p&gt;需要高于 5.1 版本的 PowerShell，Windows 10 以及更高的版本应自带。&lt;/p&gt;
&lt;p&gt;PowerShell 版本检查：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;$PSVersionTable.PSVersion # has to be &gt;= 5.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;允许 PowerShell 执行本地脚本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Unrestricted&lt;/code&gt; 也可以，但不太安全。&lt;/p&gt;
&lt;h3&gt;安装 Scoop&lt;/h3&gt;
&lt;p&gt;在 PowerShell 中运行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;irm get.scoop.sh | iex
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这里如果想要将 scoop 安装在指定位置，可以运行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;# 下载安装器
irm get.scoop.sh -outfile &apos;install.ps1&apos;

# 查看所有可配置选项
.\install.ps1 -?

# 安装命令示例，根据自己需要调整
.\install.ps1 -ScoopDir &apos;D:\Applications\Scoop&apos; -ScoopGlobalDir &apos;F:\GlobalScoopApps&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在内网的情况下很难通过上面的命令成功安装，可以参照 Gitee 上面的&lt;a href=&quot;https://gitee.com/scoop-installer/scoop&quot;&gt;国内镜像&lt;/a&gt;安装，具体请查看项目 README。安装命令如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;# 安装命令
iwr -useb scoop.201704.xyz | iex

# 自定义安装目录
irm scoop.201704.xyz -outfile &apos;install.ps1&apos;
.\install.ps1 -ScoopDir &apos;D:\Scoop&apos; -ScoopGlobalDir &apos;D:\GlobalScoopApps&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;使用 Scoop&lt;/h2&gt;
&lt;p&gt;通过 &lt;code&gt;scoop help&lt;/code&gt; 命令可以查看所有的命令。&lt;/p&gt;
&lt;h3&gt;安装卸载软件&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;# 安装之前，通过 search 命令搜索, 确定软件全名
scoop search foo

# 安装
scoop install fooName

# 安装特定版本的软件，以 git 为例
scoop install git@2.47.0.windows.1

# 卸载
scoop uninstall fooName
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;更新软件&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;# 更新 Scoop 自身
scoop update

# 更新部分软件
scoop update fooName1 fooName2

# 更新所有软件
scoop update *

# 禁止某程序更新
scoop hold fooName

# 允许某程序更新
scoop unhold fooName
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;清除缓存与旧版本&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;# 查看所有已下载的缓存信息
scoop cache show

# 清除指定程序的下载缓存
scoop cache rm fooName

# 清除所有缓存
scoop cache rm *

# 删除某软件的旧版本
scoop cleanup fooName

# 删除全局安装的某软件的旧版本
scoop cleanup fooName -g

# 删除所有旧版本软件
scoop cleanup *
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Bucket 相关命令&lt;/h3&gt;
&lt;p&gt;Bucket 相当于 Scoop 的仓库，在安装 Scoop 后会默认激活 main 仓库。常见的 Bucket有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;extras：Scoop 官方维护的一个仓库，涵盖了大部分因为种种原因不能被收录进主仓库的常用软件&lt;/li&gt;
&lt;li&gt;dorado：包含很多常用的 GUI 软件，比如 QQ、微信等&lt;/li&gt;
&lt;li&gt;nerd-fonts：包含大部分 NerdFont&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;想要查看 Scoop 大部分仓库，使用以下命令：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;scoop bucket list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;添加 Bucket 命令（以 extras 为例）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;scoop bucket add extras
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;建议安装程序&lt;/h3&gt;
&lt;p&gt;Scoop 在初次安装软件后，会自动安装 7-zip，因为在它安装软件的过程中会使用到 7-zip 来进行解压缩操作，但除此之外还可以安装以下软件来增强 Scoop 的功能：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;# 提权工具，临时使用管理员权限安装软件，可以在全局安装时使用
scoop install gsudo 

# 多线程下载工具，可以使 Scoop 下载更快
scoop install aria2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;gsudo 在安装全局软件时可以直接在命令前加上 &lt;code&gt;gsudo&lt;/code&gt; 提权，类似 Linux 中的 sudo，避免需要单独开以管理员模式运行的终端才能安装的麻烦。&lt;/p&gt;
&lt;p&gt;aria2 在安装后，Scoop 的下载过程就会默认调用它，无需单独设置。&lt;/p&gt;</content:encoded><h:img src="/_astro/windows-wallpaper.Co356QiI.webp"/><enclosure url="/_astro/windows-wallpaper.Co356QiI.webp"/></item><item><title>更换 Windows 系统中软件的图标</title><link>https://djdog.cc/blog/2023/change-icon-win</link><guid isPermaLink="true">https://djdog.cc/blog/2023/change-icon-win</guid><description>使用 Resource Hacker 修改 .exe 文件的图标</description><pubDate>Sun, 20 Aug 2023 23:38:02 GMT</pubDate><content:encoded>&lt;p&gt;网络上好多教程都只教了修改快捷方式的图标，但软件打开后，任务栏上的图标还是没有变化。&lt;/p&gt;
&lt;p&gt;因为软件的图标是包含在 .exe 文件里面的，修改快捷方式的图标不会影响软件本身打开后的样子。&lt;/p&gt;
&lt;h2&gt;Resource Hacker&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.angusj.com/resourcehacker/&quot;&gt;Resource Hacker&lt;/a&gt; 是一款免费的软件。它既是资源编译器 (对于 &lt;em&gt;.rc 文件), 又是反编译器 – 可用于查看和编辑可执行文件(&lt;/em&gt;.exe; *.dll; &lt;em&gt;.scr; )等文件类型的资源文件，以及编译资源库 (&lt;/em&gt;.res, &lt;em&gt;.mui)，创建和编译资源脚本文件 (&lt;/em&gt;.rc)，支持命令行编译和反编译资源的选项。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://pan.djdog.cc/api/raw?path=/%E8%BD%AF%E4%BB%B6/Windows/Resource%20Hacker%20v5.1.8%20Build%20360.zip&quot;&gt;下载链接&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;修改图标&lt;/h2&gt;
&lt;h3&gt;用 Resource Hacker 打开需要修改的 .exe 文件&lt;/h3&gt;
&lt;p&gt;以 Tor Browser 为例，打开 Resource Hacker，将桌面上 Tor Browser 快捷方式指向的 .exe 拖到 Resource Hacker 里。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://djdog.cc/_image?href=%2F_astro%2Fhacker1.CtgCTuvB.webp&amp;#x26;w=1182&amp;#x26;h=651&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;替换图标&lt;/h3&gt;
&lt;p&gt;点击工具栏中的 &lt;code&gt;操作&lt;/code&gt;-&lt;code&gt;替换图标&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://djdog.cc/_image?href=%2F_astro%2Fhacker2.DMMLDCSf.webp&amp;#x26;w=1182&amp;#x26;h=739&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;选择图标&lt;/h3&gt;
&lt;p&gt;在右边选择想要替换的图标，然后点击&lt;code&gt;打开图标文件&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://djdog.cc/_image?href=%2F_astro%2Fhacker3.nHgiLIIB.webp&amp;#x26;w=768&amp;#x26;h=625&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;选择完成后，点击&lt;code&gt;替换&lt;/code&gt;按钮。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://djdog.cc/_image?href=%2F_astro%2Fhacker5.2O8iLkcD.webp&amp;#x26;w=768&amp;#x26;h=623&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;替换完成&lt;/h3&gt;
&lt;p&gt;.exe 文件的图标替换完成，这时双击打开它，任务栏中跳出的图标也是修改后的样子。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://djdog.cc/_image?href=%2F_astro%2Fhacker7.5ZQ5o4LS.webp&amp;#x26;w=1497&amp;#x26;h=1044&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://djdog.cc/_image?href=%2F_astro%2Fhacker8.CpizMbfe.webp&amp;#x26;w=79&amp;#x26;h=67&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;</content:encoded><h:img src="/_astro/windwos11logo.mini.CCSIkN5J.webp"/><enclosure url="/_astro/windwos11logo.mini.CCSIkN5J.webp"/></item><item><title>Hello World</title><link>https://djdog.cc/blog/2023/hello-world</link><guid isPermaLink="true">https://djdog.cc/blog/2023/hello-world</guid><description>DJ小站の重建123456</description><pubDate>Wed, 03 May 2023 13:01:42 GMT</pubDate><content:encoded>&lt;p&gt;稍后补充搭建过程&lt;/p&gt;</content:encoded><h:img src="/_astro/1.BD9lT1-d.webp"/><enclosure url="/_astro/1.BD9lT1-d.webp"/></item><item><title>Git 子模块 submodule 的使用</title><link>https://djdog.cc/blog/2023/git-submodule</link><guid isPermaLink="true">https://djdog.cc/blog/2023/git-submodule</guid><description>git submodule 命令的基础知识和使用中容易遇见的坑</description><pubDate>Tue, 01 Aug 2023 11:01:42 GMT</pubDate><content:encoded>&lt;h2&gt;背景&lt;/h2&gt;
&lt;p&gt;面对比较复杂的项目，我们有可能会将代码根据功能拆解成不同的子模块。主项目对子模块有依赖关系，却又并不关心子模块的内部开发流程细节。&lt;/p&gt;
&lt;p&gt;这种情况下，通常不会把所有源码都放在同一个 Git 仓库中。&lt;/p&gt;
&lt;p&gt;Git 通过子模块来解决这个问题。 子模块允许你将一个 Git 仓库作为另一个 Git 仓库的子目录。 它能让你将另一个仓库克隆到自己的项目中，同时还保持提交的独立。&lt;/p&gt;
&lt;h2&gt;使用流程&lt;/h2&gt;
&lt;p&gt;假设我们有两个项目，分别是 &lt;code&gt;project-main&lt;/code&gt;  和  &lt;code&gt;project-sub-1&lt;/code&gt;，其中 &lt;code&gt;project-main&lt;/code&gt; 代表&lt;code&gt;主项目&lt;/code&gt;，&lt;code&gt;project-sub-1&lt;/code&gt; 代表&lt;code&gt;子模块1&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;其中 &lt;code&gt;project-main&lt;/code&gt; 的远程仓库地址为 &lt;code&gt;https://github.com/username/project-main.git&lt;/code&gt;，而 &lt;code&gt;project-sub-1&lt;/code&gt; 的远程仓库地址为 &lt;code&gt;https://github.com/username/project-sub-1.git&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;接下来，我们希望在 &lt;code&gt;project-main&lt;/code&gt; 中添加 &lt;code&gt;project-sub-1&lt;/code&gt; ，而又保持 &lt;code&gt;project-sub-1&lt;/code&gt; 自身独立的版本控制。&lt;/p&gt;
&lt;h3&gt;创建  submodule&lt;/h3&gt;
&lt;p&gt;进入 &lt;code&gt;project-main&lt;/code&gt; ，输入：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git submodule add &amp;#x3C;submodule_url&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;终端中跳出这样的字样：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;➜ git submodule add https://github.com/username/project-sub-1.git
正克隆到 &apos;/path/to/project-main/project-sub-1&apos;...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
展开对象中: 100% (3/3), 完成.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时项目仓库中会多出两个文件：&lt;code&gt;.gitmodules&lt;/code&gt; 和 &lt;code&gt;project-sub-1&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;前者的内容是这样的，事实上就是子模块的相关信息；而后者那个文件，实际上保存的是子模块当前版本的版本号信息。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;[submodule &quot;project-sub-1&quot;]
path = project-sub-1
url = https://github.com/username/project-sub-1.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时在 &lt;code&gt;.git/config&lt;/code&gt; 文件中也会多出一些信息，在 &lt;code&gt;.git/modules&lt;/code&gt; 文件夹下也会多出一份内容。&lt;/p&gt;
&lt;p&gt;通常这个时候就会在主项目中使用 &lt;code&gt;git commit -m &apos;add submodule xxx&apos;&lt;/code&gt; 来进行一次提交，表示在新版本的&lt;code&gt;主项目&lt;/code&gt;中引入了这个&lt;code&gt;子模块1&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;拉取 submodule&lt;/h3&gt;
&lt;p&gt;在上述步骤创建子模块的过程中，会自动将相关代码克隆到对应路径，但对于后续使用者而言，对于主项目使用普通的 &lt;code&gt;clone&lt;/code&gt; 操作并不会拉取到子模块中的实际代码。&lt;/p&gt;
&lt;p&gt;如果希望子模块代码也获取到，一种方式是在克隆主项目的时候带上参数  &lt;code&gt;--recurse-submodules&lt;/code&gt;，这样会递归地将项目中所有子模块的代码拉取。&lt;/p&gt;
&lt;p&gt;若是已经单独拉取了主项目，则可以使用下面的命令来拉取子模块：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git submodule init
git submodule update
# 或者将上面的两条合成一步来使用
git submodule update --init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果还要初始化、抓取并检出任何嵌套的子模块：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git submodule update --init --recursive
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;更新  submodule&lt;/h3&gt;
&lt;p&gt;对于子模块而言，子模块自己就是一个完整的 Git 仓库，按照正常的 Git 代码管理规范操作即可。&lt;/p&gt;
&lt;p&gt;而对于主项目，主项目是与子项目仓库的其中一个版本绑定的，那么当子项目内容发生变化时，通常分为以下三种情况：&lt;/p&gt;
&lt;h4&gt;1. 本地主项目文件夹中的子模块发生未跟踪的变动&lt;/h4&gt;
&lt;p&gt;在开发环境中，若是直接修改了子模块文件夹中的内容，就会导致这种情况发生。&lt;/p&gt;
&lt;p&gt;此时在主项目中使用 &lt;code&gt;git status&lt;/code&gt; 就能看到子模块中尚未 &lt;code&gt;commit&lt;/code&gt; 的变动，但要是在主项目中 &lt;code&gt;git add/commit&lt;/code&gt; 是不会产生影响的。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;➜ git status
位于分支 master
您的分支与上游分支 &apos;origin/master&apos; 一致。
尚未暂存以备提交的变更：
（使用 &quot;git add &amp;#x3C;文件&gt;...&quot; 更新要提交的内容）
（使用 &quot;git checkout -- &amp;#x3C;文件&gt;...&quot; 丢弃工作区的改动）
（提交或丢弃子模组中未跟踪或修改的内容）
修改： project-sub-1 (未跟踪的内容)
修改尚未加入提交（使用 &quot;git add&quot; 和/或 &quot;git commit -a&quot;）
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时只需要进入子模块文件夹，按照子模块的版本提交就好了。&lt;/p&gt;
&lt;h4&gt;2. 本地的子模块有版本变化&lt;/h4&gt;
&lt;p&gt;在第一种情况中，将子模块的改动提交后便会出现这种情况。此时本地和远程仓库中的子模块都是更新后的版本，但主项目绑定的却是老版本的子模块。这时如果使用&lt;code&gt;git status&lt;/code&gt; 就能看到：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;➜ git status
位于分支 master
您的分支与上游分支 &apos;origin/master&apos; 一致。
尚未暂存以备提交的变更：
（使用 &quot;git add &amp;#x3C;文件&gt;...&quot; 更新要提交的内容）
（使用 &quot;git checkout -- &amp;#x3C;文件&gt;...&quot; 丢弃工作区的改动）
修改： project-sub-1 (新提交)
修改尚未加入提交（使用 &quot;git add&quot; 和/或 &quot;git commit -a&quot;）
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时在主项目中 &lt;code&gt;git add/commit&lt;/code&gt; 便可以更新主项目中 &lt;code&gt;.gitmodules&lt;/code&gt; 中的子项目版本信息。&lt;/p&gt;
&lt;h4&gt;3. 远程仓库中的子模块有更新&lt;/h4&gt;
&lt;p&gt;在非本地子模块在将自己的版本更新后，推送到远程仓库中。这时本地的子模块并没有发生变化，主项目是不会受到任何影响的。&lt;/p&gt;
&lt;p&gt;主项目虽然可以用 &lt;code&gt;git submodule update&lt;/code&gt; 来更新子模块的代码，但这个命令会按照 &lt;code&gt;.gitmodules&lt;/code&gt; 中主项目记录的版本进行更新。&lt;/p&gt;
&lt;p&gt;但现在这种情况，主项目记录的子模块版本并没有变化， &lt;code&gt;git submodule update&lt;/code&gt; 自然也不会将子模块更新到新版本。&lt;/p&gt;
&lt;p&gt;此时，一般需要进入到子模块的目录主动拉取新版，再按照第二种情况进行操作。&lt;/p&gt;
&lt;p&gt;也可以使用下面的命令，将所有子模块全部更新。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git submodule foreach &apos;git pull&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;删除  submodule&lt;/h3&gt;
&lt;p&gt;按照当前的例子，从 &lt;code&gt;project-main&lt;/code&gt; 中删除 &lt;code&gt;project-sub-1&lt;/code&gt;，应该使用：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git submodule deinit project-sub-1
git rm project-sub-1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;若由于本地的子模块有未提交的改动，则需要使用 &lt;code&gt;--force&lt;/code&gt; 参数。&lt;/p&gt;
&lt;p&gt;执行 &lt;code&gt;git submodule deinit project-sub-1&lt;/code&gt; 命令的实际效果，是自动在 &lt;code&gt;.git/config&lt;/code&gt; 中删除了以下内容：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;    [submodule &quot;project-sub-1&quot;]
    url = https://github.com/username/project-sub-1.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行 &lt;code&gt;git rm project-sub-1&lt;/code&gt; 的效果，是移除了 &lt;code&gt;project-sub-1&lt;/code&gt; 文件夹，并自动在 &lt;code&gt;.gitmodules&lt;/code&gt; 中删除了以下内容：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;    [submodule &quot;project-sub-1&quot;]
    path = project-sub-1
    url = https://github.com/username/project-sub-1.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时便完成了子模块的删除，提交代码就可以了。&lt;/p&gt;
&lt;p&gt;如果要在删除了一个子模块后，打算在同一位置加入一个新的同名子模块，则需要运行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt; rm -rf /path/to/project-sub
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="/_astro/githublab.l4mh2tAe.webp"/><enclosure url="/_astro/githublab.l4mh2tAe.webp"/></item><item><title>在 Windows、Linux、Macos 的终端中使用代理</title><link>https://djdog.cc/blog/2024/terminal-proxy</link><guid isPermaLink="true">https://djdog.cc/blog/2024/terminal-proxy</guid><description>如何在常见的三种桌面系统的终端里使用代理</description><pubDate>Tue, 23 Jul 2024 22:53:11 GMT</pubDate><content:encoded>&lt;p&gt;这三种常见的桌面系统的终端都不会自动继承图形界面的系统代理，这里介绍一下在终端里使用代理的方法。&lt;/p&gt;
&lt;h2&gt;Windows 系统&lt;/h2&gt;
&lt;h3&gt;设置代理&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;# 设置 HTTP 代理
set http_proxy=http://127.0.0.1:port

# 设置 HTTPS 代理
set https_proxy=http://127.0.0.1:port

&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;验证代理&lt;/h3&gt;
&lt;p&gt;用 ping 命令是无法验证这里设置的终端代理的，因为 HTTP 代理只能代理基于 TCP 协议的 HTTP 或者 HTTPS 协议的流量。而 ping 命令用的是 icmp 协议。&lt;/p&gt;
&lt;p&gt;所以这里使用 curl 命令来验证：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;curl -vv https://www.google.com
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;取消代理&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;set http_proxy=
set https_proxy=
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;设置别名&lt;/h3&gt;
&lt;p&gt;可以通过设置别名来简化每次使用代理时的操作。&lt;/p&gt;
&lt;p&gt;首先使用 &lt;code&gt;echo $PROFILE&lt;/code&gt; 命令来确定 Powershell 的配置文件的位置。&lt;/p&gt;
&lt;p&gt;打开输出的文件，按照如下格式编辑内容：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;function 别名 { 需要替代的命令 }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里给出我的例子：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;function setproxy {
set http_proxy=http://127.0.0.1:port
set https_proxy=http://127.0.0.1:port 
}

function unsetproxy {
set http_proxy=
set https_proxy=
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Linux 和 Macos&lt;/h2&gt;
&lt;p&gt;Macos 终端默认使用 zsh，设置方式与 Linux 默认的 bash 类似，所以就放在一起来讲。&lt;/p&gt;
&lt;h3&gt;设置代理&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 设置 HTTP 代理
export http_proxy=http://127.0.0.1:port

# 设置 HTTPS 代理
export https_proxy=http://127.0.0.1:port
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;验证代理&lt;/h3&gt;
&lt;p&gt;使用 curl 命令来验证代理是否生效：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -vv https://www.google.com
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;取消代理&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;unset http_proxy
unset https_proxy
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;设置别名&lt;/h3&gt;
&lt;p&gt;可以通过设置别名来简化每次使用代理时的操作。&lt;/p&gt;
&lt;p&gt;打开终端的配置文件（例如：&lt;code&gt;~/.bashrc&lt;/code&gt; 或 &lt;code&gt;~/.zshrc&lt;/code&gt;），添加如下内容：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;alias setproxy=&apos;setproxy(){export http_proxy=http://127.0.0.1:port; export https_proxy=http://127.0.0.1:port;};setproxy&apos;

alias unsetproxy=&apos;unsetproxy(){unset http_proxy; unset https_proxy;};unsetproxy&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;记得替换 &lt;code&gt;port&lt;/code&gt; 为实际的代理端口号。&lt;/p&gt;</content:encoded><h:img src="/_astro/debian-misbrand.BH_830Do.webp"/><enclosure url="/_astro/debian-misbrand.BH_830Do.webp"/></item><item><title>SSH-keygen 用法</title><link>https://djdog.cc/blog/2024/sshkey</link><guid isPermaLink="true">https://djdog.cc/blog/2024/sshkey</guid><description>如何生成 SSH Key 并添加到 Github</description><pubDate>Sat, 20 Apr 2024 22:21:39 GMT</pubDate><content:encoded>&lt;p&gt;SSH 是一种有较高安全性的远程登录方式。SSH Key 就是我们登录的密钥。在 Github 上管理项目时，如果是使用 https url 进行 &lt;code&gt;push&lt;/code&gt; 操作，是需要验证用户名和密码的。而使用 SSH 在 &lt;code&gt;push&lt;/code&gt; 的时候是不需要输入用户名的，如果配置SSH key的时候设置了密码，则需要输入密码的，否则直接是不需要输入密码的。&lt;/p&gt;
&lt;p&gt;并且处于众所周知的原因，大陆的用户使用 https 方式管理仓库时，经常会出现无法访问的情况，而 SSH 这种方式就可以避免这个问题。&lt;/p&gt;
&lt;p&gt;通过 SSH 克隆项目其实很简单，我们先要在本地先生成一个 SSH Key，然后把这个 Key 添加到 Github 就可以了。&lt;/p&gt;
&lt;h2&gt;生成 SSH Key&lt;/h2&gt;
&lt;p&gt;使用下面的命令，将示例邮箱何为自己用于注册 Github 时使用的邮箱。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh-keygen -t rsa -C &quot;your_email@example.com&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;代码参数含义：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-t 指定密钥类型，默认是 rsa，可以省略。&lt;/li&gt;
&lt;li&gt;-C 设置注释文字，比如邮箱。&lt;/li&gt;
&lt;li&gt;-f 指定密钥文件存储文件名。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上代码省略了 -f 参数，因此，运行上面那条命令后会让你输入一个文件名，用于保存刚才生成的 SSH key 代码，如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;Generating public/private rsa key pair.
Enter file in which to save the key (/c/Users/you/.ssh/id_rsa): [Press enter]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我这里选择不输入文件名，使用默认文件名（推荐）。那么就会生成 id_rsa 和 id_rsa.pub 两个文件。&lt;/p&gt;
&lt;p&gt;接着又会提示你输入两次密码（该密码是你 &lt;code&gt;push&lt;/code&gt; 文件的时候要输入的密码，而非 Github 密码），&lt;/p&gt;
&lt;p&gt;如果这里不输入密码，直接按回车。那么 &lt;code&gt;push&lt;/code&gt; 的时候就不需要输入密码了。&lt;/p&gt;
&lt;h2&gt;查看 SSH Key&lt;/h2&gt;
&lt;p&gt;如果在上面的步骤里没有这门指定密钥生成的位置，那么它就会生成在默认位置 &lt;code&gt;~/.ssh/&lt;/code&gt; 下。&lt;/p&gt;
&lt;p&gt;查看 SSH Key:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cat ~/.ssh/id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;得到一串以 &lt;code&gt;ssh-rsa&lt;/code&gt; 开头的密钥，复制下来。&lt;/p&gt;
&lt;p&gt;或者直接通过命令复制：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;clip &amp;#x3C; ~/.ssh/id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;将 SSH Key 添加到 Github&lt;/h2&gt;
&lt;p&gt;登录 Github 账号，点击在主页右上角的头像进入 &lt;strong&gt;Settings&lt;/strong&gt;，然后在左侧找到 &lt;strong&gt;SSH and GPG keys&lt;/strong&gt; 点击进入。&lt;/p&gt;
&lt;p&gt;点击绿色按钮 New SSH key 按钮，进入 &lt;a href=&quot;https://github.com/settings/ssh/new&quot;&gt;Add new SSH Key&lt;/a&gt; 页面（直接点这里的蓝色链接也可以）。把你复制的 SSH key 粘贴到 key 所对应的输入框中，记得 SSH key 代码的前后不要留有空格或者回车。并在上面的 Title 里给这个密钥起一个别名。&lt;/p&gt;
&lt;h2&gt;测试 SSH Key&lt;/h2&gt;
&lt;p&gt;使用这个命令：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh -T git@github.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;按下回车之后，会出现类似这样的警告：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;The authenticity of host &apos;github.com (207.97.227.239)&apos; can&apos;t be established.
RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
Are you sure you want to continue connecting (yes/no)?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里输入 &lt;code&gt;yes&lt;/code&gt; 并回车就好。&lt;/p&gt;
&lt;p&gt;如果你创建 SSH key 的时候设置了密码，接下来就会提示你输入密码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;Enter passphrase for key &apos;/c/Users/Administrator/.ssh/id_rsa&apos;:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你密码输错了，会再要求你输入，知道对了为止。&lt;/p&gt;
&lt;p&gt;注意：输入密码时如果出错了，使用删除键是无法更正的，只能重新输入。&lt;/p&gt;
&lt;p&gt;密码正确后就能看到 Github 向你打招呼了：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;Hi username! You&apos;ve successfully authenticated, but GitHub does not provide shell access.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;如何生成多个 SSH Key&lt;/h2&gt;
&lt;p&gt;假如为 Github 生成一个 SSH，注意要使用不同的名称区分不同的 key，避免覆盖之前的文件。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh-keygen -t rsa -C &quot;&amp;#x3C;您的 Github 邮箱&gt;&quot;
Generating public/private rsa key pair.
Enter file in which to save the key (~/.ssh/id_rsa): &amp;#x3C;为了区分多个key，请填写自定义的名称&gt;
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="/_astro/SSH.CnH01JJX.webp"/><enclosure url="/_astro/SSH.CnH01JJX.webp"/></item><item><title>编程实现 MATLAB 中的离散傅里叶变换 FFT 函数的部分功能</title><link>https://djdog.cc/blog/2024/matlab-fft</link><guid isPermaLink="true">https://djdog.cc/blog/2024/matlab-fft</guid><description>编写一个函数来实现 FFT（重新造轮子）</description><pubDate>Thu, 13 Jun 2024 14:53:11 GMT</pubDate><content:encoded>&lt;h2&gt;FFT_NEW&lt;/h2&gt;
&lt;p&gt;编程实现MATLAB 中的离散傅里叶变换FFT 函数的部分功能。即编写一个函数&lt;code&gt;𝑌 = FFT_NEW(𝑋)&lt;/code&gt;
满足以下条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;输入向量 X 的长度是 2𝑁，其中N 是任意自然数。你可以用 X = rand(1, 2𝑁) 产生这样的序列。（这个限制是为了降低难度）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;输出 𝑌 要和 MATLAB 自带的函数 Y = fft(X) 一模一样，即实现离散傅里叶级数的快速计算。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;必须采用快速傅里叶的变换蝴蝶型算法，而不是根据定义死算。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Matlab代码如下：&lt;/p&gt;
&lt;p&gt;FFT_NEW.m&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-matlab&quot;&gt;function Y = FFT_NEW(X)
    % 计算输入向量 X 的长度
    N = length(X);
    
    % 如果输入向量的长度为 1，直接返回该向量
    if N &amp;#x3C;= 1
        Y = X;
        return;
    end
    
    % 递归地计算偶数索引和奇数索引部分的 FFT
    X_even = FFT_NEW(X(1:2:end));
    X_odd = FFT_NEW(X(2:2:end));
    
    % 预计算旋转因子
    factor = exp(-2i * pi * (0:(N/2 - 1)) / N);
    
    % 使用蝶形算法合并偶数部分和奇数部分的结果
    Y = [X_even + factor .* X_odd, X_even - factor .* X_odd];
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;test_FFT.m&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-matlab&quot;&gt;% 示例用法
X = rand(1, 2^3);  % 生成长度为 2^3 的随机向量
Y = FFT_NEW(X);
Y_fft = fft(X);

% 绘制原始信号
figure;
subplot(3, 1, 1);
stem(0:length(X)-1, X, &apos;filled&apos;);
title(&apos;原始信号&apos;);
xlabel(&apos;样本点&apos;);
ylabel(&apos;幅值&apos;);

% 绘制 FFT_NEW 结果
subplot(3, 1, 2);
stem(0:length(Y)-1, abs(Y), &apos;filled&apos;);
title(&apos;FFT_NEW 结果&apos;);
xlabel(&apos;频率指数&apos;);
ylabel(&apos;幅值&apos;);

% 绘制 MATLAB FFT 结果
subplot(3, 1, 3);
stem(0:length(Y_fft)-1, abs(Y_fft), &apos;filled&apos;);
title(&apos;MATLAB FFT 结果&apos;);
xlabel(&apos;频率指数&apos;);
ylabel(&apos;幅值&apos;);

% 显示差异
figure;
stem(0:length(Y)-1, abs(Y - Y_fft), &apos;filled&apos;);
title(&apos;FFT_NEW 与 MATLAB FFT 结果差异&apos;);
xlabel(&apos;频率指数&apos;);
ylabel(&apos;差值&apos;);

% 检查两者是否相等
tolerance = 1e-10;  % 设定容忍误差
difference = abs(Y - Y_fft);
if all(difference &amp;#x3C; tolerance)
    disp(&apos;两者相等&apos;);
else
    disp(&apos;两者不相等&apos;);
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;IFFT_NEW&lt;/h2&gt;
&lt;p&gt;请编程实现 MATLAB 中的离散傅里叶变换 IFFT 函数的部分功能。即编写一个函数&lt;code&gt;𝑋 = IFFT_NEW(𝑌)&lt;/code&gt;
满足以下条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;输入向量 𝑌 的长度是 2𝑁，其中 𝑁 是任意自然数。你可以用 Y = rand(1, 2𝑁) 产生这样的序列。（这个限制是为了降低难度）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;输出 𝑋 要和 MATLAB 自带的函数 X = ifft(Y) 一模一样，即实现离散傅里叶级数反变换的快速计算。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;需采用快速傅里叶变换的蝴蝶型算法，而不是根据定义死算。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;（提示：如果编出了 FFT，这题不难，但是请注意，如果用递归编程，应该是除以 2，而不是除以 𝑁。）&lt;/p&gt;
&lt;p&gt;Matlab代码如下：&lt;/p&gt;
&lt;p&gt;IFFT_NEW.m&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-matlab&quot;&gt;function Y = IFFT_NEW(X)
    % 计算输入向量 X 的长度
    N = length(X);
    
    % 如果输入向量的长度为 1，直接返回该向量
    if N &amp;#x3C;= 1
        Y = X;
        return;
    end
    
    % 递归地计算偶数索引和奇数索引部分的 IFFT
    X_even = IFFT_NEW(X(1:2:end));
    X_odd = IFFT_NEW(X(2:2:end));
    
    % 预计算旋转因子
    factor = exp(2i * pi * (0:(N/2 - 1)) / N);
    
    % 使用蝶形算法合并偶数部分和奇数部分的结果
    Y = [X_even + factor .* X_odd, X_even - factor .* X_odd] / 2;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;test_IFFT.m&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-matlab&quot;&gt;% 生成测试数据
N = 2^3;  % 长度为 2 的幂
X = rand(1, N) + 1i * rand(1, N);  % 生成随机复数向量

% 计算 IFFT_NEW 和 MATLAB 的 ifft
Y_ifft_new = IFFT_NEW(X);
Y_ifft = ifft(X);

% 绘制原始信号
figure;
subplot(3, 1, 1);
stem(0:N-1, real(X), &apos;filled&apos;);
title(&apos;原始信号 (实部)&apos;);
xlabel(&apos;样本点&apos;);
ylabel(&apos;幅值&apos;);

% 绘制 IFFT_NEW 结果
subplot(3, 1, 2);
stem(0:N-1, real(Y_ifft_new), &apos;filled&apos;);
title(&apos;IFFT_NEW 结果 (实部)&apos;);
xlabel(&apos;频率指数&apos;);
ylabel(&apos;幅值&apos;);

% 绘制 MATLAB IFFT 结果
subplot(3, 1, 3);
stem(0:N-1, real(Y_ifft), &apos;filled&apos;);
title(&apos;MATLAB IFFT 结果 (实部)&apos;);
xlabel(&apos;频率指数&apos;);
ylabel(&apos;幅值&apos;);

% 绘制结果差异
figure;
stem(0:N-1, abs(Y_ifft_new - Y_ifft), &apos;filled&apos;);
title(&apos;IFFT_NEW 与 MATLAB IFFT 结果差异 (实部)&apos;);
xlabel(&apos;频率指数&apos;);
ylabel(&apos;差值&apos;);

% 检查两者是否相等
tolerance = 1e-10;  % 设定容忍误差
difference = abs(Y_ifft_new - Y_ifft);
if all(difference &amp;#x3C; tolerance)
    disp(&apos;两者相等&apos;);
else
    disp(&apos;两者不相等&apos;);
end
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="/_astro/MATLAB.BTWMXGLi.webp"/><enclosure url="/_astro/MATLAB.BTWMXGLi.webp"/></item><item><title>使用 Vercel 零成本搭建 Umami：开源易用的网站访问量统计工具</title><link>https://djdog.cc/blog/2024/umami</link><guid isPermaLink="true">https://djdog.cc/blog/2024/umami</guid><description>Umami + Vercel 搭建流量数据统计系统</description><pubDate>Sun, 31 Mar 2024 01:34:45 GMT</pubDate><content:encoded/><h:img src="/_astro/umami.BuUGTc87.webp"/><enclosure url="/_astro/umami.BuUGTc87.webp"/></item><item><title>使用 Cloudflare R2 和 PicList 搭建自己的免费图床系统</title><link>https://djdog.cc/blog/2023/piclist</link><guid isPermaLink="true">https://djdog.cc/blog/2023/piclist</guid><description>Cloudflare 才是真正的良心云！</description><pubDate>Mon, 30 Oct 2023 08:30:13 GMT</pubDate><content:encoded>&lt;h2&gt;为什么选择 Cloudflare S2&lt;/h2&gt;
&lt;p&gt;现在网上也有好多免费的图床，比如出名的像&lt;a href=&quot;https://imgse.com/&quot;&gt;路过图床&lt;/a&gt;、&lt;a href=&quot;https://www.hualigs.cn/&quot;&gt;遇见图床&lt;/a&gt;，还有非常经典的 &lt;a href=&quot;sm.sm&quot;&gt;SM.MS&lt;/a&gt;。但这些免费图床都多少有些不太稳定。其他的一些需要自己搭建的代替方案也都陆陆续续的失效了，比如之前盛极一时的 Gitee 图床、微博图床。这次的 Cloudflare R2 图床不知道能用多久，不过这个方案自然是有不少好处的，易迁移这点就击败了大多数竞品。而且 Cloudflare 的格局不是一般的大，可以看一下他们的&lt;a href=&quot;https://developers.cloudflare.com/r2/pricing#storage-usage&quot;&gt;定价方案&lt;/a&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A 类操作费用：每个月 1M 次免费额度，超出后每百万次收取 $4.50 的操作费用&lt;/li&gt;
&lt;li&gt;B 类操作费用：每个月 10M 次免费额度，超出后每百万次收取 $0.36 的操作费用&lt;/li&gt;
&lt;li&gt;存储费用：每个月10GB免费额度，超出后每个月每 GB 收取 $0.015 的存储费用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这么大的额度对于个人博客来说几乎是用不完的，而且就算超出这个免费范围，需要付的费用也是很低的。&lt;/p&gt;
&lt;h2&gt;为什么选择 PicList&lt;/h2&gt;
&lt;p&gt;它基于大家熟知的 Picgo，并在此之上增加了一些特色功能，并且仍开源免费&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可以在图片上传之前对图片进行预处理，比如转换格式，增加水印等&lt;/li&gt;
&lt;li&gt;在删除相册中的照片时，可以同步删除储存桶里的文件&lt;/li&gt;
&lt;li&gt;在 Windows 和 Linux 平台，支持 Mini 窗口上传，MacOS 可以使用顶栏图标上传&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;具体内容见 &lt;a href=&quot;https://piclist.cn/&quot;&gt;PicList官网&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;创建 CloudFlare R2 储存桶&lt;/h2&gt;
&lt;h3&gt;准备工作&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;一个域名，备不备案都可以，免费付费也都无所谓。Cloudflare 倒是会提供一个 .r2.dev 的二级域名，不过可惜有时候在境内会无法访问&lt;/li&gt;
&lt;li&gt;一张信用卡。Visa、万事达、银联都可以，PayPal也可以。绑定卡后会进行一次小额扣费进行验证，过了一会就会返还。&lt;/li&gt;
&lt;li&gt;Cloudflare 账号，这里不赘述注册过程&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;创建储存桶&lt;/h3&gt;
&lt;p&gt;在 Dashboard 左侧面板里选择 R2，点击创建存储桶。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./Snipaste_2024-02-15_22-07-49.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;在这里填好储存桶的名字，在下面按照图示选好位置，简中博客访客主要集中在大陆，所以这里选择亚太地区。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./Snipaste_2024-02-15_22-12-46.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;域名绑定&lt;/h3&gt;
&lt;p&gt;将购买好的域名绑在 Cloudflare 上进行解析，中间需要等待域名 name server 更新，快的话几分钟就可以，最慢也不会超过 24 小时。&lt;/p&gt;
&lt;p&gt;绑定好了后，就可以在储存桶的设置界面自定义一个域名。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./Snipaste_2024-02-15_22-17-02.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;等待一两分钟后，状态变为有效就可以了。&lt;/p&gt;
&lt;h3&gt;生成API管理令牌&lt;/h3&gt;
&lt;p&gt;在概述界面点击&lt;code&gt;管理 R2 API 令牌&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./Snipaste_2024-02-15_18-11-48.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;点击&lt;code&gt;创建 API 令牌&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./Snipaste_2024-02-15_18-12-53.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;自定义令牌名称和权限。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./Snipaste_2024-02-15_18-14-03.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;创建成功后，把这四串字符复制下来存好，退出这个界面后它们将不再可查看。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./Snipaste_2024-02-15_22-33-25.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;配置 PicList&lt;/h2&gt;
&lt;p&gt;打开PicList，依次点击 &lt;code&gt;图床&lt;/code&gt;-&gt;&lt;code&gt;Amazon S3&lt;/code&gt; ，即可添加新图床配置。点击配置文件右上角指出的符号&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./Snipaste_2024-02-15_18-19-38.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;依据我图片的信息来填写图床配置，这一步较为重要，需要认真填写。&lt;/p&gt;
&lt;p&gt;上传路径那里，我填的是 &lt;code&gt;{year}/{month}/{fullName}&lt;/code&gt;，大家可以作个参考。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./Snipaste_2024-02-15_22-43-01.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;</content:encoded><h:img src="/_astro/PicList-cover.nmNdZS3E.webp"/><enclosure url="/_astro/PicList-cover.nmNdZS3E.webp"/></item><item><title>PyTorch 框架 + MNIST 数据集手写数字识别</title><link>https://djdog.cc/blog/2023/pytorch-mnist</link><guid isPermaLink="true">https://djdog.cc/blog/2023/pytorch-mnist</guid><description>PyTorch 手写数字识别</description><pubDate>Thu, 19 Oct 2023 11:00:12 GMT</pubDate><content:encoded>&lt;h2&gt;PyTorch&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;由 Facebook 人工智能研究小组开发的机器学习框架&lt;/li&gt;
&lt;li&gt;代码简洁、符合人类思维、易上手&lt;/li&gt;
&lt;li&gt;少量代码即可完成机器学习任务&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;MNIST 数据集&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;手写数字图片 7 万张&lt;/li&gt;
&lt;li&gt;训练集 6 万张 + 测试集 1 万张&lt;/li&gt;
&lt;li&gt;每张图片大小为 28*28 像素&lt;/li&gt;
&lt;li&gt;灰度值范围 0-255&lt;/li&gt;
&lt;li&gt;每张图片配有一个标记，既这张图片的真实值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;./mnist.webp&quot; alt=&quot;MNIST示例&quot;&gt;&lt;/p&gt;
&lt;h2&gt;设计神经网络&lt;/h2&gt;
&lt;p&gt;设有这样一张图片，大小为 5*5，内容为数字 7：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./mnist-eg.webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;将像素重新排列成为一维阵列，构成神经网络的&lt;code&gt;第零层节点&lt;/code&gt;，设第0层节点中的数值为 X00、X10、X20、……、X240&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;计算&lt;code&gt;第一层节点&lt;/code&gt;的数值，例如 X01 = ∑ai,10 * Xi0 + bi,10&lt;/p&gt;
&lt;p&gt;字母 &lt;code&gt;i&lt;/code&gt; 表示前一层的节点序号&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;同理构建第二、三、四层节点，节点传播公式也扩展为Xk+11 = ∑ai,1k * Xik + bi,1k&lt;/p&gt;
&lt;p&gt;字母 &lt;code&gt;k&lt;/code&gt; 和 &lt;code&gt;k+1&lt;/code&gt; 表示网络层数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;最后一层节点即为输出层，输出层有十个节点，每个节点对应 0-9 的数字，节点的数值就是该节点对应数字的概率，表示这张图片是某数字的概率&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;./neural-network.webp&quot; alt=&quot;神经网络示例&quot;&gt;&lt;/p&gt;
&lt;h2&gt;输出节点归一化&lt;/h2&gt;
&lt;p&gt;由于节点传播公式中的 &lt;code&gt;a&lt;/code&gt;、&lt;code&gt;b&lt;/code&gt; 是任意的，所以输出层节点上的数值也应该是任意的，但概率的取值范围是 0-1，且十个概率加在一起应该等于 1。&lt;/p&gt;
&lt;p&gt;所以将输出节点的数值进行如下处理：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用自然常数 e 对 X0、X1、X2、……、X9 进行一次指数运算，将变成每个数都变为正数，得到 eX0、eX1、X2、……、X9&lt;/li&gt;
&lt;li&gt;将上一步得到的十个数字求和，得到 ∑eXi&lt;/li&gt;
&lt;li&gt;用第二步中得到的数字作分母，用eX0、eX1、X2、……、X9 除以 ∑eXi&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这样便得到了在 0-1 范围内，且总和为 1 的数组，以上便是 &lt;code&gt;softmax 归一化&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;训练&lt;/h2&gt;
&lt;p&gt;上面的步骤得到了一组看上去像是概率的数字，但并不具备概率的意义，因为任意取值得到的 &lt;code&gt;a&lt;/code&gt;、&lt;code&gt;b&lt;/code&gt; 并不一定会使得到的数组接近真实概率，还需要经过训练才能让其具备识别的能力。&lt;/p&gt;
&lt;p&gt;所以，可以把神经网络理解为一个函数。训练的过程，就是调整函数中的参数的过程。在这个例子里面，我们每次只用了一张图片来调整网络参数，也可以每次将几个图片打包为一个 &lt;em&gt;&lt;strong&gt;batch&lt;/strong&gt;&lt;/em&gt;，一起发给神经网络来调整参数。&lt;/p&gt;
&lt;p&gt;上面的例子中，所有节点间的计算都是线性的，所以网络的总输入和总输出也是线性的。但对于很多问题，输入输出间存在非线性。所以我们会在在节点传播公式中套上一个非线性函数 &lt;em&gt;&lt;strong&gt;f()&lt;/strong&gt;&lt;/em&gt;，称为&lt;em&gt;&lt;strong&gt;激活函数&lt;/strong&gt;&lt;/em&gt;。常见的有对数函数、双曲函数、整流函数等等。&lt;/p&gt;
&lt;h2&gt;编写代码&lt;/h2&gt;
&lt;p&gt;这段代码用到了 numpy、torch、torchvision、matplotlib 四个库，用下面的命令进行安装：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pip install numpy torch torchvision matplotlib
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下面是项目代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import torch
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision.datasets import MNIST
import matplotlib.pyplot as plt


class Net(torch.nn.Module):

    def __init__(self):
        super().__init__()
        self.fc1 = torch.nn.Linear(28*28, 64)
        self.fc2 = torch.nn.Linear(64, 64)
        self.fc3 = torch.nn.Linear(64, 64)
        self.fc4 = torch.nn.Linear(64, 10)
    
    def forward(self, x):
        x = torch.nn.functional.relu(self.fc1(x))
        x = torch.nn.functional.relu(self.fc2(x))
        x = torch.nn.functional.relu(self.fc3(x))
        x = torch.nn.functional.log_softmax(self.fc4(x), dim=1)
        return x


def get_data_loader(is_train):
    to_tensor = transforms.Compose([transforms.ToTensor()])
    data_set = MNIST(&quot;&quot;, is_train, transform=to_tensor, download=True)
    return DataLoader(data_set, batch_size=15, shuffle=True)


def evaluate(test_data, net):
    n_correct = 0
    n_total = 0
    with torch.no_grad():
        for (x, y) in test_data:
            outputs = net.forward(x.view(-1, 28*28))
            for i, output in enumerate(outputs):
                if torch.argmax(output) == y[i]:
                    n_correct += 1
                n_total += 1
    return n_correct / n_total


def main():

    train_data = get_data_loader(is_train=True)
    test_data = get_data_loader(is_train=False)
    net = Net()
    
    print(&quot;initial accuracy:&quot;, evaluate(test_data, net))
    optimizer = torch.optim.Adam(net.parameters(), lr=0.001)
    for epoch in range(2):
        for (x, y) in train_data:
            net.zero_grad()
            output = net.forward(x.view(-1, 28*28))
            loss = torch.nn.functional.nll_loss(output, y)
            loss.backward()
            optimizer.step()
        print(&quot;epoch&quot;, epoch, &quot;accuracy:&quot;, evaluate(test_data, net))

    for (n, (x, _)) in enumerate(test_data):
        if n &gt; 3:
            break
        predict = torch.argmax(net.forward(x[0].view(-1, 28*28)))
        plt.figure(n)
        plt.imshow(x[0].view(28, 28))
        plt.title(&quot;prediction: &quot; + str(int(predict)))
    plt.show()


if __name__ == &quot;__main__&quot;:
    main()
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="/_astro/pytorch.B0sVlFPi.webp"/><enclosure url="/_astro/pytorch.B0sVlFPi.webp"/></item><item><title>使用 NVM 管理多个版本的 Node.js 以及配套的 NPM</title><link>https://djdog.cc/blog/2023/nvm</link><guid isPermaLink="true">https://djdog.cc/blog/2023/nvm</guid><description>NVM 是 Node.js 版本管理工具，可以很便捷地通过命令行快速安装和使用不同版本的Node。</description><pubDate>Thu, 06 Jul 2023 21:38:02 GMT</pubDate><content:encoded>&lt;p&gt;我们可能在工作和学习中可能都会遇到需要使用多个node版本的时候，NVM可以很好地解决这个问题。&lt;a href=&quot;https://github.com/nvm-sh/nvm&quot;&gt;NVM&lt;/a&gt; 全称 node.js version management ，是开源的 nodejs 版本管理工具。通过它我们就可以很便捷地通过命令行快速安装和使用不同版本的 Node。&lt;/p&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;p&gt;如果现在电脑上有安装 node，切记把它卸载掉。如果是 Windows 系统且有配置过环境变量，记得把环境变量一起删掉。&lt;/p&gt;
&lt;p&gt;卸载结束后，用下面的命令安装：&lt;/p&gt;
&lt;p&gt;Windows：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;winget install &apos;NVM for Windows&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Linux：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;export NVM_DIR=&quot;$HOME/.nvm&quot; &amp;#x26;&amp;#x26; (
  git clone https://github.com/nvm-sh/nvm.git &quot;$NVM_DIR&quot;
  cd &quot;$NVM_DIR&quot;
  git checkout `git describe --abbrev=0 --tags --match &quot;v[0-9]*&quot; $(git rev-list --tags --max-count=1)`
) &amp;#x26;&amp;#x26; \. &quot;$NVM_DIR/nvm.sh&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等待下载结束后自动安装。然后添加环境变量，这里就不作教程了。&lt;/p&gt;
&lt;p&gt;然后运行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;nvm version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果出现了版本号，则表示安装成功。&lt;/p&gt;
&lt;p&gt;然后将下面的代码加入到你的 &lt;code&gt;~/.bashrc&lt;/code&gt;、&lt;code&gt;~/.profile&lt;/code&gt;或&lt;code&gt;~/.zshrc&lt;/code&gt;中：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;export NVM_DIR=&quot;$HOME/.nvm&quot;
[ -s &quot;$NVM_DIR/nvm.sh&quot; ] &amp;#x26;&amp;#x26; \. &quot;$NVM_DIR/nvm.sh&quot;
[ -s &quot;$NVM_DIR/bash_completion&quot; ] &amp;#x26;&amp;#x26; \. &quot;$NVM_DIR/bash_completion&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;使用&lt;/h2&gt;
&lt;p&gt;要下载、编译和安装最新版本的node，请执行以下命令，会自动安装最新的&lt;code&gt;node&lt;/code&gt;和它对应版本的&lt;code&gt;npm&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;nvm install node # &quot;node&quot; 是最新版本的别名
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;要是需要某一个版本的&lt;code&gt;node&lt;/code&gt;，则运行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;nvm install &amp;#x3C;version&gt; # 将其替换成你所需要的版本号
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;卸载指定版本，语法与 &lt;code&gt;install&lt;/code&gt; 用法一致：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;nvm uninstall &amp;#x3C;version&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;切换使用指定的版本 &lt;code&gt;node&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;nvm use &amp;#x3C;version&gt; # 临时,只在当前窗口生效指定版本

nvm alias default &amp;#x3C;version&gt; # 永久,所有窗口生效指定版本
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;使用国内 npm 镜像加速下载&lt;/h2&gt;
&lt;p&gt;出于众所周知的原因~~GFW~~，国内使用 &lt;code&gt;npm&lt;/code&gt; 下载的速度可能不是很快，可以使用 &lt;a href=&quot;https://npmmirror.com/&quot;&gt;cnpm&lt;/a&gt; 来解决：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install -g cnpm --registry=https://registry.npmmirror.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者你直接通过添加 &lt;code&gt;npm&lt;/code&gt; 参数 alias 一个新命令:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;alias cnpm=&quot;npm --registry=https://registry.npmmirror.com \
--cache=$HOME/.npm/.cache/cnpm \
--disturl=https://npmmirror.com/mirrors/node \
--userconfig=$HOME/.cnpmrc&quot;

# Or alias it in .bashrc or .zshrc
$ echo &apos;\n#alias for cnpm\nalias cnpm=&quot;npm --registry=https://registry.npmmirror.com \
  --cache=$HOME/.npm/.cache/cnpm \
  --disturl=https://npmmirror.com/mirrors/node \
  --userconfig=$HOME/.cnpmrc&quot;&apos; &gt;&gt; ~/.zshrc &amp;#x26;&amp;#x26; source ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="/_astro/nodejs-wallpapers.xBAgnPAe.webp"/><enclosure url="/_astro/nodejs-wallpapers.xBAgnPAe.webp"/></item></channel></rss>