Recent Posts

Roy Binux's avatar

猫之城物理钓鱼挂(二):图像采集以及画面分类

上一篇中,我们实现了屏幕触控的物理输出,但是钓鱼这个小游戏还是需要根据画面反馈来做动作的。我一开始的想法是用一个摄像头拍摄平板的画面然后进行图像处理。尝试了一会发现,就摄像头这 720P 的分辨率,光是梯形校正准确率都不高,可能做个图像分类还行,但是要分辨画面中的信息对我来说还是有些困难。然后睡前一阵查找,发现了软件实现的 AirPlay。

图像采集

AirPlay 是 Apple 的屏幕镜像和投影协议,这个协议已经被逆向并且有软件实现了,例如 LetsView, AirServer。通过 AirPlay + 接收软件,我们可以将 iPad 画面镜像投影到电脑上,分辨率更高,而且没有色差,处理起来就更简单了。如果是安卓的平板,也可以通过 Chromecast 或者 Miracast 协议投影,原理是一样的。

当图像投影到 PC 上之后,就可以通过截取 PC 屏幕窗口的的方式获取到平板画面内容。第一种方案是使用 MSS,一个跨平台的 Python 截图包,它能以大约 20 FPS 的速度捕获图片。使用也很简单,首先需要获取投影软件的窗口位置和大小,然后按帧截图发送给 OpenCV 处理。实现的代码在这里:screen_capture.py。由于 MSS 并没有提供获取窗口大小的方法,它的区域捕获仅仅依靠的是屏幕坐标。所以获取窗口还是需要我们自己实现的,而这部分不是跨平台的,也没办法获知窗口移动。再加上 MSS 仅仅是截图,当窗口在后台时就失效了,使用起来并不方便。

而更好的方法是通过 OBS + 虚拟摄像头 + OpenCV,对的,就是平时游戏主播使用的直播软件。简单来说就是使用 OBS 捕获投影软件窗口,再通过虚拟摄像头输出给 OpenCV。OBS 软件本身是跨平台的(但是在不同平台可能会有些不同),FPS 要多少有多少,而且窗口可以被遮挡(窗口不能最小化到后台,但是可以放在另一个 Virtual Desktop),窗口移动什么的也完全没有问题,专业的确实就是专业。OBS 设置部分很简单,只要增加一个 Source,然后再根据需要调整输出分辨率就好了。Python 部分的源代码在:obs_capture.py

Note:虽然最新的 OBS 自带了 Virtual Cam,但是似乎在 Windows 上和 OpenCV 有兼容性问题,捕获的画面是黑的,依旧需要使用插件解决。

画面分类

现在采集到了平板上的游戏画面,下一步就是给画面进行分类,来获得游戏所处的界面。这么做主要有这些原因:

  1. 很多游戏操作是有网络交互的,当点击按钮之后,会有不定长的延迟进入下一个界面,在下一步操作前进行画面分类识别能更鲁棒
  2. 在有的界面中,存在需要进一步识别的交互内容,例如钓鱼小游戏的浮标。先识别界面类型,能更有效和准确地决定是否需要进行这些信息提取。
  3. 获取当前状态可以使 bot 更灵活,脚本可以从任意状态启动。这一部分会再 第四篇 blog 中讲到。

在这个项目中,我直接抄了 tensorflowImage Classification Tutorial。对于这种标准的 UI 界面,随便什么模型效果应该都不差:classifier_training.ipynb

做图片分类的第一步是采集训练样本,你会注意到 screen_capture.pyobs_capture.py__main__ 部分都有 cv.imwrite 以及对应的按键绑定的代码。我首先会在开启图像采集的过程中,游玩游戏,手动进行需要自动化的整个流程,手动或者每 1 秒地频率采集一些原始图像。然后对应每一个分类新建一个文件夹,例如在《猫之城》中,我有 fish_idle, fish_ring, fish_drag, fish_reward 和 not_supported 这样一些分类。然后将采集到的图片拖到对应分类的文件夹中,我对于分类和图片的选取是这样的:

  • 分类之间的图像需要有较大的不同。例如,点击之后显示的确认对话框就没必要单独建立一个分类。
  • 每个分类选取至少 10-20 张 不同 的图片,尽量涵盖这个类别可能出现的所有变种,例如《猫之城》中 fish_idle 会出现不同的场景导致背景不一样。
  • 单个类别不应该有远多于别的类别的样本,最多和最少之间不超过 10 倍这样。
  • not_supported 可以用来放一些脚本用不到的 UI 截图来增加类别之间的差异性,以及在进入没有分类的页面的时候不会错误激活脚本。

然后就是套代码了,图片分类并不需要很高的图片分辨率,这里我随便选了一个 220x300 来保持图片宽高比,套示例模型就能达到 99% 的准确度了。因为是 UI 界面,也不存在裁切变换,之后实际测试结果也非常好。最后将分类列表和模型保存下来就可以啦。为了保存单个文件,并且减少体积,使用的是 TensorFlow Lite 模型,predict 的代码在 classifier.py。唯一需要注意的是使用的时候需要自己 resize 到 220x300,并且 OpenCV 图片的颜色是 BGR 而 tensorflow 是 RGB 的,需要要进行转换。其他就没什么了,总共有效代码也就 15 行,踩着巨人的肩膀,使用成熟的库之后还是挺简单的。

Note: 图片中的 fish_ring = 099% 就是图片分类的结果和 score,而其他的图片识别内容和辅助线就在下一篇 blog 中讲解啦。

依云's avatar

让离线软件真正离线

本文来自依云's Blog,转载请注明。

去年我做了个索引 Telegram 群组的软件——落絮,终于可以搜索到群里的中文消息了。然而后来发现,好多消息群友都是通过截图发送的,落絮就索引不到了。也不能不让人截图嘛,毕竟很多人描述能力有限,甚至让复制粘贴都能粘出错,截图就相对客观真实可靠多了。

所以落絮想要 OCR。我知道百度有 OCR 服务,但是我显然不会在落絮上使用。我平常使用的 OCR 工具是 tesseract,不少开源软件也用的它。它对英文的识别能力还可以,尤其是可自定义字符集所以识别 IP 地址的效果非常好,但是对中文的识别能力不怎么样,图片稍有不清晰(比如被 Telegram JPEG 压缩)、变形(比如拍照),它就乱得一塌糊涂,就不说它给汉字之间加空格是啥奇怪行为了。

后来听群友说 PaddleOCR 的中文识别效果非常好。我实际测试了一下,确实相当不错,而且完全离线工作还开源。但是,开源是开源了,我又没能力审查它所有的代码,用户量太小也不能指望「有足够多的眼睛」。作为基于机器学习的软件,它也继承了该领域十分复杂难解的构建过程,甚至依赖了个叫「opencv-contrib-python」的自带了 ffmpeg、Qt5、OpenSSL、XCB 各种库的、不知道干什么的组件,试图编译某个旧版 numpy 结果由于太旧不支持 Python 3.10 而失败。所以我决定在 Debian chroot 里安装,那边有 Python 3.9 可以直接使用预编译包。所以问题来了:这么一大堆来源不明的二进制库,用起来真的安全吗?

我不知道。但是我知道,如果它联不上网的话,那还是相对安全的。毕竟我最关心的就是隐私安全——一定不能把群友发的图片泄漏给未知的第三方。而且联不上网的话,不管你是要 DDoS 别人、还是想挖矿,收不到指令、传不出数据,都行不通了嘛。我只要它能从外界读取图片,然后把识别的结果返回给我就好了。

于是一个简单的办法是,拿 bwrap 给它个只能访问自己的独立网络空间它不就访问不了互联网了吗?不过说起来简单,做起来还真不容易。首先,debootstrap 需要使用 root 执行,执行完之后再 chown。为了进一步限制权限,我使用了 subuid,但这也使得事情复杂了起来——我自己都难以访问到它了。几经摸索,我找到了让我进入这个 chroot 环境的方法:

#!/bin/bash -e

user="$(id -un)"
group="$(id -gn)"

# Create a new user namespace in the background with a dummy process just to
# keep it alive.
unshare -U sh -c "sleep 30" &
child_pid=$!

# Set {uid,gid}_map in new user namespace to max allowed range.
# Need to have appropriate entries for user in /etc/subuid and /etc/subgid.
# shellcheck disable=SC2046
newuidmap $child_pid 0 $(grep "^${user}:" /etc/subuid | cut -d : -f 2- | tr : ' ')
# shellcheck disable=SC2046
newgidmap $child_pid 0 $(grep "^${group}:" /etc/subgid | cut -d : -f 2- | tr : ' ')

# Tell Bubblewrap to use our user namespace through fd 5.
5< /proc/$child_pid/ns/user bwrap \
  --userns 5 \
  --cap-add ALL \
  --uid 0 \
  --gid 0 \
  --unshare-ipc --unshare-pid --unshare-uts --unshare-cgroup --share-net \
  --die-with-parent --bind ~/rootfs-debian / --tmpfs /sys --tmpfs /tmp --tmpfs /run --proc /proc --dev /dev \
  -- \
  /bin/bash -l

这里给了联网权限,是因为我需要安装 PaddleOCR。没有在创建好 chroot 之后、chown 之前安装,是因为我觉得拿着虽然在 chroot 里但依旧真实的 root 权限装不信任的软件实在是风险太大了。装好之后,再随便找个图,每种语言都识别一遍,让它下载好各种语言的模型,接下来它就再也上不了网啦(为避免恶意代码储存数据在有网的时候再发送):

#!/bin/bash -e

dir="$(dirname $2)"
file="$(basename $2)"

user="$(id -un)"
group="$(id -gn)"

# Create a new user namespace in the background with a dummy process just to
# keep it alive.
unshare -U sh -c "sleep 30" &
child_pid=$!

# Set {uid,gid}_map in new user namespace to max allowed range.
# Need to have appropriate entries for user in /etc/subuid and /etc/subgid.
# shellcheck disable=SC2046
newuidmap $child_pid 0 $(grep "^${user}:" /etc/subuid | cut -d : -f 2- | tr : ' ')
# shellcheck disable=SC2046
newgidmap $child_pid 0 $(grep "^${group}:" /etc/subgid | cut -d : -f 2- | tr : ' ')

# Tell Bubblewrap to use our user namespace through fd 5.
5< /proc/$child_pid/ns/user bwrap \
  --userns 5 \
  --uid 1000 \
  --gid 1000 \
  --unshare-ipc --unshare-pid --unshare-uts --unshare-cgroup --unshare-net \
  --die-with-parent --bind ~/rootfs-debian / --tmpfs /sys --tmpfs /tmp --tmpfs /run --proc /proc --dev /dev \
  --ro-bind "$dir" /workspace --chdir /workspace \
  --setenv PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
  --setenv HOME /home/worker \
  -- \
  /home/worker/paddleocr/ocr.py "$1" "$file"

kill $child_pid

这个脚本会把指定文件所在的目录挂载到 chroot 内部,然后对着这个文件调用 PaddleOCR 来识别并通过返回结果。这个调用 PaddleOCR 的 ocr.py 脚本位于我的 paddleocr-web 项目

不过这也太复杂了。后来我又使用 systemd 做了个服务,简单多了:

[Unit]
Description=PaddleOCR HTTP service

[Service]
Type=exec
RootDirectory=/var/lib/machines/lxc-debian/
ExecStart=/home/lilydjwg/PaddleOCR/paddleocr-http --loglevel=warn -j 2
Restart=on-failure
RestartSec=5s

User=1000
NoNewPrivileges=true
PrivateTmp=true
CapabilityBoundingSet=
IPAddressAllow=localhost
IPAddressDeny=any
SocketBindAllow=tcp:端口号
SocketBindDeny=any
SystemCallArchitectures=native
SystemCallFilter=~connect

[Install]
WantedBy=multi-user.target

这里的「paddleocr-http」脚本就是 paddleocr-web 里那个「server.py」。

但它的防护力也差了一些。首先这里只限制了它只能访问本地网络,TCP 方面只允许它绑定指定的端口、不允许调用 connect 系统调用,但是它依旧能向本地发送 UDP 包。其次运行这个进程的用户就是我自己的用户,虽然被 chroot 到了容器里应该出不来。嗯,我大概应该给它换个用户,比如 uid 1500,应该能起到跟 subuid 差不多的效果。

顺便提一句,这个 PaddleOCR 说的是支持那么多种语言,但实际上只有简体中文等少数语言支持得好(繁体都不怎么样),别的语言甚至连语言名和缩写都弄错,越南语识别出来附加符号几乎全军覆没。

Roy Binux's avatar

猫之城物理钓鱼挂(一):物理模拟触屏点击

真的有2年半没有写 blog 了。我是那种不愿意在事情尘埃落定之前,把它写下来的类型。在这两年半里,H1B 抽到了,也跳槽了。收入上去之后,也更愿意花钱解决问题,而不是自己做点什么,有好几次想要提笔,又感觉没什么好写的。以后会改善吗?我觉得不会,虽然我依旧会去尝试各种新的东

依云's avatar

我所讨厌的网页行为

本文来自依云's Blog,转载请注明。

有些网页的行为通常不被视为 bug,甚至是故意为之,但很令人讨厌。这里记录一些我所讨厌的网页「特性」。它们被归为两类,要么导致某些场景下用不了,或者用着很不方便,要么很打扰人。

可访问性问题

忽视系统、浏览器设置,在浏览器使用浅色主题的情况下默认使用深色主题,或者在浅色主题下代码部分使用深色主题。反过来问题不大,因为我有 DarkReader

主体文本不支持选择和复制。选择和复制之后,用户能做很多事情,比如查生字、翻译、搜索相关主题。

已访问链接与未访问链接显示没有差别。

消除可交互元素(链接、按钮)的 outline。这个 outline 以前是虚线框,现在火狐改成了蓝色框,用于标识当前键盘交互的对象。

搜索框不支持回车确认,必须换鼠标点击。

位于文本框后的按钮不支持使用 Tab 键切换过去,并且 Tab 键在此文本框中也没有任何显著的作用。必须换鼠标点击。

需要交互的元素不能被 vimium 插件识别为可点击。这大概是使用非交互元素来处理交互事件,甚至事件监听器都不在元素本身上。

使用 JavaScript 实现原本可以直接用链接实现的内容(链接目标是某个 JavaScript 函数调用)。这导致我无法使用中键来在新标签页中打开。

显著不同的内容没有独立的 URL。尤其见于一些单页应用(SPA)。要到达特定内容(比如加书签或者分享给别人),就只能记录先点哪里、再点哪里等。

预设用户的屏幕大小,导致浏览器窗口过小的时候部分关键内容(如登录按钮)看不到、无法操作。

交互元素没有无障碍标签。成堆的「未加标签 按钮」。

通过 User-Agent 判断浏览器,并拒绝为某些 User-Agent 服务(但实际上去除这个限制之后,功能是完全没有问题的)。

当没有带声音自动播放权限时,无声播放主体内容(而非等待用户操作使其获得权限)。说的就是 Bilibili。

为大屏幕用户(如桌面用户)展示为手机屏幕设计的页面。这些页面中字体特别巨大,并且不能被浏览器缩放影响。交互元素上鼠标指针不改变为手状,甚至只支持触摸操作而不支持鼠标点击。

悬浮于主内容之上的「在App中打开」。点名批评 imgur。它的按钮不光挡住图片,而且用户放大图片的时候它也被放大,挡住更多图片内容。

不能禁用的图片懒加载,或者视频内容被移出画面、切换到后台就停止加载。点名批评 Telegram、维基百科。我等你加载呢,你非要我盯着看你加载浪费时间?现在网好,你赶紧给我加载好,进电梯或者地铁或者山洞了,我再慢慢看你的内容啊。

视频内容被移出画面就停止播放。点名批评知乎。我让你播放你就给我播放。我不看视频,是因为视频画面没啥可看的,可是我听音频部分呀。

覆盖浏览器的 Ctrl-F 查找快捷键,并不提供方案来避免覆盖。我就搜索当前页面,不要你的站内搜索功能。

注册前请务必先阅读用户条款和规则,用户条款和规则页面需登录后才可访问。

简体中文内容指定繁体中文的字体,或者添加繁体中文的标签。或者反过来。

打扰用户

在内容页面,任何会动的非主体内容,包括但不限于广告、内容推荐。形式可以是动态 GIF、滚动动画、视频等。用于首页渲染效果的背景动画和视频不算,作为主体内容者也不算。

针对非音视频网站,自动或者非用户明确表达地(比如在用户点击不相关内容时)播放带音频的内容。

消耗 CPU 的背景特效。如 canvas-nest。会让 CPU 很吵,也会浪费能源、加剧气候变化。

依云's avatar

tmux 状态栏优化

本文来自依云's Blog,转载请注明。

在 tmux 的状态栏里,通常会显示当前时间。配置起来也非常简单,%Y-%m-%d %H:%M:%S这样的时间格式化字符串扔过去就可以了。然而这样做有个小问题:这个时间只能精确到秒。我的意思不是说我想让它显示毫秒,而是希望它像电视台和广播电台的时间一样,显示(播报)「12:00:00」的时候,就刚好是这一秒的开始。

一般来说,这么延迟个一秒以内的随机数问题不大,除了你有多个这种时间戳的时候——

这些时间戳哪个先更新、哪个后更新可完全说不准的,你可能看到明明在地球另一边的服务器上先到某一秒,本地才跟上。甚至同一个 tmux 的不同客户端里,这个时间戳的更新时间都可能会有差异。

我想优化这个的另一个原因是,我经常使用 extrace 来查看程序调用另一程序使用的命令行参数,然而我本地连了多少个 tmux,每秒便会有多少个 sh + awk 进程出来读系统负载。尤其是我从 Awesome 换到 Wayfire 之后,顶栏改用 waybar 了,很多指示器都是内建或者自己写的外部脚本,不再需要每隔几秒跑个子进程去获取信息,这样 tmux 调用子进程来刷新状态造成的干扰就突显了出来。

于是就有了 accurate-time 程序。它每个整秒会去读系统负载,然后和当前时间一起送给 tmux 来显示。每秒一个进程,已经少了很多啦。

既然是我的程序自己来读负载,也就方便做更多事情了,比如根据负载情况使用不同的文字颜色:绿色表示低负载,灰白是稍微有点活干,蓝色和 cyan 是比较忙碌,黄色、品红表示已经忙不过来啦,红色就是要累趴下啦。之前偶然间发现 qemu-git 这个包使用 ninja、但是链接的时候又套了一层 make,造成系统负载冲到了两百多。但是无论高低,tmux 的负载显示都是红色,所以我可能之前已经视而不见许多次了。加上颜色之后,这类异常就更容易被注意到了。以前我本地每次风扇呼呼地转才发现系统负载高,但是我要是用耳机的话就听不到了,现在也多了个高负载的指示。

安装和配置很简单,cargo build --release 编译,然后把编译出来的 target/release/accurate-time 扔到 $PATH 里,再如下配置 tmux 状态栏右边即可:

if-shell "accurate-time tmux" {
  set -g status-interval 0
} {
  set -g status-interval 1
  set -g status-right "#[fg=red]#(awk '{print $1, $2, $3}' /proc/loadavg) #[fg=colour15]%Y-%m-%d %H:%M:%S"
}

本来我还打算给 waybar 上的时间也这么做一下的,不过程序写好了才发现 waybar 自己已经把时间对齐到更新间隔了。

依云's avatar

Google Chrome 中的字体设置

本文来自依云's Blog,转载请注明。

Google Chrome 是我的备用浏览器,主要用于对比和检查网页的渲染效果,以及某些网页在火狐上可能不太正常,就用 Google Chrome 试试。

但 Google Chrome 有个非常令人恼火的问题:默认字体实在太难受了!

如果没有指明字体,那么 Google Chrome 默认使用 Times New Roman 字体。这是我十年前从 Windows 那边拷过来的字体,看上去细细软软的,很复古,不太适合屏幕显示。屏幕显示一般使用无衬线字体,但 Google Chrome 默认是衬线字体。好吧,那网页要是指明要 sans-serif 字体呢?Google Chrome 这次看上了 Arial,同样是一款古老的、来自于 Windows 的字体。

行吧……反正我也不是多喜欢这两字体,就全部删掉好了!结果,呃,「自定义」??

实际上它们分别是「Liberation Serif」和「Liberation Sans」字体。这是我的系统上 fc-match「Times New Roman」和「Arial」给出的字体,由 ttf-liberation 包提供,google-chrome 包依赖(看 AUR 上的评论,这是因为 Google Chrome 的 PDF 渲染需要这个字体)。

Google Chrome 就是这么喜欢 Times New Roman 和 Arial,系统上不安装它也要找个替代品来用,就是不听用户通过 fontconfig 设置的默认字体。用户要想 Google Chrome 听点话,需要在「设置」->「外观」->「自定义字体」里像这样设置一下:

而火狐的话,用户不需要在这种犄角旮旯里设置:

可惜大部分用户都在用 Google Chrome 或其变种,所以制作网页上还是得手动指定一些现代点的字体。

RecursiveG's avatar

折腾 RISC-V 单片机 Part1

大约半年前在 SparkFun 上买了一块 RED-V 开发板。基本算是 HiFive1 Rev B 的克隆,比 Rev B 便宜一些,同样使用 SiFive 的 FE310-G002 处理器。SiFive 的 MCU 自带一套 SDK,不过要搭配指定的 IDE 才好用,作为有洁癖的 Linux 用户这当然是不行的,所以就有了这次的折腾。

准备工作

我一开始是打算用 SDK 的代码,不过看了一圈感觉这样和玩 Arduino 也没区别了,失去了折腾的意义,所以决定放弃 SDK 直接用汇编艹寄存器。
这里是需要准备的文档和工具:

  • SparkFun RED-V Schematic: 这是板子的电路图,用来看板子上的接口都具体连接到 MCU 的哪个针脚。
  • Freedom E310-G002 Datasheet/Manual: 这两份文件可以从 SiFive 的网站上下载到,包含几乎所有重要信息。
  • Clang: 编译器。为啥不用 GCC?因为我不想单独折腾一份 GCC 的工具链。Clang 既可以编译出 x86 程序又可以编译出 RISC-V 程序,从软件源里装好就可以直接用了。
  • LLD: LLVM Linker。这下也不用配置 RISC-V 的 binutils 了
  • OpenOCD: 负责和板子通信,烧录程序,调试等。

三份 PDF 文档需要自己下载,而其他三个程序应该能直接用包管理装。

单片机基础

简单而言,单片机不像 CPU,有各种内存保护/分页机制等。所有的硬件控制/非易失存储(硬盘)/易失存储(内存)都位于同一个 Memory space。
详细信息可以在 Manual Chapter 4 中看到,比如说,[0x20000, 0x21FFF] 就属于 “OTP Memory Region”。

另外一些地址可以用于控制硬件,比如[0x1001_2000, 0x1001_2FFF]属于 GPIO,稍后可以看到,如果往某个特定的地址写1,那么芯片上的某个针脚的电平(电压)就会发生变化,如果这个针脚上连了一个 LED,那么它的亮灭状态也会发生变化。这些可以控制硬件行为的地址我一般称之为寄存器,注意不要和汇编语言里的寄存器搞混了。

程序应该放在哪儿?

一个重要的问题是,单片机在启动的时候到底会执行哪条指令?查看 Manual Chapter 5.1 可知:

On power-on, the core's reset vector is 0x1004.

即会首先执行 0x1004 处的指令(练习:请翻阅 Memory Map 查看该地址属于哪片区域?)并且手册也列出了预先烧录在该地址的指令列表。不过很可惜我并没有找到文档里所说的 MSEL pin 在哪里,不过从调试结果来看,0x1018处的jr指令最终会跳转到0x10000处。

继续阅读 Manual 5.1.1, 0x10000处的指令会跳转到0x20000,继续阅读Datasheet Chapter 5 “Boot code”,我们最终会跳转到地址0x20000000,查看memory map,该地址属于QSPI 0 Flash,也就是非易失存储器,看上去这里就是我们应该写入代码的地方了。(PC程序员初次看到Program counter能直接指向外部存储设备实在是刷新三观)。

编程器

向单片机写入程序的过程被称作 program(编程),所以用来编程的硬件也就叫做“编程器”了。还有一个我无论如何都无法理解的翻译叫做“仿真器”,英文叫 emulator, 这应该也是一个上古词汇,但是比起“编程器”,这个词更强调你可以调试单片机上的程序,比如下断点,单步执行等。现在一般用来指链接单片机和电脑的那根线。总而言之,你需要一个东西把单片机和电脑连起来,以便两者通信。

一般来说,这个硬件一头用JTAG等方式连接到单片机,另一头通过USB协议连接电脑,OpenOCD则是一个开源的程序允许你通过这个“编程器”以各种方式操纵各种单片机。当然也包括向 SPI Flash 中写入我们的程序。

在 RED-V 上,最大的芯片是一块 MK22FN128 的ARM单片机,这块单片机里预先写入了一个 J-Link OB 的商业程序,这个程序让这个ARM单片机实现了编程器的功能,所以我们只要直接用普通的USB线连接板子和电脑就可以了。J-Link 使用一种特殊的协议与电脑通信,好在Segger公司公开了这种协议的spec,所以OpenOCD也能和编程器通信啦。

TLDR

  • 单片机通电后会经过一系列跳转,最终开始执行 0x20000000 处的指令。
  • 该地址实际访问的是外部的存储器。
  • 可以通过编程器向该存储器中写入数据。

To be continued in part 2.

AlisterTT's avatar

谁是红码

灵感记录一下

感觉可以出一个类似狼人杀的桌游“谁是红码”。基础机制是,每个人拿一堆位置卡牌,例如俩人都出了“酒吧”,那你就被感染了。所有人都感染了红码获胜,幸存者得努力找出红码隔离获胜。然后在这个基础上可以添加一些别的机制,例如银行管理员和储户,管理员可以给储户发放伪红码,储户则需要证明自己是安全的,否则就会被投出去隔离。

狼人杀添加一个角色叫小熊猫,小熊猫是一张明牌,这个角色没有任何屁用,晚上得闭眼,第二天可以参与讨论,但是不能投票,狼人可以杀他,但是杀了小熊猫也没有任何屁用,小熊猫是一张中立卡。小熊猫给大家买了零食算获胜。

's avatar

金恋,和一些最近的作品

写在前面

不用说也知道,本篇会有很多剧透。以前我大概会放一个大大的警示框在这里,列举一下包含哪些作品的剧透。但是我忘了怎么写的了。不过话说回来,提前告诉读者有什么剧透,难道不也是一种剧透吗?

那么,本篇大概包含金恋(金色ラブリッチェ)的剧透。

金色时光

如果有人问,说到金恋,你脑海里浮现的是什么画面?

我的答案一定是那反复出现的,波光粼粼的湖面。

游戏里,关于湖的传说虽然一带而过了,但是死,确确实实是永恒的话题。过于永恒而不知该从何说起。就算说,可能也会是一些老生常谈,不过我还是想努力讲一些有意思的事情。那么就看我下面的发挥了。 对一个人来说,死意味着物质的消失和思想的消逝,不过对他人来说,这个人的又意味着什么呢?我问这个问题,是因为想到,我好久没有联系小学的同学了。如果说,一个人的死意味着没法再见到他们,那么对我来说——我明白这个说法不好——现在的联系不上的状态和死了,没有什么区别。

我们的关系在渐渐死去,变成说得上一点点话的陌生人。

如果一个陌生人死了,我的感想,当然排除没有感想的情况,应该不是针对死者的,而是一些泛泛的、漠不关心的感想:人如何脆弱、人生如何缥缈,如此这般。

高中的时候,隔壁班就有一个同学事故身亡。但是我不认识他。有同学说,他挺开朗的,不可能是自杀;有同学说,可惜了。我没有说什么。那天晚上,教学楼下摆了一圈蜡烛,他的一些朋友在那里默哀,我也去了。看着摇曳的烛光,我想着我要好好活着。结束后,他的妈妈几乎说不出话来,但是还是安静地说了谢谢你们来。离开的时候看着他的父母,我隐隐担心他们的婚姻还能否继续下去。不过也就仅此而已了。

对更亲近的人,抱有的感情应该会有所不同。我的记性很差,很久以前的事情大都记不太清楚了。要提最近的事情大概就是外婆了。每次去姨妈家,外婆是最关心我的那个。新年的时候,甚至还会塞给我压岁钱。临走的时候,总是希望我很快再回来一趟。然而这几年,我因为种种原因未能回家。远程电话的时候,看着她期待的眼神,我口头上说会早点回来,但也不敢保证什么时候。就在几个月前,家父打来电话说,外婆过世了。听到消息的时候,我不知所措。然后我想起来了:我终究没能回去见她一面。

外婆肯定不会怪我,她从来也没有说过我一句坏话。家父也没有责怪我。责怪我的从来都是我自己。可是,生者如何快活如何悲伤,同逝者又有何关呢?活的人永远没法替死人着想。所以我想,这喜怒哀乐大抵都是要归结到自己身上来的。

话说回来,只有归结到自身上来,才能成为实实在在的感觉。他人的小脚趾撞到桌角,与我又有何干?肯定是大笑一场。在纪念一些人的时候,有时会说没有X就没有Y,这也是把逝者的所作所为跟我们的现在联系起来。不然,光荣事迹再光荣,换来的大概也就是个无声的“哦”吧。

这里就用葬礼之后的问答收尾吧。可以算是在身边人过世后心理活动的一个例子吧。

“我有在闪闪发光吗,她没有对我失望吧?”

“我真的成为世界上最帅的男友了吗?”

其他一些最近玩过看过的作品

Judgment,这个就死很多人了。大家都是硬派,没什么话说。

52赫兹的鲸(52ヘルツのクジラたち)。标题的来源是源自一头特别的鲸。通常鲸声音的频率在10-40Hz,而这头鲸的声音却超出了这一范围。因为据称别的鲸听不到这个频段的声音,人们称它为“最孤独的鲸”。这头鲸数年来没有被找到,只有它的声音飘荡在海洋里。全本书里我觉得美晴是里面最讨喜的人物了,最后她回去的时候我眼泪掉下来。我在想,天鹅之歌是不是也能用来形容这些没有被听到的SOS呢?查了下词典,再仔细想想,还是没那么像。

三体。看完之后有点激动,第三卷那个时间跨度大的不得了,有些追不上。

Ratchet & Clank, the game和rift apart。这个两纯粹是老少皆宜的有趣游戏。

LUNARiA。不错的作品,我还在等松山写流星群的下一卷。

白金数据。开头居然有像是harmony的梗(人人身上装着IC芯片,由政府监督一举一动),有点快乐。

大概就这么多。如果要问我是什么刻骨铭心的内容的话,我说不上来。好酒也是要反复品才能出味的,像我这样,囫囵吞枣,不加思考地吸收,可能最后就忘得一干二净了。

Phoenix Nemo's avatar

修复 CentOS 'org.freedesktop.login1' timed out

又到了喜闻乐见帮人修系统的时间。

Felix Yan's avatar

萌新的 PolarFire SoC Icicle Kit 初体验

这两天翻出来了去年代收的 PolarFire SoC Icicle Kit。因为隔壁的 FPGA 大佬们看不上这块板子,我打算尝试物尽其用一下,目标只是用板子上的 RISC-V 核启动 Arch Linux RISC-V 的 rootfs 测试(把它当作一块 SD 卡槽没有问题、并且带 PCIE 的 HiFive Unleashed 来用。隔壁嵌入式群的大佬们:买椟还珠!)。如此便开始了年轻人的 FPGA 初体验(可能还是不能算)。

噩梦的开始

一开始尝试的当然是最新版的 Yocto 镜像,毕竟这是“官方”的 Linux 镜像。结果刷完后立刻遇到了启动失败:

一开始我还以为是 SD 卡坏了。在多次尝试未果后……

当时的猜测是(不一定对),可能因为板子上 FPGA 部分(抱歉,我不知道专业的称呼)不够新,所以我打算刷一下 HSS。结果这成为了噩梦的开始。

可怕的“硬件”工具链

我最初参考的文档来自 U-boot:https://u-boot.readthedocs.io/en/latest/board/microchip/mpfs_icicle.html

这份文档可能已经颇为过时,里面编译 HSS 的部分从一开始就找不到名叫“icicle-kit-es”的 BOARD.

在我加上 mpfs- 前缀,并根据后续报错依次按照我的 CROSS 工具链目标修改了 PLATFORM_RISCV_ABI=lp64d PLATFORM_RISCV_ISA=rv64gc 之后,我遇到了第一个大魔王:SoftConsole

好在这个工具可以无需注册直接下载。

顺利安装完成后,按照要求设置 SC_INSTALL_DIR,我终于看到了……下个错误:缺少 fpgenprog。

由于不想安装完整的 Libero SoC(一个巨大的需要折腾 license 的开发工具集),我试图去下载这里提到的 Program Debug Tool。从文档上找到下载链接点开后,看到了这样的悲剧:

它没了。

后面提到的 Programming and Debug 工具下载也藏在了注册墙后面,我考虑转向其他思路试试,先暂时没有继续了。

(另:关于 Libero SoC 的安装会有多坑,可以参考这位受害者的体验: https://www.cnx-software.com/2021/10/25/installing-libero-soc-in-ubuntu-and-windows-10/

Arch 内核的陨落

由于目前 Arch Linux RISC-V 基本没有处理 bootloader 部分的工作,我打算先试试直接使用旧版 Yocto 自带的 U-boot 来启动 Arch 的内核、rootfs。由于不熟悉 U-boot 和这些嵌入式镜像格式,我先花了点时间学习 U-boot 的启动逻辑 和操作 uImage 的常用命令等。

Yocto 的镜像里有一个很小的 /boot 分区,里面有 boot.scr.uimg 脚本和 fitImage 镜像。我遇到的第一个问题是,这个 FAT16 的 /boot 分区装不下 Arch 的 kernel,而且把 FAT16 扩容并转换为 FAT32 是 libparted 等常用工具不支持的操作。

在艰难尝试了许多次之后,我确定了这个分区后面的那个类型为 BIOS boot 但 GParted 抱怨为损坏分区的分区可能存放的是 uboot 本体(或者含它的 HSS?尚未仔细研究)。因此向后扩容 /boot 的想法可能不大靠谱。我只好退而求其次,把第一个分区删掉,直接把最后的 rootfs 所在分区标记为 legacy_boot

然后我复制了 Unmatched 上的 extlinux.conf 并做了相应修改(内核版本、UUID 等)。第一次尝试启动失败在缺少了两个环境变量:

后来在大佬们的帮助下,我找到了设置它的办法。其实正确的值就来自上面的 boot.scr.uimg,设置前者为 ${ramdisk_addr_r},后者则只需要设置一个足够大的值。

然而这次 Arch 的内核挂在了无限循环刷屏 L2CACHE ERROR 上。

由于大佬觉得这个问题不好解决,我决定先暂时放弃内核,用 Yocto 的内核启动 Arch rootfs 测试。

用魔法打败魔法

在现在的情况下,直接用原版的 boot.scr.uimg 和 fitImage 组合至少存在这样的问题:

  • 1、Arch rootfs 期待一个 rw 的 /。默认的 ro 环境会导致启动后一大堆服务失败、SSH Host Key 未生成等奇怪的问题。
  • 2、默认的 root= 设置为了 SD 卡的第三个分区(/dev/mmcblk0p3)。但经过上面的操作,SD 卡上现在已经只剩两个分区了。

为了修改 cmdline 解决这些问题,我在 U-boot shell 和 uEnv.txt 里鼓捣了各种操作都没有成功。看起来这个内核是把 cmdline 写死编译进去了。

在不重新编译内核的情况下,怎么更改里面写死的 cmdline 呢?那当然是直接修改二进制了!

首先把 fitImage 拆开,用 dumpimage 工具提取出里面的内核和 fdt 文件。从输出中可以看到,内核是 gzip 压缩过的:

用 gzip 解压这个文件,然后用 vim 打开:

诶嘿,我们的 cmdline 找到了。直接修改为想要的值(分区号直接替换,然后换掉一个应该影响不那么大的参数写上 rw),并保持字符串总长度不变(填空格补齐)。一共有两处,做同样处理即可。

修改完后,直接把未压缩的内核、fdt 复制到 rootfs 内,然后添加一个 extlinux 启动项:

label yocto
        menu label Arch Linux with Yocto kernel
        linux /boot/yocto.kernel.patched
        fdt /boot/yocto.dtb

Bingo!成功启动。

至此,最初的目标有了一个最低限度的成果。

尾声/题外话

感谢 PLCT 实验室、TUNA、AOSC 等社区一直以来的帮助,肥猫现在可能从完全不懂嵌入式稍微进步了一点点。

没想到折腾这块难啃的板子会成为我荒废三年多的博客再次更新的契机。我的这一轮 Arch Linux RISC-V 移植项目从最初尝试至今也已经超过三年,而今年年底就是我进入 Arch 十周年了。希望自己下次写博客不要又是三年以后

The post 萌新的 PolarFire SoC Icicle Kit 初体验 first appeared on Felix's Blog.
imi415's avatar

LPC MCUs and ELF manipulation

01. LPCs and vector checksum

After playing with NXP LPC series MCUs for some while, something has bothered me: Verification of program flash against ELF files always fail.

Verification failure

Hmmm.. That's strange. Tried a few different LPC models, and the failure position is always 0x1C. After digging into the user manual, I found out these MCUs uses the reserved 0x1C vector as a checksum for the first 8 vectors. The bootloader sums up the first 8 words, and if the result is zero, the flash content is considered as valid and bootloader will jump to the application reset vector.

LPC54102 UM

Different IDEs and tools reacts differently to this hardware feature, for example, IAR will compute this checksum by the linker during link stage, and the final image or hex files will contain correct contents. J-Link and OpenOCD process this checksum beforee flashing the image to target MCUs, regardless what the original image has.

However, this checksum machnism causes a problem when verifying the flash content against original ELF files, since the original file still contains invalid value for the checksum field, which will incremential download the first flash sector even if the application has no changes.

02. ELF Patching

Since I already know how the checksum is computed, the next thing is to find a way patching the ELF image, writing the correct checksum into the specified offset in interrupt vector table. Instead of grepping and using some regex magic, I decided using libelf from elfutils to manipulating the section data.

The documentation for libelf is too brief to give me the instructions on how to modify the content of a specific section. After several hours of searching between mailing lists and with the help of an old book, I finally get the library working:

((uint32_t *)ivt_data->d_buf)[7] = checksum;

It is important to use MMAP commands, which will modify the data in-place without touching other section information (Since we only modify one word).

Elf *e_handle = elf_begin(elf_fd, ELF_C_RDWR_MMAP, NULL);

The ELF will be modified in-place, which can be successfully verified by J-Flash.

The code is published at GitHub.

Patch OperationSuccessfully Verified

03. References

[1]:https://sourceforge.net/projects/elftoolchain/files/Documentation/libelf-by-example/

[2]: https://www.iar.com/sv/knowledge/support/technical-notes/general/ielftool-checksum---when-using-lpc-device/

[3]: https://www.nxp.com/webapp/Download?colCode=UM10850 (Sign in required)

imi415's avatar

FreeRTOS on CH32V307

Porting and running mainline FreeRTOS on WCH CH32V307 RISC-V MCU
's avatar

Intrigued by Randomness: Mahjong, Crappy Machine Learning, and Gatcha Games

It's not possible to display full formatting in an RSS reader, different RSS readers may also display drastically different layouts. Therefore it's recommanded to read the article by clicking the web URL.


Humans are pretty drawn to randomness. That’s probably a well-known fact, but I’ve just come to understand on how true it is, and I want to talk about it with regards to some of my personal experiences, as presented in the title.


Mahjong is a complex game. I’ve seen elders gather in community space and play it, but never had any idea why the tiles held by winning players make them win. There are more interesting games to play though, so I didn’t try to learn it. That is, until the online game Mahjong Soul came out, which is just Japanese Mahjong with random players online. But the game is obviously targeted to my generation, with cutesy artstyle and player avatars being anime girls (they even added anime guys later). So lots of my friends started playing it, and pretty enthusiastic, too.[1]

A game in Mahjong Soul

I tried to dabble in it, but the new player guide is filled with undecipherable jargon, unknown phrases explained by even more unknown phrases, 20+ different winning conditions, all intertwined. The rules overwhelmed me to no end, so I gave up. Until this year, when many of friends are still playing it often, they instigated me to play again. I said I can’t understand the rules, threw them bags of questions like "what does phrase X even mean?", in attempt to show them my inability to understand the rules. But somehow, this time, they actually had the patience to answer all of my petty questions. Over an hour later, being the one asking questions, I inevitably started to grasp the rules of Mahjong, or at least, quote one friend, "about 20% of Mahjong rules".

Wait, what, there’s more? That took such a long time and so much patience out of everyone, and I only learned about 20%? I exclaimed, "That just shows how complex Mahjong’s rules are!"

They suggested me to "just dive in, understanding will come naturally". But my experience disagrees. All I can do is play robotically or arbitrarily. There is no time in each turn to think everything through, most of the time I have no idea what I am doing. There is little feedback otherthan winning. If I take some action, it is very difficult to know whether that action is beneficial or harmful. When I lose, even if every action taken in that game are good decisions, I wouldn’t know. If I do win, what does that mean? Which decisions have lead to the win?

Comparied to other tabletop games like chess, Mahjong is much more complex. It requires such a high commitment, one needs to sit down and study it, just to be able to start playing. Whereas in chess, learning the rules is quick and feedbacks are easy to come by during plays. A piece is taken, that likely comes from a previous wrong move; I put the opponent in a difficult position, that probably means I did something right. To me, chess is a superior game than Mahjong.

But I missed a critical factor: Chess has zero randomness[2], it’s a game of pure skill (or in my case, at least blind luck). Mahjong is over halfly determined by chance, the starting hand is random, each tile is drawn from a shuffled deck. Skills do matter, but each player is still at the mercy of Fortuna. Better players are merely "more likely" to win, which only show up in a large number of games. In an isolated set of several games, worse players still win sometimes. This means, as some other friends pointed out, Mahjong is a great party game, the fun comes from the randomness. Indeed, if all that happens is weak players being crushed by strong players, it wouldn’t be fun for a group of people who have different skill levels. That happens with chess, and all other games that emphisize skills.

The luck factor also brings thrills to experienced players. Something unpredicted can always happen, anyone may have drawn a tile they need at any time, or not having drawn a useful tile for a long time. There can always be something new. I suppose that is why the elders in community space play it from day to night, seemingly tireless.


A couple of years ago (I can’t believe it has been that long), I wrote a chatbot, HoroBot. It runs in a couple of Telegram and IRC groups. It’s core functionality is to send random emojis whenever discussion is happending in the group. It is just for fun, seeing how merely sending random emojis can make a bot seem to blend in a group chat. This was a success, some didn’t even notice that it’s a bot hanging out amongus, for a long while. They joked that it has passed the Turing test. Later, I added more functionalities to it, one of which is detecting whether a chat participant is "of the bot’s own kind". Because Horo is a wolf, this feature is called the "wolf detector".

The way the wold detector works is based on a Bayesian classifier. Don’t worry, you don’t need to know anything technical. And neither did I. All I knew was that it’s a tool that lets a computer program to categorize sentences automatically. First, train the program with a set of sentences and what category each sentence is known to belong, then, with enough training, the program should know what a sentence in each category "looks like", so that when I give it another sentence, it will tell me its category. It’s a form of machine learning. Such things is often used for detecting spam messages, or whether user reviews to products is positive or negative. I wasn’t using it for anything that serious though, I wanted HoroBot to tell whether a chat participant is "of HoroBot’s own kind" or not.

Graphical explanation of this type of machine learning. Source: Yan, Ma et. al. CC-BY

For my application, there are 2 categories, "is" and "is not" (of HoroBot’s own kind). I trained the program with past chat log of the ArchLinuxCN group at the time. Messages sent by anyone with name containing "horo" is considered to be in the "is" category, otherwise "is not". It was obviously pointless, but the whole thing was just for fun. After training, whenever HoroBot sees another message, it will give a category of that message, and the categorization given to the last 100 messages sent by one user determines their score, i.e. "probability of being the bot’s own kind".

Someone (top) using the wolf detector. HoroBot (bottom) replies with "(redacted) has a 56% change of being of my kind."

The results are, as expected, pretty useless. What does even mean to be "of HoroBot’s own kind"? And because there is no way of interpreting this score, there is no way of telling how accurate it is. It appears that most of the results are around 50%, which gives the suspicion that if I put everyone’s scores up, it’s going to be a normal distribution, i.e. the category of each message is pretty much random. I have not tested that suspicion, though. Actually, it’s potentially worse than random guesses, the "original horos" (people who have names containing "horo" in the chat logs I used for training) tried to see their score, and they were consistently lower than others!

I will confess now, that I do have some idea why my Bayesian classifier was so crappy. A Bayesian classifer needs a sentence to be a list of words, rather than a list of characters. I need a way of segmenting the sentences into words. In Chinese, there are no spaces between words, so segmenting is not trivial. I wasn’t bothered to to anything elabourate, so I just decided arbitrarily: every 2 characters is a word! That is clearly a terrible way of doing segmenting. It has probably made every sentence meaningless.

Incredibly, despite all that, this is the most popular feature of HoroBot! To this day, several years later, when I have not updated the bot in a long time, participants of ArchLinuxCN chat group still seem to see their wolf detection scores often. It puzzles me: It’s just a pointless, practically random number! Why have they not gotten tired of it yet! But well, I guess, I made something that people liked, it should be something to be pround of.

This is purely baseless speculation, but I guess one reason of the wolf detector being popular is it’s unpredictability. The result is not random, the same message always yields the same categorization, but over different messages, it appears random. Yet we know the score is somehow related to the messages a person has sent, while that relation is unknown. Such randomness intrigues us, as we are curious to see "Does sending this message make my score go up or down?" Psychologists say that humans loves finding patterns in random events. Here we do have patterns, how unsensible it may be, it’s somewhere within the algorithm, and knowing this makes us wonder all the more strongly.


I’d like to think of myself as a relatively rational person. Playing gatcha games is a thing to be looked down upon in my book. Here, gatcha games refer to video games that has subpar gameplay, and the main attraction is collecting "cards" which are obtained randomly upon paying microtransactions. The cards are usually depicted as lovable characters.

The profits of gatcha game makers is surely betted on our attraction towards randomness. Each time one pays for the microtransaction, they can be intrigued by the anticipation of their new card (or lack thereof, most of time in this type of games, getting a collectible card is a rare event, usually they are less exciting stuff). The problem is, being attracted to that means I become more likely to spend more money on the totally useless cards, and devote time to virtual characters who have absolutely no care for me (other than their creators wanting to extort for more money). This is different to being drawn towards playing Mahjong with friends, which at least practices friendship; or watching over a wolf detector score, which doesn’t cost much.

I would argue that playing gatcha games is a lot like drinking alcohol. Doing it a lot is definetely bad. Doing it a little is probably acceptable, but unhealthy nonetheless. To be fair, it is really difficult to resist paying for the card draws, so I resorted to just stay away from gatcha games. That resulted me in missing out on some games with gatcha mechanics but do have some content, unfortunately. 🐁


  1. One became so devoted in Mahjong, he even went ahead and made an actual AI for it. It was just published recently.
  2. Other than maybe using some random means of determining who gets to move first.

Unless otherwise stated, the original contents on this website are licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.While reposting, please state that the article comes from FiveYellowMice's Blog, and include a link to the original article.

kookxiang's avatar

又开始写博客了

也许你会好奇,为什么在 2018-08-14 后我的博客就再也没有更新了。

呃,这个事情怎么解释呢… 也不是故意要咕…

主要吧… 工作这种东西就很忙…

而且我又不擅长写作,一写起内容来跟便秘似的

才不是嫌原来那个博客太丑,然后想自己或者找人设计一个新主题最后放弃

总之现在终于弄了个新的博客,用上了之前买了很久的域名 kk.sb

用 Hexo 的目标也非常简单,希望新的博客能专注于内容,不整那些花里胡哨的东西

不知道有没有人看,剩下的内容就吐槽下之前考虑使用的博客系统 锐评各大博客系统

Typecho

老博客用的就是 Typecho

优点

  • 还算轻量?
  • 文章默认用的 markdown
  • 之前弄了一些小插件(虽然有些已经挂了)

当然也有缺点

  • 开发组比我还能咕(今年突然宣布诈尸了,也不知道为啥)
  • 用的人太少,自然也没什么人去做主题插件
  • 有一说一,现在感觉服务器上搭 php 环境不如其他语言简单方便(要配挺多东西)

WordPress

同属 PHP 系的博客系统,应该是目前用户量最大的

优点:

  • 完善的第三方主题/插件,甚至有成熟的付费和定制化市场
  • 像我这种套 cloudflare 的还有对应的优化插件
  • 持续维护中

缺点:

  • 没找到合适的主题,主题市场热销大多是把 WordPress 改造成商城之类的,要不就是列表强依赖图片,像我这种不配图的文章就特别丑
  • 老生常谈的性能问题
  • 哪怕我不用 WordPress,nginx log 里面都一堆 wp-login.php 和 wp-admin 的请求,需要保持更新

Ghost

基于 node.js 的博客系统

优点:

  • 默认主题颜值还行
  • 所见即所得编辑器
  • AMP 支持
  • 对第三方模块嵌入支持很好

缺点:

  • 默认主题虽然好看,感觉还是需要文章配图才能看
  • 几乎没找到啥第三方插件,官方甚至叫 integrations 而不是 plugins

Medium

Medium 是我看到最理想的博客系统了,其实我原本是打算直接用它的,甚至里面草稿箱还有半篇文章

优点:

  • 所见即所得的编辑器
  • 阅读页设计单纯,对于文字和代码的展示都不错
  • 有官方持续维护,不需要自己维护
  • 文章阅读可以带来收入
  • 可以绑定自定义域名(需要开会员)

缺点:

  • 墙了
  • 主题能够自定义的内容很少
  • 付费制度,免费用户能看的文章有限,不知道还会不会有人看
  • 英文网站,如果写中文默认字体丑出翔(直接劝退)

语雀

嗯… 公司弄的东西…
其实准确的说是 Alipay Inc. 的东西

优点:

  • 编辑器简单好用
  • 界面清爽好看

缺点:

  • 不能自定义域名挂在自己网站(虽然可以自己反代)
  • 完全没有自定义主题/插件能力
  • 因为公司在用总有一种在加班的感觉(

Hexo

因为可以静态化部署所以出名,

优点:

  • 静态化部署,可以直接丢 OSS 或者 CDN 上面,理论性能最快
  • 相对还算丰富的第三方插件
  • 直接解析 markdown 文章,方便导入也方便导出

缺点:

  • 官网的第三方主题很多粗制滥造的主题(并不是想喷这些作者,只是觉得官方需要筛选一些好的放在自己的页面上)
  • 奇怪的模板引擎,虽然可能只是我没见识过

嗯,最后选了 Hexo 先用着,如果后续有更好的选择也能方便地迁移过去

's avatar

如何在已有的 Vue CLI 项目使用 esbuild

背景

我们的门户网站项目(Vue 2 / Vue CLI 45 / TypeScript / Element UI)前端部分编译所需时间太长,因此开始考虑在不对已有项目进行过于伤筋动骨的调整的前提下,提升编译速度的方式。

由于 Vite 使用了 esbuild 进行编译速度的提升,我们想到了一个主意:借助 esbuild-loader,把 Vue CLI 中的 Babel 替换为 esbuild。

分析

在项目根目录执行 npx vue-cli-service inspect,可以看到最终生成的 Webpack 配置中,以下部分涉及到了 babel-loader:

      /* config.module.rule('js') */
      {
        test: /\.m?jsx?$/,
        exclude: [
          function () { /* omitted long function */ }
        ],
        use: [
          /* config.module.rule('js').use('babel-loader') */
          // (略)
        ]
      },
      /* config.module.rule('ts') */
      {
        test: /\.ts$/,
        use: [
          /* config.module.rule('ts').use('babel-loader') */
          // (略)
          /* config.module.rule('ts').use('ts-loader') */
          // (略)
        ]
      },
      /* config.module.rule('tsx') */
      {
        test: /\.tsx$/,
        use: [
          /* config.module.rule('tsx').use('babel-loader') */
          // (略)
          /* config.module.rule('tsx').use('ts-loader') */
          // (略)
        ]
      }
    ]

由此可知,我们需要将 jststsx 的默认规则进行清空处理,然后让 jststsx 使用 esbuild-loader

操作

首先,安装 esbuild-loader

npm i -D esbuild-loader

然后,在 vue.config.js 下的 chainWebpack 中加入以下内容:

// 清空已有的使用 `babel-loader` 的规则
config.module.rule("js").uses.clear();
config.module.rule("ts").uses.clear();
config.module.rule("tsx").uses.clear();

// 注入使用 `esbuild-loader` 的新规则
config.module.rule("js")
    .test(/\.m?jsx?$/)
    .use("esbuild-loader")
    .loader("esbuild-loader")
    .options({
        loader: "jsx",
        target: "es2015"
    })
    .end();
config.module.rule("ts")
    .test(/\.ts$/)
    .use("esbuild-loader")
    .loader("esbuild-loader")
    .options({
        loader: "ts",
        target: "es2015"
    })
    .end();
config.module.rule("tsx")
    .test(/\.tsx$/)
    .use("esbuild-loader")
    .loader("esbuild-loader")
    .options({
        loader: "tsx",
        target: "es2015"
    })
    .end();

就可以了。

已知问题

  • 如果项目中有使用到 Web Worker,肯定会炸掉,出现 TypeError: Failed to construct 'URL': Invalid URL 错误。采用 Babel 则正常工作。

遗憾

尽管 esbuild 是好文明,我们依然无法在那个门户网站项目中使用;因为我们项目要求兼容 IE11,而 esbuild 目前最低只能编译到 ES2015,这就导致编译产物无法在 IE11 等不(完全)支持 ES2015 的浏览器中运行;不过,在本地调试时还是很爽的,因为开发环境冷启动和热更新速度确实快了不少。

不过,如果你的项目不需要兼容 IE11 等老浏览器,但恰好还没有升级到 Vue 3 + Vite,完全可以试一试。能快一点是一点啊)

's avatar

Memory Order

大家好,这里是很懂C++的BlancJpg。

Memory order是什么?哎呀怎么这个都不懂。Memory order不是很简单嘛!Memory是记忆,order是顺序。理所当然,memory order是记忆的顺序!当然,我记性不是很好,经常记不清顺序——卡特列夫库——是什么的库?

拿昨天的早饭做例子吧,我吃的是面包夹肉饼——好吃吗?嗯……还行吧——我记得很清楚,我先吃了面包再吃的肉饼的。

……什么?原子化?对对对,我的牙齿是先碰到面包,再碰到肉饼的分子的。所以从分子层面上来说我是先吃的面包。你呀,明明是分子说什么原子化。难道是要把分子劈开吗?想裂变吗?

就说是先吃面包了!麦当劳的肉饼比较x……好了好了换个例子!拿前天做例子吧,我是先吃的早餐然后吃的午餐。——我说吃早餐了就是吃了!别多管闲事!所以从正常人的眼里来看,我肯定是先吃的早餐然后吃的午餐,除非有人在超光速运动。啊不对,如果是超光速运动的人,那就不是吃了,大概会看到我先吐出午餐,再吐出早餐。像小红帽故事里的大灰狼一样。所以是小红帽在超光速运动。谁也没看见大灰狼吃奶奶的场景对吧?没看见就是一切皆有可能。

大灰狼记不记得自己点了什么菜呢?毕竟是order……哈哈!

讲到哪里了,讲到晚饭了。前天的晚饭吃得比较快活。吃的羊肉串加牛肉面。饿了一天的肚子也填饱了。——所以讲吃早餐了!话真多呢这家伙!走了!

依云's avatar

从 getmail6 到 offlineimap

本文来自依云's Blog,转载请注明。

起因

上个月收到这样一封邮件:

意思就是说,Google 觉得把密码直接交给邮件客户端,权限太大,不够安全。所以要用户改用基于 OAuth2 的认证方式,只给程序邮件相关的权限。哦,你说应用专属密码?要用那个必须得启用两步验证——也就是意味着遇到灾难的话,我无法从一无所有的状态开始恢复。

从 POP 到 IMAP

getmail6 只支持使用 XOAUTH2 认证的 IMAP 协议,并不在 POP 协议上支持这个(不知道是否有可能)。所以我得换 IMAP 协议了。

具体操作步骤在 getmail6 的示例配置中有写。简单来说就是自己去申请个桌面软件的 app 信息,然后给自己的用户添加试用权限,再通过 OAuth2 获取 refresh token 和 access token,就能登录了。getmail6 自带了个 getmail-gmail-xoauth-tokens 程序用来走 OAuth2 流程,不需要另外安装程序来处理的同时也可以给其它程序使用。

所以我的 msmtp 配置就不用麻烦了,改两行配置就好:

auth oauthbearer
passwordeval getmail-gmail-xoauth-tokens ~/.getmail/gmail/lilydjwg@gmail.com.json

但是呢,虽然邮件是收回来了,IMAP 和 POP 还是挺不一样的。POP 没有「文件夹」的概念,所有收到的邮件,不管我有没有在 Gmail 网页或者客户端上阅读、归档,不管它进了哪个标签(文件夹)(「垃圾邮件」除外),我都会收到,并且把收过的邮件标记为已读。

而通过 getmail6 使用 IMAP 收取,我能做的选择就是,要不要把收过的邮件标记为已读或者删掉(可在 Gmail 中设置为归档)。不管如何,getmail6 只会收到它运行时位于收件箱中的邮件。如果我选择标记为已读的话,那么已读邮件也不会被 getmail6 收到。所以标已读的话,我在别的地方看过的邮件不会被收到。删除的话会好点,收过的邮件归档了,还省得我手动去归档,但是在别的地方,收过的邮件和已处理的邮件没了区分。

所以不如上 offlineimap,完全同步好了。

从 getmail6 到 offlineimap

offlineimap 的配置就比较复杂了,一是要对文件夹名进行转码,二是我要设定只同步指定的文件夹:收件箱、Maillist 和垃圾邮件。要同步垃圾邮件的原因是,Gmail 经常把有用的邮件往里边扔。

[general]
accounts = gmail
maxsyncaccounts = 10
socktimeout = 60
pythonfile = ~/.offlineimap/offlineimap.py

[Account gmail]
localrepository = gmail-local
remoterepository = gmail-remote

[Repository gmail-local]
type = GmailMaildir
localfolders = ~/.Maildir
filename_use_mail_timestamp = no
nametrans = gmail_nametrans_local

[Repository gmail-remote]
type = Gmail
remoteuser = lilydjwg@gmail.com

sslcacertfile = /etc/ssl/cert.pem
ssl = yes
starttls = no

oauth2_client_id_eval = get_client_id("lilydjwg@gmail.com")
oauth2_client_secret_eval = get_client_secret("lilydjwg@gmail.com")
oauth2_access_token_eval = get_access_token("lilydjwg@gmail.com")

nametrans = gmail_nametrans_remote
folderfilter = gmail_folderfilter
import os
import json
import subprocess

_LOADED_DATA = {}

def _load_data(account):
  with open(os.path.expanduser(f'~/.getmail/gmail/{account}.json')) as f:
    _LOADED_DATA[account] = json.load(f)

def get_client_id(account):
  if account not in _LOADED_DATA:
    _load_data(account)
  return _LOADED_DATA[account]['client_id']

def get_client_secret(account):
  if account not in _LOADED_DATA:
    _load_data(account)
  return _LOADED_DATA[account]['client_secret']

def get_access_token(account):
  cmd = [
    'getmail-gmail-xoauth-tokens',
    os.path.expanduser(f'~/.getmail/gmail/{account}.json'),
  ]
  out = subprocess.check_output(cmd, text=True)
  return out

def gmail_nametrans_remote(foldername):
  foldername = foldername.removeprefix('[Gmail]/').encode('ascii').decode('imap4-utf-7')
  if foldername == '垃圾邮件':
    foldername = 'Spam'
  elif foldername == '草稿':
    foldername = 'Drafts'
  return foldername

def gmail_nametrans_local(foldername):
  if foldername == 'Spam':
    foldername = '[Gmail]/垃圾邮件'
  elif foldername == 'Drafts':
    foldername = '[Gmail]/草稿'
  return foldername.encode('imap4-utf-7').decode('ascii')

def gmail_folderfilter(foldername):
  foldername = foldername.encode('ascii').decode('imap4-utf-7')
  return foldername in [
    'INBOX', '[Gmail]/垃圾邮件', '[Gmail]/草稿',
    'Maillist',
  ]

然后在 Gmail 那边创建个过滤器,把来自邮件列表的邮件扔到「Maillist」文件夹里去。搜索「 (to:@googlegroups.com OR from:vim-dev-github@256bit.org OR to:@zsh.org)」并创建过滤器,选择操作「跳过收件箱、 应用标签“Maillist”」即可。注意以后在修改的时候直接修改「包含字词」字段即可,并且记得「OR」「AND」「NOT」之类的操作符需要改回大写。

这样做完之后还有个问题:一封邮件同步到 offlineimap 后,我在 mutt 里阅读并删掉了它。offlineimap 一看,哟,邮件没了,得在服务器上删掉。Gmail 根据我的设置,把从 IMAP 删除的邮件归档,但是它并没有选项来标记为已读。所以这封邮件最终会以未读的状态躺在「所有邮件」里。

于是我去 App Script 里写了个脚本,把这些邮件标记为已读:

function mark_as_read() {
  const threads = GmailApp.search('is:unread AND NOT (label:Maillist OR in:inbox)', 0, 30)
  for(const thread of threads) {
    Logger.log('Marking as read: %s', thread.getFirstMessageSubject())
    thread.markRead()
  }
}

手动运行一遍之后,就可以在左侧栏里给它设置个触发器定时跑啦。

新邮件提示

使用 offlineimap 之后,最大的问题变成了邮件散落在不同的账号下的不同文件夹,一个个过去翻看太低效了。所以我就给 zsh 设置了提醒:

mailpath=(
  ~/.Maildir/INBOX/new'?GMail has a new message.'
  ~/.Maildir/Spam/new'?GMail has a new spam.'
  ~/.Mail/inbox'?New local mails.'
)

问号前边是邮箱的路径,后边是提示信息。之前那个 mbox 格式的邮箱我还留着,用来收取来自本地 cron 的邮件。

一个小问题是,procmail 用不成了。不过现在各种无用的网站消息也少了,所以不需要通过 procmail 处理垃圾邮件了(新浪微博我没有使用邮件注册、LinkedIn 和 Twitter 消停了、网易和QQ邮箱不用了)。现在中文邮件列表也几乎没人用了,我也不用让程序去重写「回复:RE:回复:」这类糟糕的邮件标题和过滤掉自动回复了。

依云's avatar

微信消息通知的困扰

本文来自依云's Blog,转载请注明。

一直以来,不得不用的微信以其糟糕的通知体验让我十分不爽。

在手机上,我使用的是 Google Play 商店里的微信。在电脑上,我使用的是通过 Wine 运行的 Windows 版本微信([archlinuxcn] 仓库里的 wine-wechat-setup 脚本可用于安装)。

消息通知不及时

这个问题是最近我的手机日渐陈旧之后我才注意到的。表现是,在一段时间(比如一两天)不使用微信之后,收到新的微信消息或者视频通话,可能会延迟几个小时收到通知。在 Android 通知日志中可以确认,收到通知的时间和消息在微信中展示的时间有数小时之差,并不是因为我没有及时看手机。

我的 Telegram 从来不这样丢消息,即使因为后台进程过多 Telegram 被杀之后,通知只会不能在其它端阅读之后被清除,而不会延迟那么久。而微信,即使它还在后台运行着,却经常占着资源不干活,何况消息通知本应走 FCM。

打开微信即清除所有通知

我有一条微信消息,但是我现在不方便立即回复(比如需要使用电脑而我正出门在外),所以我会让那条通知一直留着。其实以前版本的 Android 系统更方便,可以将通知延后一段时间,只是不能自动指定延后的时间比较遗憾,后来被移除真的太可惜了。

然后呢,比如我要进个超市,或者测个核酸,付个钱啥的,只好打开微信扫码呗。结果所有还未处理的通知全部不见了!等忙完当时的事情,回到家里的时候,我就不一定还记得我还有几条微信消息还没处理了。

多端不同步容易错过

我在用电脑的时候,如果不登录电脑版微信的话,那么我将不会注意到手机上的微信有新消息。那就登录电脑版吧,然后我去上个厕所吃个饭,不用电脑的时候又会错过消息。在电脑端登录的时候让手机上也显示消息通知?那样所有消息都要看两遍,而且消息多的时候还得仔细回想某条消息到底是不是已经处理了。

Telegram 的消息同步做得真好啊。你在哪端用,哪端先给你发通知。其它端的消息会晚几秒出现。一旦在任意端读取了消息,另外的端上的相应消息全部都会被取消掉,不会有消息重复的问题(不过最近好像 Android 上的通知取消变得不那么可靠了)。

手机不可离远

现在电脑版微信终于不需要天天在手机上确认登录了。只要我每两三天登录一次,就可以避免把手机扔去充电了、来到电脑前、又去找手机的麻烦事。——我一开始是这么以为的。直到我发现,我刚刚看到通知、正要处理的消息,并没有在电脑版微信里同步出来。

不知道为什么,微信跟电脑用户有仇似的。明明我有电脑了,不需要凑合于手机的小屏幕和戳戳戳的屏幕键盘了,微信还非得把手机给拉过来。

语音通话不支持耳机接听

某天,我因为沉迷于放置型游戏,把手机扔桌子上充上电让它自个儿玩,自己去睡觉了。第二天早上睡正酣的时候,来了个电话,我拿耳机给接了。然后需要通话的另一方不知道怎么想的,没有商量就发起了微信语音通话,这个耳机根本接不到……

我也尝试过让 Google 助理回拨电话,不过使用不熟练,并没有成功。你说我为什么不起床去接?我睡着被电话惊醒了,还没回过神来啊 QAQ。

依云's avatar

Qt 的字体渲染问题

本文来自依云's Blog,转载请注明。

GUI 程序我现在依然倾向于 GTK,因为虽然 Qt 拥有良好的跨平台性,但可能是太注重跨平台性了,在 Linux 平台上反而有一些水土不服的问题。

字体太多,支持太少

你可能觉得,系统上字体太少,所以经常会遇到不常见的字符无法显示的情况。然而对于 Qt 来说,字体越多,反而越容易遇到个别字符不能显示的情况。

这是我的 /etc/fonts/conf.d/66-qt.conf 中的一段。因为顺序的原因,我只能放到 /etc 下。除了针对 sans-serif 配置外,我也有同样的配置应用于 serif 和 monospace。

<fontconfig>
  <!-- Adjust font order for Qt applications -->
  <alias>
    <family>sans-serif</family>
    <prefer>
      <!-- 格拉哥里字母:Ⰽⱁⱀⱄⱅⰰⱀⱅⰹⱀ Ⰹⱍⰹⰳⱁⰲ -->
      <family>Noto Sans Glagolitic</family>
      <!-- 爪哇文:꧁   ꧂ -->
      <family>Noto Sans Javanese</family>
      <!-- 西夏文:𗷲𗒅 -->
      <family>Noto Serif Tangut</family>
      <!-- 埃及象形文字:𓁹 -->
      <family>Noto Sans Egyptian Hieroglyphs</family>
      <!-- 苏美尔楔形文字:𒆠𒂗𒂠 -->
      <family>Noto Sans Cuneiform</family>
      <!-- 中日韩统一表意文字扩展 C:𫚥 -->
      <family>HanaMinB</family>
      <!-- 拉让文:ꥃ -->
      <family>Noto Sans Rejang</family>
      <!-- 越南傣文:ꪀꪑ -->
      <family>Noto Sans Tai Viet</family>
      <!-- 切罗基文:ꮳꮧꮢ ᨣ -->
      <family>Noto Sans Cherokee</family>
      <!-- 老傣仂文:ᨣ -->
      <family>Noto Sans Tai Tham</family>
      <!-- 安纳托利亚象形文字:𔘓 -->
      <family>Noto Sans Anatolian Hieroglyphs</family>
      <!-- 马姆穆文补充:𖤍  -->
      <family>Noto Sans Bamum</family>
      <!-- 图标字体(PUA): -->
      <family>OperatorMonoSSmLig Nerd Font</family>
      <!-- 巴塔克文:ᯤ -->
      <family>Noto Sans Batak</family>
      <!-- 古北欧文:ᛋᛖᚱᚣᚨᛚᚳᚨᚾᛞᛚᛖ -->
      <family>Noto Sans Runic</family>
    </prefer>
  </alias>
</fontconfig>

这个配置的意思是,把这些字体的优先级提高一些。当使用 fontconfig 的程序要显示字符的时候,它会指定一个模式,匹配到一个字体列表。渲染文字的时候,就可以遍历这个列表,直到找到可以显示这个字符的字体,所以一般来说,只要系统上装了对应字符的字体,它就能显示出来。

但是 Qt 额外地需要这个配置,因为 Qt 只会检查列表中的前255项。而世界上的不同文字那么多,所以想要能够显示它们,就得有一堆字体。比如 noto-fonts 这个包里就有614个字体文件,远超 Qt 支持的数量。总有些奇奇怪怪的文字被网友用来当颜文字,或者挂在名字上彰显个性。不这么调整一下,Qt 遇到了就只能「吃豆腐」了。

空心豆腐

当一个字符显示不出来的时候,那么怎么显示好呢?一般会显示成某种方框。Pango火狐会将该字符的 Unicode 码点以十六进制的形式显示在方框里边,这样虽然不知道这个字符长什么样子,但至少知道它是哪个字符,也知道多块豆腐是不是同一字符,在不能复制字符本身的时候很有用。比如当它出现在求助者的截图里的时候,比如当它出现在不能复制的地方的时候。

然而 Qt 不这样做。管你什么字符,Qt 统一显示为空心方框。从视觉上完全无法知晓它到底是什么字符,要是复制不到的话,就别想弄明白你缺什么字体了。

PS: Matrix 客户端 fluffychat 的 Web 版,使用的是 Fluffy 图形界面库,即使在 Web 版,文字渲染依然完全是自己做的。不管浏览器的设置不管系统的设置,豆腐块是带叉号的方框,还不能选中,十分讨厌。

非 BMP 字符

所有使用 UTF-16 的平台(Java、JavaScript、Windows、Qt),外加 MySQL 容易遇到的一个问题:非 BMP 字符(也就是那些 U+FFFF 之后的字符)会被当作是两个字符处理。随着 emoji 的流行,大家应该都修了不少。然而,Qt 在展示非 BMP 字符的时候,你可以选中半个字符。如果不小心漏掉半个的话,复制出来的半个字符就会变成问号(还好不是 GBK 时代那样弄乱后续所有字符)。

font features

一些字体可以通过 fontconfig 设置 fontfeatures 属性来启用(或者禁用)一些特性,比如连字,带斜杠的 0,小型大写字母,居中的中文标点,等等。Pango 很早就支持了,火狐最近也支持了,但 Qt 那边依旧没啥动静。(感谢 Coelacanthus 的评论。)

's avatar

记一次自建 Gitea + Drone 实例被挖矿的经历

「关于我自建 Gitea + Drone 实例然后被人一瞬挖矿这件事」
依云's avatar

Wayfire 迁移进展(四):不那么 high 的 DPI

本文来自依云's Blog,转载请注明。

使用24寸4k屏幕作为主屏的时候很简单,设置 scale 为 2 就好了。但是,当 2 嫌太大、1 嫌太小的时候,问题就来了。比如我希望使用 120dpi,把 scale 设置为 1.25 可好?

而这才是理想的效果:

看不出来差别?放大八倍,你看差别多明显:

正常 120dpi 渲染出来的文字边缘清晰犀利,次像素平滑左红右蓝。再看看 scale=1.25 的文字,线条经常糊掉,次像素平滑效果几乎完全被抹掉。实际看上去的效果就是跟透明麿沙玻璃看屏幕似的,线条边缘总是有点糊糊的感觉,1080p 的屏幕被降级成了 720p 似的。

之所以出现这样的情况,是因为 Wayland 只支持整数倍缩放。因为,Wayland 混成器不能告诉客户端你得把窗口给画成 1.25 倍的,而客户端也无法告诉混成器我这个图像画的是 1.25 倍。所以,混成器只好告诉客户端你给我画个 2 倍的图像吧。混成器拿到图像之后再缩小 0.625 倍,自然有些逻辑像素就不能对应到单个的物理像素上去了。

所以,我还是设置 scale=1,不要混成器帮我去缩放。我自己通过另外的办法告诉客户端把字写大点儿。图标之类的就顾不上啦,反而大点小点都还能看。比如我要 1.25 倍大小的文字,就这样做:

  • GTK 3:在 dconf 里设置org.gnome.desktop.interface.text-scaling-factor=1.25就好了。最开始的截图就是 dconf-editor 里这一项配置。
  • Qt:设置环境变量 QT_WAYLAND_FORCE_DPI=120
  • Telegram:除了上边这个环境变量外,额外地在它自己的设置里设置 150% 的缩放(Telegram 的字偏小所以要设置得大一些)。设置环境变量是为了 fcitx5。
  • waybar:config 文件中设置 heightstyle.css 中设置 font-size
  • Xwayland:和 X11 下的 HiDPI 设置差不多的。比如 GTK 2 设置 Xresources Xft.dpi: 120 就好了。

我遇到的差不多就这些了。没办法,Linux 就是这么乱 QAQ。不过虽然 Wayland 协议不支持,好歹还有绕过的办法。

RecursiveG's avatar

Rclone 同步 OneDrive for Business 共享

使用 OneDrive for Business 的 WebDAV 接口访问,无需登录。先去浏览器访问你拿到的分享链接,地址栏应该会变成如下形式:

https://[YOUR-DOMAIN]-my.sharepoint.com/personal/[YOUR-EMAIL]/_layouts/15/onedrive.aspx?[一堆别的东西]

然后打开 F12 找到一个叫 FedAuth 的 Cookie:

FedAuth=77u/......

然后用命令行在 rclone 里添加一个 WebDAV 的远程地址。语法是这样的:

rclone config create <name> <type> <key>=<val> <key>=<val> ...

具体到这里就是:

rclone config create <随便> webdav 'url=https://[YOUR-DOMAIN].sharepoint.com/personal/[YOUR-EMAIL]/Documents' 'headers=Cookie,FedAuth=77u/...'

细节请根据浏览器里的信息自己调节,如果设置无误就可以在 Rclone 里查看文件了:

rclone lsd '<你之前填的>:'

几个注意事项:

  • 暂不清楚这个 Cookie 的有效期是多长,如果 Cookie 失效的话自然就不能访问了。
  • 限速是存在的,如果 sync 的时候进度不动并且网络没流量通过,那大概是被限了。rclone 自己的速度计在速度为 0 的时候不会立即归零,而是 5MB,4MB,3MB… 这样慢慢下去,非常反直觉。限速时间还挺长的,暂时没有发现好办法能绕过。
  • 暂不清楚是不是所有的分享链接都可以用这种方式访问,可能需要组织管理员开启 WebDAV 功能?
AlisterTT's avatar

没事瞎画

好像并没有什么意义,不定期更新一下blog内容。

ホロ's avatar

咱和()的 2021 年

有些事情在慢慢变化的嘛,例如咱逐渐开始偷懒到只在 Matters 发表文章这件事。 以及换服务器玩脱了把咱自己的 Mastodon 搞爆炸了什么的……

可以去那里看看咱这一年写了些什么,和发了什么牢骚 。(笑)

以及人老了就喜欢偷懒啦,所以后面大概主要会用那边的 WordPress 来写文章了。

在这里,名字还是一样的。

至于这里嘛,虽然后面可能不会再有大的更新了,不过咱应该还会尽力留着。 万一哪天咱又有心情开始折腾了呢……

咱也谢谢和咱一起路过这六年的大伙儿了。

's avatar

失败经历:为什么 Pomment 至今没有正式发布

从 2015 年开始,我的博客是一直在使用外挂评论系统的,从多说到 Disqus。其实这些评论系统本身没什么问题,但是中间发生了一些事情:

  • 2016 年下旬,Disqus 无法在大陆地区访问
  • 2017 年上旬,多说宣布关闭

博客圈里有很多像我这样的难民,他们需要一套替代的评论系统解决方案,但当时市面上缺少足够好用的自建评论系统(并不是没有,isso 其实就是一个)。因为我从小就没有玩伴,也从未有过很多朋友,我希望借助这个风潮来提升自己在圈子的知名度。于是,在 2017 年上旬,Pomment 开工了。

v0

最早版本的 Pomment 就是采用 Node.js 编写的(其实后来几个版本都是)。由于我当时是高三党,加上开发经验严重欠缺,以前只是使用 JavaScript 写过一些小玩具,因此程序设计非常糟糕,以至于在后期难以继续往下编写,最终在 5 月弃坑。

v1

2018 年,我系统的学习了 JavaScript 的基础知识和 ECMAScript 2015 的新功能,雄心勃勃的决定再次尝试开发 Pomment。

这一次,我希望为 Pomment 增加足够多的功能,来吸引很多博主使用 Pomment。但是,这些功能都是我自己根本用不到的:

  • 基于用户 IP 的留言自编辑/删除功能
  • 插件系统,可以开发反垃圾邮件以及提醒邮件发送的 Provider
  • 功能齐全的 Webhook 和 Telegram Bot
  • 遵循 GDPR 的访客自助服务功能……

但实际上,由于这些功能我自己根本不会使用,加上功能数量过多,导致软件的开发和测试成本直线上升,拖累了整个项目的进展;同时,由于 JavaScript 本身属于弱类型语言,加上自身编码水平仍然较为欠缺,导致程序运行开销巨大、存在大量隐性错误,难以继续维护;尽管程序早在 2018 年 5 月就在自己博客上线,但是当时线上版本的问题较为严重,同时产生了大量的脏数据。

v2 和 v3

为了解决 v1 的问题,在 2018 年 9 月,我决定对整个程序进行重构。这一次的亮点是,我首次采用了无数据库设计(所有数据存储在若干 JSON 文件中);相比通过 Node.js 的 ORM 调用数据库,效率反而更高,而且更加节省内存。

然而,我依然迷恋于堆积自己不需要的功能(尽管在这一版本中删除了一些),导致系统质量和开发效率依然欠佳。同时,博客圈的风向开始发生转变:越来越多的人青睐无后端、静态的博客及评论解决方案,同时一些新兴的评论系统(例如 gitment)巧妙地借助 GitHub 等公共服务存储评论数据,使得 Pomment 的地位也变得非常尴尬。毕竟博客本体都已经是静态/无后端的了,谁还希望专门为评论系统租用 PaaS 服务呢?

v3 则是在 v2 的基础上迁移到了 TypeScript,并修正了不少的类型相关编码错误;同时,还使用 Vue 2 编写了一套管理界面。目前的 Pomment 版本其实已经较为成熟,但是在现代的博客生态之下受到青睐已经是不太可能了。

遗产和未来的 v4

随着我大学毕业以及需要寻找工作,如何让自己的简历更加出彩成为了我需要考虑的事情。而正是由于我开发了 Pomment,我可以大方的把它写在我的简历上,同时对于整个项目的开发过程、遇到的坑洞都有很多可以说的地方。事实上,我不觉得我的评论系统程序本身是失败的,但过程是。

但是,谁不是在学习过程中不断摔跟头的呢?

在明确了我开发开源软件的目的是为自己服务以后,Pomment v4 的愿景就清晰起来了:使用 Golang 重写,只注重自己需要的功能,把更多的精力放在打磨特定的功能而非堆积功能数量(质量重于数量)。

's avatar

突入2022

已经两整年没有更新过这里了。如果只是看我在这里发的文本而没有通过其他途径了解我的话,大概会还在担心我现在的状态吧。那么在这新的一年到来之际,来汇报一下 BPC 的状况。

滚出 THU

总而言之,我成功在 2020-2021 学年补上了毕业设计,成功地把结业证书换成了毕业证书。

之前提到过,由于毕业设计挂科,我需要重新补一遍毕业设计,而由于各种压力和个人状况,我放弃了第一年补毕业设计的机会。虽然我没有把握住这次机会,但是这给了我喘息的空间。

于是在 2020 年的 5 月,因为感觉调整过来了一些,需要找点事情做,所以我去给我正在读研的的同届同学做的 zCore 修 bug 去了。它是一个用 Rust 编写,运用了 Rust 的 async 语言机制,参考谷歌的 Fuchsia 里的 Zircon 斯县的一个操作系统内核。借此机会我被这位同学把介绍给了他的导师,于是之后的一整年,我跟着他的导师做了一些操作系统方面的事情,并且完成了毕业设计。虽然中间是出了一点事故和波折,但是最终还是完成了,可喜可贺。

作为毕业设计的内容,我重新写了半个操作系统内核,起名叫 breakcore。虽然没能完全写完,但是基本的动态内存管理和上下文切换都是有的。作为方便调试的设施和毕业设计中的亮点,我还想办法让它在 panic 的时候打印的调用栈信息里附带上了从内核二进制的 debuginfo 里读出来的,精确到文件、函数、行号列号的调试信息。虽然之后可能不太有机会完成剩余部分了,但是各位如果有兴趣的话,也可以看一看。

自食其力

毕业之后,我休息了几个月。在那之后,我在 2021 年的 8 月获得了一份全职的开发工作。这份工作是由 Telegram 上的一位网友介绍的,他看到本站的背景动画之后,觉得我的图形学水准大概能在他所在的公司发挥很大的作用。最后当然是顺利地通过面试,迅速入职了。

不过由于各种原因,我暂时不能透露公司的名字和具体业务。我的工作内容是交互内容的开发,从图形到音频,从具体实现到底层架构都有一些涉及,技术栈上的话则是以 Web 平台为主。

公司的氛围还是很不错的,待遇上也还可以,而且工作时间也比较灵活,我可以不用担心不能早起。唯一的问题是,公司的发展不是特别顺利,把我招进去大概一定程度上也是想请我来救火。不过,我确实算是满足了他们的期待,工作上也还算顺利。希望公司之后的发展能更好,有朝一日我也能和大家分享我的职务作品。

各种活动再开中

2020 年的 4 月,我如约给 Pikanote 建立了 专门的站点 ,最然更新频率依旧不高,但是确实是写了一些新东西。最近的文章是 USTC Hackergame 2021 Writeup,是我参加中国科学技术大学第八届信息安全大赛后写的题解,当时排名还挺高的,也是让我重新认识了一下自己能有多强。

CanvasArt 也进行了更新,加入了近年来本站的背景动画效果。和在这里使用的版本相比,那边的版本加入了很多可以调整的参数,大家可以玩玩看。

另外就是,工作之后有了收入,我终于可以攒新机器了,新机器搭载了 RTX 3070 Ti 的显卡,Ryzen 9 5900X 的处理器,性能上和之前 2015 年买的笔记本相比有了质的飞跃。由于新设备不再会有视频编码性能上的问题,我终于可以重新开始直播了,休息日的午后也许能在 BPC 的直播间 看 BPC 打游戏。虽然网络有的时候不太稳定,音频输入的声音也比较小,但是之后大概会有机会加以改善吧。

想做的事情还有很多

新的一年开始了,希望新的一年能够多搞点事情。

BPC 的生日也不远了。从 v14 开始自己画头像和背景设计到现在,已经算是满十年了。今年当然也会换上新的 v24 的头像和背景设计。虽然还没有实际开始实现,但是我心中已经有想法了,敬请期待。

今年大概还会做一些新的技术上的尝试,补全一下我在本科期间没能学到的一些东西,解决一些怨念。如果时间宽裕的话,也许说不定还会有空重启 F70 写一点自己的游戏?

另外在非技术的部分也希望有些进步,既然有了高性能的显卡,当然不能浪费他的算力。总之希望今年能有机会研究一下 Blender 和其他的一些东西,尝试做一些 Motion Design 的内容。除此之外,说不定也许能搞出一些别的玩意儿?

新的一年到来了,属于我的可能性依旧还在,愿我能够借助这些许的可能性,创造出在夜空中绽放的绚烂花火。

's avatar

我的 2021

于是,2021 年猝不及防的结束了。虽然我很多时候懒得写这种总结,但是考虑到我还有一个博客在运行,还是写一篇总结好了。

设备添置

今年,我利用自己的收入,给自己添置了很多新的装备。其中两件最重要的是:

同时,今年我把我的 Homelab 建设了起来。我通过购买一些全新/二手设备和配件,完成了我业余机房的基础建设。

功能上,可以分为图形虚拟化服务器、Linux 虚拟化服务器、云游戏服务器、NAS 和软路由;同时,还借助一台阿里云 ECS 实现端口转发、VPN 等功能。当然,这样的业余机房也不是没有代价的;一个是噪音比较大(就这我还没考虑机架式服务器),还有一个是电费要比以前高出不少(好在内蒙古的电价相对还是很低的)。但是,这套 Homelab 极大的改善了我(自认为是 Power User)的 IT 生活体验,包括云游戏也可以让我在任何地方享受家里安装的 PC 游戏。

说到 PC 游戏,其实这一块一直是我最缺乏了解的领域。我主要的游戏经历都是在家里的山寨 FC、后来(打着 MP4 旗号)的模拟器机、智能手机,以及 Nintendo Switch 上;由于以前家里的 PC 配置并不理想,加上父母的态度对 PC 游戏并不友好,我在 PC 上玩过的游戏寥寥无几(不过包括 Minecraft)。其实我开始涉足云游戏,只是希望拥有更好的远程桌面体验;虽然今年显卡价格蹭蹭蹭的上涨,但是因为我去年恰好买了张索泰的 GTX 1650 Super 当亮机卡(迷惑行为),我误打误撞的就开始玩起了《原神》,结果我一发不可收拾,还注册了 Steam 账号,开始研究我还能在 PC 上玩些什么有趣的游戏。因为就算是 1650 Super 这种入门级游戏显卡,它带来的游戏体验也是碾压对我来说的传统游戏设备(至少现今),而且键鼠操作也让我感觉更加灵活、舒适。

不过我也发现很多 PC 游戏都有着烦人的 DRM 和反作弊措施 (aka rootkit)。虽然我不认为我是什么隐私怪,但这让我感觉并不太爽;同时因为我工作站的十代 i7 算不上玩游戏的最佳选择,我从群友那边收了一套 B450 + Ryzen 5 3600 的套装,用手上的一些东西组装了专用的云游戏服务器。结果我的 1650 Super 反而成瓶颈了(

兼职

随着我不断接近毕业,学校的事情也变得越来越少。于是今年年初,在 @qwe7002 的介绍下,我开始利用空闲时间做一些前端开发的远程兼职,并陆续参与了几个项目:

  • 某微信小程序(2 月至 4 月)。这个小程序是经过了几个外包开发者之手,代码逻辑混乱不堪。我经过不懈努力,成功的重构了一小部分浑浊不清的代码,还写了几个新的页面。不过这个项目的经历也让我明白 TypeScript 对于这种多人合作的大型 JS 项目真的很关键,同时对小程序的好感进一步受损,因为这玩意即使是对开发者也很不友好啊。
  • 某 ERP 系统前端(3 月至年底)。这一次,我和另外几位小伙伴,从零开始了一个比较庞大的 Vue 2 项目。我参与了整个项目的选型和脚手架搭建工作,同时意志坚定的选择了 TypeScript(虽然代码里还是有一大坨 any。这个项目还是让我感觉非常愉悦的,因为毫无大型商业项目开发经验的我们居然成功的把项目做了出来,积累了不少经验;而且,还成功让我的小伙伴们掌握了 TypeScript 的基本使用(他们以前都只有 JavaScript 的使用经验);而最重要的是,我拿到了一笔非常可观的报酬。

12 月,我顺利的完成了毕业设计和毕设答辩,进入实习阶段。2022 年起,我将在福州开始我人生中的全新篇章——成为社畜。虽然不知道以后还会发生什么,但是我对我的未来还是充满期待的。

博客

今年我没有对自己博客花很多的时间。不过,我的博客一年来运行基本正常,没出幺蛾子,还是可喜可贺的。

以及,我开始用 Golang 重构我博客的评论系统了。原来写的 Node.js 后端虽然能用,但是算上依赖以后的体积非常臃肿,而且非常吃内存(要知道我的 VPS 也就是 1c1g 的配置);同时,我想找个东西来练练 Golang,所以就拿自己博客的评论系统开刀了。

目前还没有写完,但是到时候大概可以给我可怜的 VPS 节约不少内存吧。

2022……?

2022 年对于我来说会是变化最大的一年,因为我的身份要从学生变成社畜了,同时以后要开始在南方城市常年驻扎。所以未来的事情,只能说走一步看一步吧。

听某些人说,2022 年意味着 2020 年的重复,因为 2022 年拿英文读听起来像 Two thousand twenty too(也是 2020 年)。2021 年的世界依然不太平,所以只能希望 2022 年不要真的是这样,以及第三次世界大战永远不要发生了(至少在我的整个人生中)。

最后,祝大家新年快乐。

SgDylan's avatar

2021,就这么结束了

春去秋来,年复一年。


's avatar

为什么我玩很多网游都感觉不开心

大概是我觉得跟很多玩家在一起互相竞争太累了。

比如玩个 Minecraft SMP 服务器,玩到后期就开始各种内卷了,比如哪个聚落有更好的生产设施、更美丽宏伟的建筑、更多的物产等。

而我自己或许因为人缘不太好,缺少团队的支持,导致我在这无形的竞争中无法出类拔萃,会让我感到不快。但是我又知道,我根本肝不过那些初中/高中党。

至于那些有着排行榜的其它网游,也很容易让我感觉到因为竞争带来的压力。

结果,我发现我真正需要的是像《原神》这样奇怪的网游。它没有 PvP、没有排行榜,可选的好友联机也仅限于合作 PvE 和收集资源。

但是,我又可以跟我的同学等等交流很多东西,比如武器、圣遗物的搭配等等。

我似乎可以找到我想要的那种平衡点。

SgDylan's avatar

RouterOS 接入 IPv6 记录

记录 RouterOS 配置 IPv6 的过程。

依云's avatar

Wayfire 迁移进展(三):taskmaid, waybar 以及 mako 等

本文来自依云's Blog,转载请注明。

我又来更新我的 Wayfire 迁移进展啦~

我写了一个 taskmaid 工具,使用 wlr foreign toplevel management 扩展来提供窗口管理相关功能。程序自己作为 daemon 随 wayfire 启动运行,通过 D-Bus 提供接口供别的程序使用。你问我为什么不直接每个需要的程序直接使用 Wayland 协议?因为用起来麻烦呀。Wayland 提供信息的方式是一组一组的事件,也并没有高层次的库,处理起来只能一堆回调怼上去,相当不顺手。

它最主要的功能就是在 waybar 上标题当前窗口的标题啦。顺便加上了中键关闭和显示 app-id 的功能。应用程序图标因为没有办法准确匹配(比如火狐 nightly 版本的 app-id 也是 firefox),所以没有做。

其次是获取当前活动窗口所在的显示器接口名称。我使用这个名称来判断我是不是位于 E-ink 屏幕上,并为终端、Vim、skim、mutt 等工具使用专门适配过的亮色主题。这个方案比之前在 X11 下使用当前鼠标坐标来判断要灵活一些。当然更灵活的方案是匹配显示器的名称啦,这个数据 Wayfire 的 Wayland 协议里是有提供的,有需要的话我再做。Wayland 并没有一个协议来获取当前鼠标或者键盘焦点所在的显示器信息,所以我只好用窗口管理协议来跟踪活动的窗口了。

顺便还做了个 lswin 工具,列出打开的窗口信息。工作区太多啦,我又喜欢最大化,有时候会有窗口忘了关。甚至偶尔我还会不小心把窗口最小化了,然后没有办法给恢复回来……如果以后还经常出现这种情况,我再给 taskmaid 加一个恢复最小化窗口的功能好了。

除了使用 taskmaid 显示标题之外,我还加了个显示 AQI 的小脚本。以及之前忘记加网速指示器了,现在也加回来了。不得不说 waybar 比 Awesome 的那个顶栏要好配置得多。不仅不限语言,而且不是非得用定时器,可以在信息变动的时候及时更新信息,没变动就不浪费资源获取重复的信息了。我的 waybar 配置都在这里

我给 Wayfire 发了一个 pull request,添加了最基础的快捷键禁制器的支持,可以在 spicy 等软件中屏蔽 Wayfire 自己的快捷键了,大大方便了我对 Wayfire 和 Sway 的测试。当然也可以用于 VNC 啦。不过并没有像 Sway 那样加选项、支持主动禁用快捷键等功能,短期内我也不太可能会去加这个。原本我是想着在 Wayfire 里再跑一个 Wayfire 或者 Sway 啥的,但考虑到配置方面的问题,还是拿虚拟机隔离了比较好。

最新的 Wayfire 版本已经支持切换到之前的工作区啦~

桌面通知程序 mako,之前遇到两个问题。一是通知经常是糊的,没有适配 HiDPI 屏幕,而鼠标指针则一直都是又糊又大。我给修了,虽然我其实有点不知道我是怎么修好的……总之是整理了一下代码,为了减少调试日志而减少了与 Wayland 混成器的通讯,也变得更高效了。会记住上次显示使用的缩放倍率,所以不会像之前那样一出来是糊的、下一刻才会变清晰了。在 Wayland 协议里,客户端可以获知有哪些显示器、大小和缩放倍率如何,但是客户端并不能提前知道自己将会显示在哪个显示器上(倒是能够指定显示在哪个显示器上),只有显示出来之后才知道,然后做调整后再更新一下……

另一个问题是,在 Wayfire 下 mako 在全屏时不会显示通知,会被盖住。设置 layer=overlay 之后倒是能在全屏时显示通知了,但是它也会在 swaylock 锁屏界面上显示……后来了解到 mako 有模式这么个特性,我就在锁屏的时候切换到专为锁屏设置的模式下,解锁之后再切回来。反正锁屏是一句命令,自己拿脚本包一下就好了。

最近新的桌面环境稳定下来了,倒是没有再遇到更多的 bug 了。Spicy 会在里边的虚拟机跑特效动画时经常报个「Gdk-Message: Error flushing display: 资源暂时不可用」错误然后退出,我给它用 try_until_success 包了一下倒是问题不大。我也发现了不光是 Wireshark,也有 GTK 程序弹出菜单会显示在错误的位置。

那么就酱~

Phoenix Nemo's avatar

配置 Fail2ban 保护 Proxmox VE

各种情况下 Proxmox VE 的登陆界面需要暴露在公网的时候,需要使用 fail2ban 来保护它不被暴力破解。

创建 filter

文件 /etc/fail2ban/filter.d/proxmox.conf

1
2
3
[Definition]
failregex = pvedaemon\[.*authentication failure; rhost=<HOST> user=.* msg=.*
ignoreregex =

创建 jail

文件 /etc/fail2ban/jail.d/proxmox.conf

1
2
3
4
5
6
7
8
[proxmox]
enabled = true
port = https,http,8006
filter = proxmox
logpath = /var/log/daemon.log
maxretry = 3
# 1 hour
bantime = 3600

重启 fail2ban

1
~> systemctl restart fail2ban

然后检查是否配置生效

1
2
3
4
~> fail2ban-client status
Status
|- Number of jail: 2
`- Jail list: proxmox, sshd
's avatar

致大学招生办:我好菜啊

在 RSS 中无法显示完整的格式,不同的 RSS 阅读器所显示的内容也可能会有很大差距。为了能够获取到完整的内容,最好还是点开网页链接看。


虽然难以接受,但自己已经远远脱离可以自称“中二少年”的年纪,即将被社会毒打了。不过听说有一种办法也许可以减轻这种毒打,同时还可以延缓它的开始——读硕士。讨厌的是,想要申请许多学校的硕士,需要一个黄鼠尤其不擅长的东西:写自荐信。

这自荐信没有框架,没有标准格式。写出来会不会被录取,完全凭靠招生办审阅者的感觉。他们说:“自荐信要表达出你独特的地方,表现为什么你是这个课程的最佳人选而其他人不是。”前半句很好满足,因为黄鼠确实觉得自己很独特——哪个人不是呢?黄鼠有着独特的特征、独特的经历、独特的能力,就像每个人一样。可是自荐信不是征婚启事,也不是可以随口说任何内容的博文,里面写的必须得是和要申请的硕士课程相关的内容,对吧?像“喜欢二次元纸片人”这样的信息,应该是不合适的,除非申请的是美术系。而在这个限制之中,黄鼠就没有那么独特了。会做黄鼠会做的事情的人在时间上数不清,其中也有不少人大概做得比黄鼠更好。至于“表现为什么我是最佳人员而其他人不是”,就完全没有头绪了。黄鼠自己都不觉得自己的相关能力有多独特,怎么能够断言别人做得不如黄鼠呢?比黄鼠条件更好的人大有人在。自己都不相信的事情,要怎样说服招生办呢?

黄鼠高中的成绩很差,因此没有足够的分数在大学进入自己心仪的计算机科学专业,而是不得不学了一个算是相关的专业,网络工程。 4 年即将过去,黄鼠感觉在学校中似乎并没有学到很多(值得花费 4 年的)东西,时间似乎都花在了来回的交通,关心各种行政事物,还有满足各种繁杂考核标准上。倒是在自己的时间里进行的学习,似乎反而还不如中学时的多。有趣的课程是存在的,可是再有趣的东西,被掩埋在时间压力、行政事物、标准考核下,再被批判的目光盯着,并且这个批判目光可以非常轻易地使黄鼠白交学费、白花时间、延迟毕业、打乱一切计划——的时候,也变得枯燥乏味了。于是黄鼠采用了这样的心态:不指望从学校学到什么,主要的能力靠自学,从学校只是为了得到文凭。但是大概是因为自己比高中时变废了,并且也因为在课业中已经敲电脑足够累了,黄鼠在课外进行的自我提升反而减少了。

长辈说,大学并不只是为了学习和得到文凭,还有一个很重要的收获是“人际关系”。可是……黄鼠完全没有在那方面做任何努力,也不会突然无厘头地和其他人搭话。并且因为某个来自武汉的全世界流行病,许多时间都是呆在家里上网课,杜绝了除上课和完成小组作业之外的人际交流。倒是反而与几乎都是在地球另一面的网友们相处的非常好。

现在黄鼠就要从网络工程本科毕业了,终于也许可以有机会在硕士去搞计算机科学了。这两个应该向是相关的专业,想要过去应该是蛮直接的吧?可是光是最低要求就使黄鼠与许多学校的计算机科学硕士无缘:有些是说必须要有计算机科学的学士学位,有些是在后面加注了“或同等学位”。黄鼠怎么知道自己的“网络工程”是不是算是同等?有些地方说这个要求是故意写的这么模糊的,要看每个人的具体情况,这个黄鼠喜欢;但有些地方写了很明确的怎样算是“与计算机科学学士同等”,要包含某些特定的课程,像是“基础算法”、“离散数学”、“数据结构”、“面向对象编程”什么的——都是黄鼠没有在学校学过的东西。就在这时,黄鼠才意识到了自己的本科与真正的计算机科学本科是有多大的差距。编程黄鼠当然是会,但是并没有任何官方机构可以为黄鼠证明;而其它 3 个黄鼠是完全没有系统地学习过。即使是在没有列出这些明确要求的地方,黄鼠想他们大概也是会默认申请者都有这些知识的吧?也许是,也许不是,黄鼠不知道这会不会为自己在审阅者眼中减分。

黄鼠觉得自己还是有资格被称作“极客”的。但是仔细想一想,自己真的有做出什么出众的事情吗?听说贡献开源项目是一件极客们经常做的事情,可黄鼠没有为任何大型开源软件贡献过代码。看一眼自己的 GitHub ,黄鼠有贡献过的最大的开源项目有两个:一个是给软件的文档加了一句话,另一个是 Dress[1] 。听说在技术社区中活跃也是一件极客们经常做的事情,那黄鼠在 ArchLinux 群水群算吗?黄鼠没有打过包、贡献过翻译、管理过什么东西。黄鼠唯独能称作是极客的地方,无非就是写了一些个人项目,一些没什么挑战性、没有什么创新、几乎都是只有自己用、都是玩具质量的软件,换句话说,都是在“造轮子”。朋友建议说,即使是个人项目也可以写它创造了什么,解决了什么挑战。可是黄鼠全部在做的,都只是在学习怎样调用别人事先已经写好的框架,做出玩具的样子。造轮子能够有什么挑战和创新呢?黄鼠能够把自己的轮子们列举出来,并且说明一个个都是做什么的,但是那样听起来无比寒酸。放在企业里面,黄鼠能够做到的事情大概与 3 个月速成培训班出来的人无异,是像民工那样堆砖砌瓦的工作。堆砖砌瓦当然很重要,但是黄鼠不想要做那样的事情一辈子,要是想的话,完全不需要去读硕士。

黄鼠造过什么轮子?有许多 Telegram bot (聊天机器人),大量的 bot 。有会在群里随机发表情的 bot ,有生成图片的 bot ……尽管写它们的过程对于黄鼠来说都很有趣,并且有网友喜欢,但显然不能够被称作是任何“技术壮举”。黄鼠做过一个 LED 时钟 ,但是那只是包含了一些基础又粗糙的木工,一些用几个小时就可以上手的电路板绘制,以及一些面向初学者的嵌入式软件开发。黄鼠在做完时钟之后,被网友推荐加入了一个“嵌入式”的群,然而群友们在说的话,大部分时候黄鼠都听不懂。他们都比大概与黄鼠年龄相仿,讨论的内容却高几个层次。黄鼠想,自己要申请研究生的话,竞争对手们大概有许多都是那样的人。

黄鼠有许多失败的个人项目,像是现学现卖的过时视觉小说游戏引擎教程,像是愿景过于宏伟的博客评论系统。黄鼠能够把他们称作自己的“经验”吗?它们的失败,是因为自己失去了兴趣与失败的时间管理。可是“对事情容易失去兴趣”和“不擅长时间管理”应该都是作为研究生申请人不被看好的特征吧?网上说“如果没有相关技术经验的话,无关的经验也可以展现自己的软能力,像是时间管理和团队协作”,可是刚刚说的事情只能够证明黄鼠没有时间管理的能力。而从团队协作而言,个人项目只有自己一个人,有和其他人合作的只有学校的小组作业,而那无一例外都不断在证明黄鼠团队协作能力的缺乏。

计算机科学硕士在黄鼠看到的大学中通常有几个子方向,像是机器学习、人机交互、图形、安全、算法、数据库、编程语言、系统和网络,哪一个是黄鼠想要做的?从初中就决定要做这方面的职业的黄鼠应该有很长的时间来想,可是直到现在自己真的要选择了的时候,才有认真去想。唔……自己好像哪个也许都可以做?那么,哪一个好找工作?不对,黄鼠怎么能这样功利,如果因为功利选择了自己不喜欢的方向,痛苦就会充满未来了。所以黄鼠究竟要在自荐信中说自己要做哪个子方向呢?按照自己在个人项目中写了许多网页前端来想,黄鼠应该会喜欢人机交互,可是其它好像也还行,黄鼠也不知道自己在那个领域能够做什么——黄鼠只是有自己造过轮子,完全没有系统的学习过,不知道真的学习起来会是什么样子,更不知道做研究是如何了——万一黄鼠不喜欢怎么办?导师选定了应该很难后悔了吧?与之相对的,黄鼠在本科所学习的网络工程,最相关的子方向是系统和网络,黄鼠觉得自己的成绩还行,所以应该算是已经尝过了它的味道,还有文凭证明,所以也许做系统和网络会更好?黄鼠当然可以把两个都写上去,可是两个都不能够称作是十分地有基础:一个只有自己造轮子的经验,一个只有上了几门课的经验。

对了!为什么一定要做研究呢?黄鼠只是听朋友说“上课这样久会库走,做点项目更有趣”,觉得很同意,所以想去申请研究型硕士。可是黄鼠从来也没有做过和“研究”有半点关系的事情,怎么知道“研究”不会令黄鼠痛苦万分呢?授课型硕士更加简单,可是那样就感觉自己放弃了很好到的机会——黄鼠连这样的决定都无法做到,审阅者一看:这个人怎么这么没有点子,大概不管是研究和上课都不太行。黄鼠可以写两份申请,但是研究和授课的自荐信侧重点不同,写一份已经如此焦头烂额,写两份……有时间再说吧。

一所大学的“自荐信编写指南”视频中,提到说自荐信要包含“你的方向如何与导师相符”。黄鼠连自己的子方向都不确定,具体要做怎样的研究那是更加没点子了。要和潜在导师讨论的话,总不能说“我完全不知道自己想要做什么研究,等过一年再看着办吧”这样的话,一定会降低自己的亲和力的。在同样的视频中,也提到说如果没有研究点子的话,展现自己有做过相关阅读也可以,读过相关的研究,就可以说“我对这个领域有充分的了解,我有信心在这里做研究”了。黄鼠没有做过相关阅读,要现场抱佛脚读一些论文吗?在现在这个距离报名截止日期十分近的时候,黄鼠觉得要静下心来画上几天时间读论文(黄鼠从来没有读过除了摘要以外的论文!),再对这个领域产生充分了解,再对自己产生信心,是一件十分困难的事。实际上,黄鼠有浏览过学校导师们的过往论文标题,可对它们的感觉都大体是“我难以想象自己可以做与这相似的事情”,要么是因为觉得很平淡,要么是觉得太高端了完全不懂,要么是两个因素的集合——这听起来好像不太妙……吧?黄鼠完全没有头绪自己要做什么。

指南中说,自荐信要展现自己的独特。黄鼠想,自荐信一定要写得真诚:如果虚伪的话,不仅大概写不出来,而且如果按照虚伪的说明被录取的话,大概面对的将会是痛苦的生活了。可是黄鼠的独特优势是什么?黄鼠要真诚地说什么?越是构想,越是觉得自己真诚地应该对招生办说:我好菜啊。你们看,我会这些许多人都会的技能,可能这个技能组合不多见。你们觉得我行吗?

可是黄鼠显然是不能这么说的。申请人自己都不能说服自己适合这个学习和研究,显然是不能够指望阅读上千份申请人的自荐信的招生办被说服的。

黄鼠十分认同,自荐信真的是一个非常好的筛选学生的方式。它强迫每个人必须深刻地审视自己,了解自己,才能够写出来它。对于黄鼠来说真的十分有效,即使没有被任何地方录取,有过这样的自我审视应该也是难得的吧。

然后黄鼠成功地被拖延症带领着写完了这篇博文,自荐信正文却还是只有几行 _(:3)<)_ 。

“直接把这篇博文当作自荐信发过去吧。”黄鼠有这样的冲动,但是那样大概就是自暴自弃了。 🐁


  1. 一位朋友说,如果自己是跨性别者什么的,也可以写进去。可是……抛开黄鼠是不是不谈,即使是,写进去也不能够是自己变得更被审阅者看好吧?总不见得大学招生会有 LGBT 优待什么的。倒不如说可能会使人觉得申请人在强行博取同情。

除特殊说明以外,本网站原创内容采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。转载时请注明来源 FiveYellowMice 的博客 ,以及原文链接

Horo's avatar

怀旧手机游戏不正经研究 - 引子

为啥人(?)老啦就喜欢怀旧咧?

先回忆下咱的手游史

咱最早在手机上玩游戏的时间大概能追溯到十多年前,当时咱住在咱的某一个亲戚家里,作为一个熊孩子(x),偶尔也会摆弄摆弄他的手机。以及到了现在咱还记得那台手机,三星 SGH-i718+。

刚才从网上搜索了下,大概就像这个样子。看到那个 Windows 键的话,~~老学校~~玩家应该已经知道了,这部手机搭载的是 Windows Mobile 系统。(以及搜索的时候不经意间发现网上说这是三星第一台国行 Windows Mobile 手机)

虽然内置的游戏只有一个戳泡泡游戏来着(Bubble Breaker?),但是咱不知道怎么发现的(也许是忘了吧)这个手机可以上网,还可以下载 JavaME 游戏来玩,于是接下来的事情就可想而知了……

唉,从五块钱 1M 或者 30M 走过来的表示说多了都是泪啊 😂

以及后来咱也从这位亲戚那里玩到了 Windows Phone 7/8 和 Android 手机,虽然经常是他自己都搞不懂怎么用来请教咱的样子……

后来咱搬去父母家了,虽然他们也忙着做生意经常不着家,于是为了联系方便,就给咱买了一部手机。 Nokia 6700 Slide。

虽然那个时候的咱并不知道啥智能手机塞班系统什么的,但是它也能和咱最早玩到的那部手机一样可以安装游戏。

以及它竟然还支持 3G 网络,加上咱当时用的也是联通卡,于是流量和话费迅速消耗…

然后在不知道什么时候惨遭标准结局(丢了)…… 在挨了顿骂几个月以后,家里还是给买了新手机,还是诺基亚。

就是 Nokia C7 啦,后来才发现咱直接跳过了 S60v5 整个时代。(虽然咱还是能发现有同学买了 S60v5 系统的手机来着,例如堪称街机的 5230 )

除了触屏这个显而易见的特性以外,C7 还有当时颇为珍贵的 Wi-Fi 功能。(以及后来才知道当时国内为了推广自有标准 WAPI 强行让国行手机阉割 Wi-Fi 这档事)于是找地方蹭网一度也是咱的活动之一,直到家里装了宽带和无线路由器。

虽然没有数字按键了,玩之前玩过的 Java 游戏有些不方便。但是咱靠它玩到了很多塞班 3 游戏啊,大部分的画面都比那些 Java 游戏好多了。(嗯,咱那时候完全没听说过 N-Gage……)

例如现在还有更新的狂野飙车(Asphalt)系列,最早是 Gameloft 在 2004 年发表在 NDS 和 N-Gage 的游戏,后来也移植到了 iOS 、Android 等新的手机平台。图片上是咱记忆里在 C7 上玩的 Asphalt 5 。

再后来的某一天呢,咱父母的手机坏了,于是就以再给咱买一台作为交换换走了咱这台 C7。当时 Android 也开始流行起来了,于是鬼使神差间咱买了三星 Galaxy Tab 2 7.0 。

没错,一台能打电话的平板!😂 所以咱那个时候怎么想到买它的呢。

于是接下来就是延续到现在的折腾 Android 的故事了, ~~就和咱接下来要聊的话题没太大关系了……~~

至于 iOS 嘛,咱买的第一部 iPhone 是 iPhone SE,于是就和怀旧更没啥关系了。

好啦好啦,虽然老的 iOS 和 Android 游戏也有不少佳作啦,但是现在的新系统上面几乎都运行不了那些老游戏啦。

至于去淘一下老手机平板什么的, ~~经费有点不足……~~

那么接下来呢?

在看了好几个同样爱好怀旧游戏的爱好者的视频以后,咱也被一股不可名状的引力所吸引开始在网上收购一些老手机了。(以及在自己和亲戚那淘一淘货)

于是接下来咱有点兴趣的问题就是,咱想玩 Java ME/Symbian/N-Gage 游戏的话,用哪部手机比较合适?

当然啦,假如自己还有能用的手机的话,那肯定是用现成的最节省成本。于是问题就演变成了如果要淘一淘二手的话哪些型号性价比更高了。

以及有些平台已经有差不多的模拟器了(例如模拟 JavaME 的 J2ME Loader 和模拟 Symbian 的 EKA2L1 ),那么在手机上用模拟器是否也还行呢?假如汝不是特别介意手指搓玻璃的话。

以及带物理键盘的 Android 手机搭配模拟器会不会效果更好来着,例如上一篇文章里那台多亲 F21 Pro。其它的有按键的 Android 手机(像是三星的~~土豪专用~~心系天下系列和黑莓的最后几部键盘 Android 手机)应该也能类比。

~~其实还是没钱买~~

那么是不是还可以扩展到其它的老电玩平台呢……像是 3DS/PSV 或者 PS3/Wii 之类的。

这大概就是长期计划了……说来刚刚打开某软件搜索价格的时候发现咱之前两百块收的 PSTV 已经涨的飞起了,虽然并没有什么关系(x)

于是接下来就是等快递了。 ~~(连鸽子都能说的这么清新脱俗)~~

依云's avatar

Wayfire 迁移进展(二):Xwayland HiDPI 以及 waybar

本文来自依云's Blog,转载请注明。

这几天完成了一个很重要的功能:我让 Xwayland 支持 HiDPI 了!

实际上让 Xwayland 支持 HiDPI 的补丁早就有了,但是我当时尝试的时候补丁并不能很好地应用,我手动修了修,不明不白地应用上之后,并没有能够正常使用。现象是,DPI 是对了,但是窗口大小会不断地缩为原来的四分之一(长宽都减半),全屏时也只占左上角的四分之一。

这几天我给 xorg-xwayland 打上了新版补丁,然后在一番理解之后,给 wlroots 写好了相应的补丁,现在 Xwayland 终于也可以看清晰了!

这两个补丁,xwayland 那边是通过一个 X 窗口属性来设置缩放倍数,然后 xwayland 会告诉混成器自己的窗口使用了对应的缩放倍数,这样混成器就不会当它不支持缩放、强行给拉伸一下了。当然还有输入坐标的转换之类的。缩放倍数为 2 时,X 客户端会看到之前两倍的显示大小,并且 X 使用的坐标是 Wayland 这边的两倍,所以 Wayland 的输入事件从 X 服务器传给 X 客户端的时候需要乘以 2。

混成器这边,需要了解客户端传过来的 X 坐标和 Wayland 坐标不再相同,需要进行相应的转换。没有进行转换的结果就是,客户端告诉混成器说自己是 1024x1024 的窗口大小,然后实际上创建出来是 512x512 的。混成器再告诉客户端你现在只有这么大,然后客户端说好,我调整一下。于是又变小了……

两个补丁打上之后,由于头文件有变化,混成器可能需要重新编译一遍。然后按 X 的方式设置 HiDPI,比如设置 Xft.dpi: 192 或者 winecfg 里设置 dpi 为 192。如果有运行于 Xwayland 的 GTK 3 程序,也要设置 GDK_SCALE=2 GDK_DPI_SCALE=0.5。然后执行以下命令设置 X 属性,让 Xwayland 做相应调整:

xprop -root -format _XWAYLAND_GLOBAL_OUTPUT_SCALE 32c -set _XWAYLAND_GLOBAL_OUTPUT_SCALE 2

接下来就能愉快地 wine 和 gimp 啦~

这几天做的另一个比较大的动作是配置好了 waybar。我也不知道这个组件叫什么好,很多地方都叫面板(panel),i3 / sway 那边直接叫 bar。它现在经常出现在屏幕顶部所以我也有时叫它顶栏。总之就是显示窗口信息、系统托盘和状态指示器啥的那一条。

我是从它自带的配置文件修改的,但是风格给完全改掉了。原本的风格是一块一块的彩色背景的字,我嫌太过显眼,经过一番调整之后,给改成了黑底上的彩色字,跟我原来的 Awesome 差不多,也和我显示器的黑边挺配的。指示器的放置也是差不多的。十分遗憾的是并没有合适的窗口列表小部件可用。它自带的那个 wlr/taskbar 会把所有工作区的窗口全部显示出来,很挤。而且不知道为什么,一旦加上它之后就最小要占用 34px 的高度,太占空间了,所以作罢。我打算以后自己实现一个,现在就拿正在播放的媒体凑一下吧。它现在长这样:

左边就是使用 playerctl 做的媒体信息。左键可暂停播放,滚轮切歌。字的颜色是和窗口边框匹配的。

中边留着给窗口标题。

右边依次是:

  • idle 禁制器。点一下眼睛亮起来,禁用无活动时自动休眠。
  • CPU 和 load 信息。
  • CPU 温度。太高了会变红。
  • 内存使用率。
  • 电池信息。充满电又插着电源线,它就隐藏起来了。预期充电或者使用的时候图标会出现,并且可以看到剩余时间。如果在放电并且电量低,应该会变红并且闪烁。这设定跟我 Awesome 的那个一样,不知道等到什么时候才能用上,到时候才能看到效果了。
  • 音量。左键单击是切换静音,滚轮调节音量。图标会显示设备类型(我这里有内建、HDMI(实际上是走的 DP)、蓝牙三种)。麦克风静音的时候也会显示图标。
  • 系统托盘。它终于可以在多个屏幕上同时显示啦~
  • 时钟。

我最终还是用上了那个包名为「otf-font-awesome」的图标字体。

waybar 比 Awesome 的 bar 好配置多了。很方便使用外部程序来定义。也不一定要用定时器。程序可以一直跑着,一行一条状态更新,就不需要在「更新不及时」和「更新太频繁消耗资源、干扰调试」之间抉择了。

我把 wayfire、waybar 以及其它一些东西的配置文件上传到 GitHub dotconfig 仓库了。XDG 标准路径挺好的。

还有一些小的更新——

壁纸我使用了 swaybg,因为它支持不同显示器使用不同的壁纸,这样我的 e-ink 墨水屏就可以独享纯白壁纸了~或者什么时候我专门找张合适的黑白壁纸也挺好的。

fcitx5 输入条的文字 padding 太大。鉴于我现在日常使用 Wayland 了,我改了我这个主题,适配 Wayland。X 那边也没有太难看。

fcitx5-paste-primary 已经添加了 Wayland 支持,虽然实现很不优雅……

看图软件,使用 imv(同时支持 Wayland 和 X)取代了 sxiv。许多图片要预览的话,thunar 或者 geeqie 也挺好的。

以及一些已经报告的 bug:

还有一些未报告和未调查清楚的 bug,等事情明了之后我再更新啦~

依云's avatar

Wayfire 迁移进展

本文来自依云's Blog,转载请注明。

这几天又解决了一些问题,记一下。

Wayfire 部分:

  • 部分按键绑定无效的问题,Super+数字键无效是因为这个是 git 版本才有的。PrintScreen 无效是因为需要写成KEY_SYSRQ……
  • 窗口标题的问题。显示中文的 pr 已经提交。也把 scale 插件的问题一起修了。
  • 要不显示标题栏也很好办,首先 preferred_decoration_mode = server 让窗口们都用 wayfire 画的装饰,然后设置 height = 0 这样就看不到标题栏啦(窗口边框还留着;连边框都不想要的话可以不加载这个插件就好了)。
  • lightdm 启动不了 wayfire 的问题,在 ~/.xprofilesleep 1 就好了。相关 issue:Missing some input devices in wayland session · Issue #63 · canonical/lightdm
  • 嗯,lightdm 是会给 Wayland 会话 source ~/.xprofile 的。所以在里边判断 XDG_SESSION_TYPE 环境变量然后做相应的处理就好了。另外 sddm 是会 source ~/.profile 的。
  • invert 和 zoom 插件只支持一个显示器的问题,没有再次复现。可能是 git 版修了吧。
  • 挂起之后恢复,没键盘鼠标的问题大概也好了?今天我只遇到过一次没键盘,重新插了一下……
  • resize 调整窗口时保持比例(比如用于 scrcpy)。我已经在自己的 fork 中加入这个功能。
  • 锁屏使用 swaylock。不过它只锁屏并不会关显示器,所以我又写了个 xset dpms force off 的等价程序
  • HiDPI 下 Xwayland 窗口是糊的。通过改变插值算法(默认的 GL_LINEAR -> GL_NEAREST)来缓解。sway 默认就支持这个。这个 nearest 算法在整数倍放大时,会不那么糊,不过颗粒感会很明显(就是把显示器分辨率给降回去啦)。
  • 哦,还有个 git 版本的新问题:slurp 或 swaylock 在运行时,会消耗不少 CPU。我发现是由于 wayfire 一直在发送 configure 事件造成不断地重绘,已经给补上并提交 pr 了。

我的 Wayfire fork 位于 https://github.com/lilydjwg/wayfire/tree/lilydjwg,里边有什么请自行看提交历史。不过要注意的是,这个分支我可能会 push -f 以清理历史。

应用程序部分:

  • flameshot 需要设置 XDG_CURRENT_DESKTOP=sway 才能工作,然而在多显示器的时候只会给用户编辑左上角的部分,还是没法用。于是我用回传统的「选择+截图」组合了,只不过在 Wayland 下是 slurp + grim 这个组合。
  • wl-paste 和 xsel 不同步的问题,是由于 wlroots Xwayland 在窗口没有焦点时,被禁止与 Wayland 部分同步剪贴板。
  • 我装好 xdg-desktop-portal{,-wlr},设置好 XDG_CURRENT_DESKTOP 环境变量,然后重置了一下 obs-studio 的配置文件之后,它能工作了。不过只能录整个屏幕,不能按窗口录啦(由于更容易意外录到别的内容,反而不那么安全了)。

然后是剩下的问题:

  • spicy 无法捕获键盘是因为 wayfire 没有实现那个协议。有空我去 patch 一下好了。
  • 火狐还是不能录屏。听说是协议有更新火狐还没跟上?
  • wireshark 的菜单会显示在屏幕最右边。
  • mako 的通知文字经常是糊的,reload 一下什么的可能会好。也遇到过它不显示,reload 一下又好了的情况。
  • GTK 3 程序的右键菜单,上下会多出一部分内边距并被加上的圆角。圆角我还能忍,但多这么一部分不能选中就很难看了,然后火狐的多级菜单还没把这个考虑进去,没对齐各级菜单……

解决这各种问题挺累的,我就不仔细核查和整理了。本文只是个记录,把已经完成的事项从我的 TODO 列表转存到博客而已啦=w=

's avatar

npm、镜像源与 package-lock.json

在国内开发涉及 Node.js 的应用都知道,裸连官方的 https://registry.npmjs.org 非常慢,等待时间令人捉急。

解决这种问题,我们自然想到的就是找镜像源(就像 Linux 发行版的包管理器那样)。

国内目前已经有一些 npm 镜像源,大多数情况下,它们其实还是可以用的。但是,package-lock.json 中会记录下各个包的原始 URL:

{
    "node_modules/@babel/compat-data": {
      "version": "7.16.0",
      "resolved": "https://repo.huaweicloud.com/repository/npm/@babel/compat-data/-/compat-data-7.16.0.tgz",
      "integrity": "sha512-DGjt2QZse5SGd9nfOSqO4WLJ8NN/oHkijbXbPrxuoJO3oIPJL3TciZs9FX+cOHNiY9E9l0opL8g7BmLe3T+9ew==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=6.9.0"
      } 
    },
    "node_modules/@babel/core": {
      "version": "7.16.0",
      "resolved": "https://repo.huaweicloud.com/repository/npm/@babel/core/-/core-7.16.0.tgz",
      "integrity": "sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ==",
      "dev": true,
      "license": "MIT"
        }
}

其实如果项目仅仅在国内开发和编译,问题不会很大。但是如果你开发的是开源项目(特别是面向海外的)或者在国外服务器跑 CI,你的项目就有可能会遇到安装依赖时连接不稳定的问题(因为国内这些镜像源通常不会针对国外优化)。

对此,我的建议是:

  • 尽量避免使用镜像源。
    • 对于连接缓慢的问题,可以给 npm 设置代理,或者利用国外 VPS 为 npm 自建 SNI Proxy,然后在本地修改 hosts 文件/进行 DNS 劫持。
  • 如果一定要使用镜像源,则需要:
    • 考虑清楚你的项目是否将完全在国内开发,并让团队中所有人使用相同的镜像源。
    • 尽量选择能够通过 sed 简单替换 package-lock.json 中所记载地址的镜像源(例如华为源、中科大源)。
依云's avatar

不同情况下的图形效果

本文来自依云's Blog,转载请注明。

我在上一篇说到,Wayland 下再也不会遇到撕裂了。后来群友说,这是 Intel 的 modesetting 驱动特有的问题。所以我又重新比较了一下。为了让事实说话,而不是靠很容易有偏见的主观感受,我使用 Sony Xperia XZ2 Compact 手机的「慢动作」功能,以 960fps 录制了不同情况下,火狐滚动同一页面的效果。不过视频我就不放了,上传费时又占地方。

首先是我长期使用的组合:X11 + Intel 集成显卡 + modesetting DDX,窗口管理器是 Awesome 3.5.9,混成器是 picom。这种情况下有非常严重的斜线撕裂,在画面内容变化大的时候(如无过渡切桌面、视频镜头转换、大幅度滚动页面)必现。撕裂的样子如下(「慢动作」的分辨率有限,亮度低是预期现象):

可以很清楚地看到,截图中的页面是由两帧的内容拼接而成的。而且左下的是后一帧,右上的是前一帧,我不知道为什么会是这样子。我记得以前它不会撕这么大条斜线的啊,是斜-水平-斜的样子。反正都很难受就是了。我以前以为这种撕裂是时不时出现的,但多次「慢动作」慢放表明,它发生的频繁度大大超出了我之前的感受。

这个组合还有个问题是:外接显示器时,鼠标会跟着画面的更新而闪烁。画面更新越多越频繁,它闪烁得越快,而且和更新的区域也有关系。因为眼睛总跟着鼠标跑,所以即使它大部分时候不影响定位,但对主观感受的伤害应该也挺大的。

然后 Wayland + Intel 集成显卡,混成器是 Wayfire。完全观察不到撕裂。鼠标光标也很稳定不闪。

X11 + Nvidia 独立显卡 + 官方闭源驱动。还是 Awesome + picom 的组合,输出还是经过 Intel 显卡。也完全观察不到撕裂。不过有个更严重的问题——我的外接显示器每十来秒会黑屏几秒。听说把显示器关掉重开就可以解决,不过我无意使用这个方案,就不理它了。除了我之前提到的容易崩溃之外(其实我也不知道现在它还崩不崩),这显卡不支持视频硬件加速。这意味着我根本没办法看 4k 视频。PS: 火狐的 WebRender 能正常自行启用。

X11 + Intel 集成显卡 + Nvidia PRIME Offloading。我只是好奇地试一试这个方案啦。以前这个方案里火狐没办法启用图形加速,只能用「basic」渲染器来着。现在火狐有了 Software WebRender,倒是也能比较好地跑起来了。依旧会撕裂,好像比用 Intel 显卡要好那么一点点?

然后对比一下水族馆的图形性能数据:

  • X11 + Intel 显卡,30fps 左右。
  • Wayland + Intel 显卡:接近 60fps。
  • X11 + Nvidia 显卡:30-40ftps。
  • X11 + PRIME,这个比较令我意外,竟然也在 30fps 上下。要知道这个是纯 CPU 实现的,没有 GPU 加速的呀。

其实 WebGL 我用得不多啦(Google 地图更常卡在网络 I/O 上而不是渲染上)。更多的是播放在线(YouTube)视频啦。

  • X11 + Intel 显卡,1080p 60fps,GPU 用满,丢帧三分之一!4k 60fps 也差不多。原来重点不是分辨率(反正 GPU 的解码能力还没用满),重点是视频的帧率啊。
  • Wayland + Intel 显卡,4k 60fps 都不怎么丢帧,更不说其它了。GPU 图形计算用到一半左右。
  • 没有更多方案了。我这 CPU,软件解 4k 会卡成 PPT 的。

综上,Wayland 的表现是最好的!好吧虽然遇到了挺多问题的,不过我大概都能修或者绕过。虽然撕裂不全是 X11 的错,但是确实有客观证据证明它体验不好,不是 Wayfire 的特效太绚烂太怀旧让我偏心了~

Phoenix Nemo's avatar

笔记:Arch Linux iPXE 基本启动脚本

似乎一直没有(公开且版本够新)的 Arch Linux 无人值守安装配置,所以想做一个。

参考 netboot.xyz 的 iPXE 配置,简单记录一下:

1
2
3
4
5
6
7
#!ipxe

set mirror http://archlinux.mirror/archlinux/iso/latest
set script http://unattended.install.script/script.sh
kernel ${mirror}/arch/boot/x86_64/vmlinuz-linux archisobasedir=arch archiso_http_srv=${mirror}/ ip=::: BOOTIF= net.ifnames=0 script=${script} mirror=auto
initrd ${base-url}/arch/boot/x86_64/initramfs-linux.img
boot

参考 SYSLINUX 的 PXELINUX 部分和内核 ipconfig 部分的文档写 ip= 参数的时候一边拿不到 DNS 一边疯狂报过多参数,最后发现是这个 bug 的锅。而且它还被 netboot.xyz 在脚本里注释出来了我可能需要去检查一下视力

总之目前暂且只能用 DHCP 来在启动过程正确配置网络,否则无法下载系统镜像。

截至写这篇的 Arch Linux 的官方说明在这里

最后就是自动安装脚本了,这个坑暂且撂在这里,以后有时间了再慢慢填…

咕咕咕

ホロ's avatar

带键盘的 Android 手机和多亲 F21 Pro 折腾记

因为人(?)老了就喜欢怀旧? 😂

对咱这个高不成低不就不知道算不算老人的家伙来说呢,能够拿来怀旧的应该会有那些“古老”的 手机游戏了。(也没有多么老啦,就是差不多十年前那些 Java 手机游戏了,好像叫啥 J2ME? 算了不管了后面就都叫 Java 了,希望大家不会和现在还在的那个 Java 搞混。)

虽然现在也有像是 J2ME-Loader 这种 Android 上也可以用的 Java 模拟器了,但是在触摸屏上按虚拟按键完全没有感觉嘛…… 所以咱也开始物色有键盘的 Android 手机了。

好啦咱知道去收购一些老的手机也是可行的解决方案,那下面的内容就完全没有必要写了。 是不是咱可以鸽了 (x)

举几个键盘 Android 手机的栗子

虽然 Android 的操作更多的是以触屏为主,但是也不是没有有物理键盘的机型啦。 比如摩托罗拉里程碑之类的,但是那个好像太古老了点……

最近几年最能拿出来举的例子大概就是黑莓了,例如最后一部亲自操刀的 Priv 和后面授权 TCL 设计生产的 KeyOne / Key2 。不过 TCL 也在 2020 年撒手不干了就是...

除了黑莓以外,也有几家公司设计过带物理键盘的 Android 手机,例如 Unhertz TitanF(x)tec

不过上面这些还是有一个微妙的问题,它们都是传统的 QWERTY 键盘布局,所以按键普遍的都比较小。 方向键也都在一些奇妙的地方或者干脆就没了。虽然大部分 Java 手机游戏都能用数字键代替方向键来着, 等等,这些手机上的数字键基本也要靠 Fn 之类的组合键触发出来啊……

以及它们的性价比也不怎么漂亮。(家境贫寒.jpg)

后来上网瞎逛的时候就看到了标题说的那个 多亲 F21 Pro 。 是常见的 12 键键盘布局,Helio A20 的性能虽然不强,但是满足咱这需求应该是够用的, 于是就买了一台 4G+64G 版本。

在咱开始写这篇文章的时候,才发现还有一个 F21 Pro+,平台换成了紫光展锐 T310。 同时可以选择学生版和标准版(标准版可以自由安装应用,学生版不行,F21 Pro 也不行), 不过只有 3G+32G 版本可选,如果汝不想像后面那样如此麻烦的话,去买那个就行。 3+32 应该也足够用了,除非汝往里面装了几万个游戏那样的(笑)。

借应用市场刀装第三方应用

既然这都拿“学生手机”作为卖点了嘛,那自然不能自己安装应用就是设计使然而不是 Bug 咯。 这个系统貌似是魔改了系统的软件包安装程序,如果包名不在白名单里就会提示 “禁止安装第三方应用,请去应用市场安装”。 多亲似乎也从 2 Pro 那时学来了不少的反制措施, 例如封掉了 adb 安装,提前占了设备管理员应用的位置之类的。

不过后来有人发现系统自带的应用市场其实是能安装其它的应用的,只要把正在下载中的安装包换成汝想要的软件就行了。 就算后来的系统更新封堵了一阵子,也又被发现只要把旧版的应用市场装上就能绕过了……

也有人写出了能半自动操作的工具了,例如 MlgmXyysd/k61v1injector 。 但是咱比较懒(上面那个依赖 PHP),所以就手动操作一把了。

  • 在 F21 Pro 上启动开发者选项里的 USB 调试。和普通的 Android 手机一样的方法咱就不用再啰嗦了吧?
  • 接上电脑,在手机上授权电脑,然后打开一个终端。
  • 清除手机上应用市场的数据。(这是为了接下来偷懒方便(x))
  • 打开手机的应用市场,下载一个软件。考虑到下载的时间因素,建议选一个稍微大一点的软件, 或者限制一下手机的网速也是可行的。

然后在终端上输入(汝应该知道要把哪里换成汝自己要安装的 APK 文件的路径,对吧?):

# $() 可以把括号内的命令的结果替换到上层的输入里。
# 例如这里的 adb shell ls /sdcard/Android/data/com.duoqin.promarket/files/Download/
# 会列出这个目录(应用市场的下载目录)里的文件列表。
# 如果汝刚刚是清除了应用数据再下载的话,这里就只有汝当前正在下载的应用了。
# 于是瞒天过海大法发动(x)

$ adb push /path/to/your/apk \
/sdcard/Android/data/com.duoqin.promarket/files/Download/$(adb shell ls /sdcard/Android/data/com.duoqin.promarket/files/Download/)

不过这种方法唯一的缺陷就是,应用更新以后汝还是要这么来一遍,所以还是要研究一下怎么把这破烂限制解掉。 奈何都喜欢藏着掖着……

效果大概就是这个样子。于是汝也可以把刚刚咱说的那个 Java 模拟器装上,再找来几个老游戏的 JAR。 就可以愉快的玩耍啦。

因为 F21 Pro 的屏幕分辨率是 480x640 ,正好是以前最常见的 240x320 的两倍。 所以在模拟器里设置好全屏显示,再隐藏掉虚拟键盘以后的感觉就和以前差不多了。 至于按键手感嘛……这个只能说因人而异了。

其它的小吐槽

  • 如今很多 App 都不会给键盘做优化了啊,还好 F21 Pro 有触摸屏,用起来不会像之前流行 的 C558 那样麻烦。
  • 以及该卡的国产“小而美”还是卡,刚装完能吃掉接近 1G 储存空间可还行……
  • fastboot flashing unlock 对这个是可用的,但是这个手机没有音量键没法确认啊 😂

以及这里面手机的截图其实是截取的电脑用 scrcpy 连接到手机的画面,就这样吧。

imi415's avatar

MIPI-DSI LCD with Zynq

Driving a cheap DSI LCD with Zynq
Yeechan Lu's avatar

我的浏览器地址栏中的 A – Z(2021)

前略,天国的 2017 秋酱。好久不见!

  • Adminer.REDACTED (local Adminer instance)
  • Bilibili.com
  • Cowtransfer.com
  • Ditu.baidu.com
  • Exponential-idle.fandom.com/wiki/Minigames
  • Fastmail.fm
  • Git.orzfly.com
  • Hikari.im/friends
  • Ip.ainou.plus
  • Jd.com
  • Keycode.info
  • Live.bilibili.com
  • Music.163.com
  • Namesilo.com
  • Orz.tools
  • Ping.pe
  • Qzxx.com
  • Ricecake.traveleorzea.com
  • Strings.wakingsands.com
  • Twitter.com
  • Universalis.app
  • V2ex.com
  • Weibo.com
  • Xiaomiyoupin.com
  • Youtube.com/watch?v=dQw4w9WgXcQ
  • Z3.REDACTED (local MinIO dashboard)
Horo's avatar

如何比较安全的配置 Web 服务器 - TLS 和 HTTPS

~~嗯?这家伙鸽了多久了?~~

又是一次知道的已经做好了,不知道的对着他耳朵唠叨也不会去做的系列节目。(嗯?) 如果不想听咱啰 …

RecursiveG's avatar

LTO-5 磁带机折腾入门


最近在 eBay 上捡了一台 HP 的 LTO-5 磁带机,型号是 BRSLA-0903-DC,这次就把折腾过程简单记录一下。
LTO 磁带机本体一般都是标准的 5.25 寸光驱位大小,接口类型一般是 Fiber Channel 或者是 SAS 加上供电用的 Molex 4Pin。
不管哪种接口你都需要一张对应的 HBA 卡插在 PCI-E 槽里,以及对应的光纤线或者是 SAS 线把磁带机接到卡上。
如果机箱带光驱位,SAS 的磁带机可以直接放在机箱里,FC 的应该就不行了,因为我还没找到接口朝内部的 FC HBA 卡。

硬件

(由于我懒得拍实物图,本文所有图都是网上找的)

我买到的是一台 FC 接口的磁带机,注意这张图里的磁带机外面还有一个转接架,是给磁带库用的,自己用需要拆掉。

对应的光纤通道 HBA 卡

和光纤线

以及不知道从哪儿来的供电线

全部接上就可以开机了。

所有以上硬件再加上 5 盘磁带大概一共花了 300 美刀左右。顺便吐槽一下 LTO-6 磁带机的拍卖价格真疯狂(600+)。

TAR (Tape ARchive)

磁带机应该会在 Linux 下显示为/dev/st0/dev/nst0设备,区别在于st设备会在任何操作后将磁带倒带回开头,而nst设备会将磁带停留在操作结束的地方。

tar程序可以直接对设备进行操作,比如,将文件拷贝进磁带:

tar -cvf /dev/nst0 filename

将文件从磁带还原:

tar -xvf /dev/nst0

列出磁带上的文件:

tar -tf /dev/st0

更多操作可以参考这篇文档: How to archive data using the AIT2 attached to CDF17

LTFS (Linear Tape File System)

LTO 从 LTO-5 开始支持 LTFS,你可以先将磁带“格式化”,然后用更为熟悉的目录结构来管理磁带上的文件。你需要自己从 LTFS 的 GitHub 源码 编译。Arch 用户也可以直接用 AUR 包。具体使用方法在 Quick Start 里已经写得很清楚了:

1.列出设备(如果没有可以尝试手动modprobe sg

sudo ltfs -o device_list

2.格式化磁带

sudo mkltfs -d /dev/sgX

3.挂载

sudo ltfs -o devname=/dev/sgX /ltfs

4.卸载

sudo umount /ltfs

其他

磁带机买来干什么?鉴于磁带的顺序读写以及需要手动换磁带(买带库的大佬请忽略)的特性,注定了它只适合于备份和归档用途。备份像是重疾保险,你希望永远也用不上;归档是你 6 岁时的玩具,舍不得丢但也不会再用。所以如果你说 NAS 空间不够,要用磁带来存你的电影,我觉得不太行。但如果你仓鼠症发作,打算收集世界上所有的电影,磁带大概可行。

我还顺便搜集了一下 HP 的官方文档,方便参考:

RecursiveG's avatar

USB4 与 Thunderbolt 4 备忘

最近研究了一些关于 USB4 以及 Thunderbolt 4 的资料,在此做个备忘。目前只考虑 USB Type-C 接口,并且忽略 Type-C 可以正反随意插带来的复杂性。

  1. USB Type-C 接口里有一对(两根)差分信号线,用于 USB 2.0 协议(USB 2.0, 480 Mbps)。
  2. USB Type-C 接口里有四根 GND 以及四根 V_BUS 用于送电,具体电压和电流由两端使用 CC 线协商 (Power delivery)。
  3. 在 Type-C 接口里再取两对差分信号线,用于 USB 3.x 协议(USB 3.2 Gen 1, 5 Gbps)。
  4. 通过改进协议,可以将传输速度翻倍(USB 3.2 Gen 2, 10 Gbps)。
  5. 再把 Type-C 中最后剩下四根信号线也用上,传输一样的协议,可以将速度再次翻倍(USB 3.2 Gen 2x2, 20 Gbps)。
  6. 大家发现这八根高速信号线不止可以用于 USB,也可以用来传输其他信号。比如:电脑可以与显示器透过 CC 线协商,使用两对差分信号线传输 DisplayPort 信号(DP Alt mode)。
  7. Intel 觉得 Type-C 接口不错,于是有了 Thunderbolt Alt mode,使用全部四对差分信号线传输 Thunderbolt 协议(Thunderbolt 3, 40Gbps)。
    Thunderbolt 3 本身是一种隧道协议,在这个隧道中可以传输 PCI-E 数据和 DisplayPort 数据。
    至于 USB 则可以在扩展坞中内置一个 USB 控制器芯片,通过 PCI-E 与电脑连接,这样扩展坞就可以插 USB 设备了。
  8. USB-IF 觉得 Thunderbolt 3 这个协议不错,在 Intel 开放了 Thunderbolt 3 协议后,就把它拿过来“改名”成了 USB4。使用 USB Type-C 中的两对或四对差分信号线传输(USB4, ~40Gbps)。
    与 Thunderbolt 3 相同,USB4 也是一种隧道协议,其中可以传输 USB 3.2,PCI-E,DisplayPort 等协议。
    (吐槽时间:外层协议和内层协议都叫 USB 你是认真的吗?)
    USB4 规范并不要求硬件生产厂家实现所有功能,比如说,一个最高只支持 20Gbps 速度的设备可以合法地被称作“支持 USB4”。因为 USB4 规范并不要求所有设备都支持 40Gbps。(吔屎啦你 USB-IF)
  9. Intel 觉得 USB-IF 的标准混乱,是赚钱的好机会,于是自己列了一套更高的标准(比如要求设备必须支持 40Gbps 速度),并给符合 Intel 的标准的设备贴上 “Thunderbolt 4” 的标签。

最后围观 USB4 混乱的速度要求被鞭尸的现场:https://youtu.be/ly5-QHjs8Gw?t=1845

Allison Sheridan: So a Thunderbolt 4 device is a USB4 device...Brad Saunders:    (nodding)Allison Sheridan: ...but a USB4 device is not necessarily a Thunderbolt 4 device?Brad Saunders:    It can be ...Allison Sheridan: It can be but it isn't necessarily.Brad Saunders:    It'll probably have... they may have made a choice to... maybe it's only 20 Gbps.Allison Sheridan: Right, but it's Thunderbolt 4 it's 40 [Gbps] per second, Okay.
AlisterTT's avatar

可算折腾入门了AE

AE算是我上大学时期的的一个噩梦,当时用小破本渲染视频都是整夜整夜的挂机,所以根本就不想碰这软件,最多也就会找个现成的模板改几个字凑合用那种。当时用了邪道的motion,基本是秒渲染,移动几次摄像头就可以搞出很厉害的效果。

随着近几年PC的性能提高,AE的教程增多,上手起来也变得没那么困难,上午看了B站一个教程,26分钟,基本就对里面的插件有了一个概括的了解,试着做了一个demo,自我感觉良好。

Phoenix Nemo's avatar

修复 LVM XFS 的 Input/output error

某服务挂了。

设备被强制重启之后发现 LVM 满了,但是文件无法访问,所有文件操作显示 Input/output error

HY's avatar

对开箱抽卡保底系统的一点讨论

现在越来越多的游戏开始加入了开箱抽卡系统,用作游戏的主要营收方式。 这里我们先不提及开箱抽卡作为赌博的本质,单 […]
's avatar

More Than a Yuri Story: Thoughts on Heart of the Woods

It's not possible to display full formatting in an RSS reader, different RSS readers may also display drastically different layouts. Therefore it's recommanded to read the article by clicking the web URL.


Characters in the title screen: Abigail (left), Maddie (right)

Heart of the Woods looks like a nice interesting love story about 2 girls, one human, one ghost. It’s homo, so it’s just what I needed to escape from the real world. Although it appears to involve love across the living and the dead, which is a concept that’s been done to literal death. But hey, the game is well-received, it’s on sale, the artstyle is new to me, and most importantly, it doesn’t appear to be too long. So I guessed it’s going to be a nice fit for the spare time I currently have.

Boy was I wrong. It does not use the old plot device of "one grows old and die while the other stay for eternity" or "the border between life and death is unbreakable so we can’t be together" that human-ghost relationship stories tend to have, which I imagined to also be a leading aspect of this one, too. Heart of the Woods has so much more than that.

Note:

There is no spoiler beyond the first chapter.

The opening scene, Tara (left) and Maddie (right) lie on the train seats

The premise of the story involves a YouTuber that talks about paranormal events, Tara, and the assistant, Maddie. The two travels to a supposedly-haunted town to investigate for their show, because a local of the town as well as a viewer of the show, Morgan, invited them. The ghost appears much later in the story, and is named Abigail (feels pretty unimaginative for a ghost name, to be honest).

At this point, even though none of the interesting things have surfaced. I was quickly drawn in by the sheer beautiful writing. Maddie’s opening monologue very effectively introduced a realistic situation: Maddie has been a long-time friend to Tara, and an assistant to her paranormal events show, but Maddie was going to quit and chase different life goals after this trip to the haunted town. Her guilt, her internal struggles and worry for Tara and all the complex emotions was very expressively shown. I felt I could be in Maddie’s shoes. Through her interactions with Tara, I could feel the awkwardness between them. Tara is salty, Maddie is guilty, but they also know they should keep their cool, but at the same time it’s also really hard to get over their emotions, however they still have a final episode to make…​ This kept going for a long time, it felt real.

It felt funny that I came to this game because of the official pair of Maddie and Abigail, but before that main course came, I was already fascinated by the relationship of Maddie and Tara. I was already worried about them. As Morgan teased them with paranormal phenomena, Tara was hyped and ready to believe, while Maddie was skeptical. Maddie thought Morgan was maniac for claiming crazy things but can’t prove them, and for her infame among townspeople. I actually shared Maddie’s opinion for a while, even though as a reader, I know for a fact that there’s a ghost and so Morgan is at least partially right.

Throughout the former half of the story, the situation keeps getting more complex, and the stakes keeps getting higher. Even without half of the official pair (Abigail) appearing, the 3 characters already seem so interesting. I was just expecting a sweet yuri story, but as I read it, it becomes full-on suspenseful. The suspense peaked at the end of the first chapter, but it did not just decline after that. Things keeps changing, and there is little to no filler texts, no boring segments about "daily lives".

I really liked the romantic parts of the story as well, they complement with the suspenseful parts perfectly. With such good writing, the characters are fleshed out, and their thoughts feels grounded. Their relationships feels human. It’s lovely. With no spoilers, allow me to say that there are lots of hugs, cuddles, and kisses. I felt them, embarrassingly. Even though I’m usually not a fan of erotic scenes in visual novels, I would probably sit through them if this game had any. (There is actually an R18 patch, I didn’t know about it.)

An interesting thing I liked about the character settings is about Tara. The first thing I noticed about her is the voice acting. Her voice sounds unexpectedly deep, almost like…​ the voice a transgender person could make. I thought "it can’t be", but I looked at the credits, and apparently Studio Élan did find a transgender voice actor, and Tara did mention in one line of dialogue that she is trans. The impressive thing is that nobody in the game ever cared about Tara’s voice, even ones that are unfriendly. Tara being trans is not part of the plot and only briefly mentioned. I think this is a massive "trans rights!" shout of how they are just regular people being themselves and we don’t make dramas on their gender. I’m behaving worse than the characters in the game because I’m making a drama about it in this paragraph.

A guest art by Roarke taken from the game’s guest art gallery. I died as I see this.

Let me hope that this article has made you give some interest to the visual novel. It is sold on itch.io and Steam. Ultimately, I think my experience with Heart of the Woods proves the point in my previous article, how good a story feels comes from subverting expectations. This novel has subverted mine a lot, and hopefully I have not spoiled it too much to let it also subvert yours. 🐁


Unless otherwise stated, the original contents on this website are licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.While reposting, please state that the article comes from FiveYellowMice's Blog, and include a link to the original article.

RecursiveG's avatar

手动硬盘安装 WePE

最近尝试了一些 Windows 下的全盘备份/恢复方案,于是顺便折腾了一下各种 WinPE 系统。WinPE 简单来说就是一个 Windows 的 LiveCD,带有各种用于 Windows 的工具。网友们在微软的 WinPE 基础上加入各种驱动和方便使用的图形化操作界面,作为不同的 WinPE “发行版”发布,微PE(WePE) 是这些“发行版”之一。

WePE 自带的安装程序除了安装必要的启动项以外还会安装一些没啥用的选项。所以记录一下手动安装启动项的方法。环境为 Windows 10 64位 UEFI 启动。你需要先制作 WePE 的 ISO,然后把 ISO 里的WEPE目录复制到随便一个分区里,我假设是D:。用管理员身份执行以下命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bcdedit /create /device
# 你会拿到一串 GUID, 假设是 {A...}
bcdedit /set "{A...}" ramdisksdidevice partition=D:
bcdedit /set "{A...}" ramdisksdipath \WEPE\WEPE.SDI

bcdedit /create /d "WePE" /application osloader
# 你会拿到一串 GUID, 假设是 {B...}
bcdedit /set "{B...}" device "ramdisk=[D:]\WEPE\WEPE64.WIM,{A...}"
bcdedit /set "{B...}" osdevice "ramdisk=[D:]\WEPE\WEPE64.WIM,{A...}"
bcdedit /set "{B...}" path \windows\system32\boot\winload.efi
bcdedit /set "{B...}" systemroot \windows
bcdedit /set "{B...}" nx OptIn
bcdedit /set "{B...}" pae ForceEnable
bcdedit /set "{B...}" detecthal Yes
bcdedit /set "{B...}" winpe yes
bcdedit /displayorder "{B...}" /addlast
bcdedit /timeout 3

设定完启动项以后就可以把盘符删掉了。

SgDylan's avatar

Imitate DSEE HX

两年前的坑 Remake,大概是最接近 DSEE HX 的实现。

's avatar

自建云游戏服务的尝试

为什么?

我最近经常玩《原神》,但是我:

  • 只有一台能带动这游戏的远程工作站,我还很难物理访问它
  • 平时在外面只能使用弱鸡的旧款 MacBook Pro
  • 用 iPhone 12 Pro 玩,感觉体验堪忧

显然,再为这么一款游戏而专门购买游戏本是不划算的,而且游戏本有着笨重、噪音大、外观普遍中二感爆棚、电池续航几乎不存在等缺点。

考虑到近年来 StadiaGeForce Now 等云游戏服务在国外的兴起,我有了新的主意:拿自己的远程工作站搭建云游戏服务。

本博文不是真正意义上的教程,但是记录了我对若干方案的尝试和使用体验。

环境

  • 服务端(工作站)和客户端都在重重 NAT 之下
  • 有一台阿里云 ECS 做跳板机,安装有:
    • Wireguard(用于和不同的远程设备连接)
    • nginx(通过 stream 模块向公网转发端口)

RDP

在此之前,我经常会使用 RDP 来连接我的远程工作站。启动 RDP 服务不需要复杂的服务端设置,在网关机上也只要简单转发一个端口到公网即可。

其实 RDP 对于一般的应用程序是没有问题的,但是完全不适合打游戏:

Moonlight

我的工作站配备有 GTX 1650 Super,因此可以借助 GeForce Experience 的游戏串流(Streaming)功能和 Moonlight 客户端,轻松搭建自己的云游戏服务。

总体来说,在有合适的网络条件下,Moonlight 可以提供足够好的游戏体验。但是它也有一些蛋疼的问题:

  • 配对时必须在远程主机上输入四位数字确认
  • 一旦连接过 RDP(因为我平时还要工作!),串流服务就会停止工作
    • 所以,上述的配对过程也不能在 RDP 进行,必须使用其它的远程桌面服务(如 Teamviewer);
      同时,每次连接过 RDP,都需要用 Teamviewer 再连接一次。

Parsec

Parsec 是一款与 Moonlight 类似的应用,但是解决了 Moonlight 的很多痛点:

  • 验证是基于他们自家帐号系统的(比在远程主机确认配对方便多了!)
  • 连完 RDP 以后可以直接连接
  • 灵活的连接方式,可以自动视情况通过局域网、Wireguard 等方式连接到服务端
  • 支持 A 卡(虽然我现在用的是 N 卡)

不过,你只能使用 Parsec 他们家的帐号系统,而且他们的客户端比较黑箱。我不是很在乎就是了……

让 GPU 一直工作

我在淘宝上随便买了个 HDMI 锁屏宝,解决了这个问题。

不过,也可以试试 虚拟显示器

对比

总之,不同的连接方案有着它们的优缺点,所以还得视场合选择使用哪种方式连接到我的工作站。

服务/特性 RDP Moonlight Parsec
支持显卡 N/A Nvidia 各种
配置难度 中等
首次连接 输入本机登录信息 在服务端完成配对操作 输入 Parsec 登录信息
流量消耗 较高 中等
图形渲染位置 客户端 服务端 服务端
针对游戏优化
使用 RDP 后再连接 N/A 需要其它远程桌面工具再连接 可直接连接
自动打洞
剪贴板共享
开源软件 客户端开源

自建云游戏服务的优越性

就是可以玩各种自己喜欢的游戏啦,而不只局限于云游戏厂商提供的可玩游戏。

不过,如果你没有长期使用 Windows 远程桌面的需求,而且只想玩一些大众游戏,那么类似于 网易云游戏平台腾讯云游戏 等服务都是可以考虑的。

Update: 如果你是原神国服玩家,还可以考虑一下官方的云・原神,不过看起来只能在手机上玩。

流量费

别人花 648 抽优菈,我花 648 让游戏跑起来。

然后我靠着免费的原石抽到了她(

黑狗布雷特's avatar

俺说游戏Season2——我十分中意现代3A游戏!

氦,新的一期俺说游戏音频节目正式上线啦!新的俺说podcast以第二季的形式回归了!本期俺说游戏阐述了我对当今流行的开放世界装备驱动打据点3A游戏情有独钟的理由——它甚至涉及到US特遣部队一项关键的军事变革!
Horo's avatar

Google 的 FLoC 是个糟糕透顶的主意

翻译自电子前哨基金会 (Electronic Frontier Foundation) DeepLink BLog 的 Google’s FLoC Is a Terrible Idea : https://www.eff.org/deeplinks/2021/03/googles-floc-terrible-idea , 原作者 Bennett Cyphers

EFF 网站的内容以知识共享 署名 4 …

's avatar

Subverting Expectations

It's not possible to display full formatting in an RSS reader, different RSS readers may also display drastically different layouts. Therefore it's recommanded to read the article by clicking the web URL.


I think a huge factor in how good a piece of artwork feels to me is how much it subverts my expectations. The "artwork" in question can be literature, illustration, music or perhaps more other types.

If a work sets up a high expectation from me, by either making really good marketing materials or its author(s) is/include someone who has produced good works before, it will need to reach or overachieve for it to not be "disappointing". It can still be objectively really good, but for me, because it is comparatively worse than the expectation, it may feel like as if it’s actually bad.

Likewise, if I don’t have much expectation for a work. For example, a low-budget work from someone I have not heard of, or works that does not appear to be serious (like a comedy or a meme). As long as it turns out to be better than that low expectation, I will feel like it’s amazing. Even if objectively, it’s so-so at best.

I want to give some examples. The movie Your Name directed by Shinkai Makoto. It has a highly-reputed director, stunning marketing posters. And before I watched it, countless praises had been seen from my peers. The resultant expectation was floating to the skies. After I watched it, I felt it was "not bad", but was it worth the hype? That was hard to answer. The plot progression felt like there’s too many coincidences, the main characters' experiences seem to just be a road laid down by the writer (which to be fair, it obviously is) rather than a believable adventure. So right after I finished the movie, I gave it 3.5/5 stars. I felt this was exactly what "overrated" means. But let us think rationally, is Your Name a good movie? I suppose most people would agree, and I agreed after I thought rationally.

On a similar vein, also an anime movie, Sword Art Online: Ordinal Scale, but this one faces the opposite scenario. The Sword Art Online series is not known for it’s depth. In fact, its story is considered really shallow and only good for "thrills" by critics. To be honest, I like Sword Art Online, I mean, I like plain thrills without much depth. So I watched the movie, and it offered me exactly what I expected: thrills without much depth. It actually overachieved a little because the movie has flashier visual effects than what’s in the TV series which I was used to. I somewhat felt better after watching this than after watching Your Name, but I would not put the 2 works on the same level.

There is a work I surprisingly liked because of this weird reason. That’s One Room season 1. The 12-episode 5-minute-each anime series that shows each of 3 girls (they don’t appear together, each one has 4 episodes dedicated to one) talking to the camera as if she is spending time with the viewer. The makers call it "first-person anime". It felt like a novel concept, but as you may guess from its description, it’s going to be an awkward anime to watch. I obviously didn’t expect much from stereotypical anime girls talking to a silent camera. I just watched for the novelty since even if it was terrible, I only lose 5 minutes each week. The first 2 characters (8 episodes) was as I expected, kind of sweet but still boring, but it only lasts 5 minutes so I didn’t mind wasting those 5 minutes 4 more times. Each character has a song sung by the voice actor and used as the ending song, the songs are ok.

Spoiler Alert:

The following 1 paragraph contains spoiler for One Room season 1 episode 9-12. Although you may not think spoilers for this work is worth worrying about, the way I wrote has indicated that those episodes are unexpected. They’re probably worth a watch, they are only 5 minutes each anyways. Click here to show spoilers

This time the song felt vastly different. It has a soul now. The story behind it, while simple, was unexpectedly engaging. I could not believe I was moved by a show this awkward-appearing. If One Room had marketed itself as a collection of nice stories, it would not have this effect.

This behavior of mine, using how are expectations are subverted to decide whether to like an artwork, is probably irrational. It’s definitely better if I can view works more objectively, isn’t it? I assume this is not weird and many other people do the same.

There may be situations where this subversion-seeking behavior is beneficial, if many people have it, I guess. Like maybe it gives more chance to start-up authors than to established ones, which perhaps encourages innovations. Although it probably makes life harder for people under high expectations.

The video game series Half-Life by Valve is an interesting example. The first game (1998) is a classic, people were astonished by it, including me who played it at about 20 years later. Then the long-awaited sequel Half-Life 2 came out in 2004. People then had high expectations, and that’s probably when the fear of it being a disappointment was the highest. But Valve had apparently once again astonished the audiences by introducing so many new things that would definitely not exist had they been keeping their status quo. I remember reading about an interview to the games' leader, and he said astonishing people and making new breakthroughs was exactly what they worked hard for. The developers expected very high from themselves to match the expectations from consumers in order to succeed. But this high self-expectation was, as I understand it from reading various information, also their detriment. Half-Life 3’s development slowly halted and never completed, probably because both consumers and developers expected so high that they were unable to fulfill it.

So…​ Well, I don’t know what to take away from the discussions in this article, I just wanted to spontaneously talk for no apparent reason. So I hope this is informational, and thanks for reading. 🐁


The heading picture is taken from 0'23" of One Room season 1 episode 9.

Unless otherwise stated, the original contents on this website are licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.While reposting, please state that the article comes from FiveYellowMice's Blog, and include a link to the original article.

's avatar

违背期望

在 RSS 中无法显示完整的格式,不同的 RSS 阅读器所显示的内容也可能会有很大差距。为了能够获取到完整的内容,最好还是点开网页链接看。


我觉得影响自己对一篇艺术作品印象好坏的很大的一个因素,是它与我的期望中有多不同。这个艺术作品可以是文学的,绘画的,或者音乐的。

如果一部作品使我对它产生了很高的期望,不管是通过宣传材料还是它的作者(们)(之一)是一位曾经创作过优秀作品的人,那它都需要至少达到、或者超越这个期望值以使得它不显得“令人失望”。这部作品可以客观上很优秀,但是对于我来说,因为它比期望值要差,就有可能感觉好像它真的就是差一样。

同样的,如果我没有对一部作品有很高的期望,比如可能是一部来自从来没听说过的作者的预算比较低的作品,或者是看起来就不是很认真的作品(像是喜剧或迷因)。这时只要它最后比这个低的期望指要做得好,那我就会感觉它好像很厉害,尽管实际上它可能最多只能称作是“普通水平”。

还是来给一些例子吧。被新海诚导演的电影《你的名字》,有一位声望很高的导演、惊艳的宣传海报,并且在我观看之前还看到了非常多的来自其他人的夸奖。其结果就是对它的期望漂浮到了天上。然后在我观看完毕后,感觉到的却只是“不错”,这部电影真的值得那么多赞扬吗?这个问题不好回答。剧情的发展感觉有太多的巧合了,主角们的经历感觉更像是编剧为它们铺好的道路(当然,实际上也确实是这样),而不像是使人信服的冒险。所以在我刚刚看完电影的时候,只给了它 3.5/5 星的评价。我感觉这就是“被高估了”所代表的意思。但仔细想一想,《你的名字》是个精彩的电影吗?大部分人应该都会认同,我也在仔细想了想之后认同了。

在相似的领域,也是一部动画电影,《刀剑神域:序列之争》是相反的情况。《刀剑神域》这个系列可不以有深度的故事而闻名。实际上,很多评论家都觉得它很肤浅,只适合看看爽快。诚实说,我喜欢看《刀剑神域》,应该说,我觉得看看没有深度的爽快很开心。于是我去看了电影,然后电影也提供了刚好我所期望的——没有深度的爽快。实际上可能还稍稍超过了一点,因为电影的视觉效果要比我所习惯了的动画的视觉效果要更加华丽。甚至感觉在看完这部电影后比看完《你的名字》后还要感觉更好,但认真地说,两部作品可不会被我放在同一个级别。

有一部神奇的作品,恰好因为这个神奇的原因使我喜欢,它是《One Room》第一季。是一部共有 12 集,每集 5 分钟的动画系列。它展现的是 3 位少女(不是在一起出现的,而是每位各有属于自己的 4 集)对着镜头说话,像是在和观者在一起渡过时间一样。动画的创作者们称它为“第一人称动画”。这个点子听起来很神奇,不过从上面的描述应该可以看出,应该会是一部看起来会令人感到尴尬的作品。我显然没有对它抱有很高的期望,既然只是动漫美少女对着沉默的镜头单方面说话。只是它反正只有 5 分钟,为了这个神奇的点子,即使它就是很烂,每周浪费了 5 分钟也可以接受。前 2 位角色(前 8 集)的故事同期望中一样,有一点趣味但实际上还是比较无聊,不过没有关系,反正每集只有 5 分钟,再继续浪费 4 次这样的 5 分钟也没有关系嘛。每一位角色有着属于自己的角色歌,被作为片尾曲使用,这些歌曲还可以。

剧透提醒:

以下 1 个段落包含对 One Room 第一季第 9 到 12 集的剧透。尽管你可能不觉得这是一个值得担心剧透的作品,但我写文章的方式应该已经表示了这最后 4 集是出乎意料的。也许可以值得看一看,反正每集只有 5 分钟嘛。 点击此处显示剧透

这一次,歌曲的感觉完全不同了。它现在有了灵魂。在它之后的故事尽管很简单,但却出乎意料的引人入胜。我无法相信自己居然在被这样一部看起来很尴尬的动画打动。如果《One Room》在一开始宣传自己是一系列感人的故事的话,那它一定不会有这样的效果。

我的这个行为——按照一部作品如何违背期望来决定这部作品是否喜欢——大概是非理性的。如果能够更加客观的看待作品,那一定会更好,对吧?我觉得这个做法一定不奇怪,许多人应该也同样做。

不过有时大概这种行为也是有益处的,如果许多人这样的话,我猜。像比如,这样可能会给新出道的作者更多的机会,因此大概会鼓励创新。尽管对于承受高期望的人来说应该反而产生了更多的压力。

Valve 的电子游戏系列《半衰期》是一个有趣的例子。它的第一部游戏(1998 年)是一部经典,震惊了许多人,甚至也包括了在约 20 年后才玩它的我。然后它的续作《半衰期 2》在 2004 年众望所归地发布。人们有很高的期望,这个时候应该也是最害怕它实际上令人失望的时候了。但 Valve 显然又一次震惊了它的观众们,展现了许多新奇的东西。而如果它们只是维持了现状的话,这些新奇的东西一定不会出现。我记得有见过一篇对游戏团队领导的采访,他说,震惊玩家与取得突破正是他们所努力争取的。开发者们对着自己期望很高,才得以匹配消费者的期望而成功。但是这样高的期望——依我看过各种信息所理解的——也是它们的弊端。《半衰期 3》的开发渐渐停止,最后也一直没有完成,大概是因为开发者与消费者们对它的期望都太高,超过了实现的能力吧。

所以……嘛,我也不知道该从这篇文章的讨论中总结出什么,只是想突然无端地说一下。所以那么,希望这篇文章有一点价值,感谢阅读吧。 🐁


题图取自 One Room 第 1 季第 9 集的 0'23" 。

除特殊说明以外,本网站原创内容采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。转载时请注明来源 FiveYellowMice 的博客 ,以及原文链接

Phoenix Nemo's avatar

FAT32 与 FAT32 的不同

缘由:游戏用的台式机坏掉了。

HY's avatar

策略性游戏的随机性

这么多年策略性游戏玩下来给我印象最深的不是某些大公司的作品,而是一款独立游戏《Into the breach》 […]
ホロ's avatar

用 Hyper-V 玩些小花样

从前面那篇 Hyper-V 和 OpenWrt 搭建软路由 开始咱就开始在 Windows 上用 Hyper-V 了。 然后场面逐渐失控……

这篇文章就是把咱这几天遇到的各种问 …

's avatar

Making a Custom Smart LED Clock

It's not possible to display full formatting in an RSS reader, different RSS readers may also display drastically different layouts. Therefore it's recommanded to read the article by clicking the web URL.


The finished product displaying a time of Tuesday, 16 March 2021 13:37:07

After around 2 years, my first (presentable) DIY project is finally complete! It’s a device with a 16x16 LED matrix display, which is primarily used to display time. It’s also WiFi-connected, syncs time via NTP, can have 3 alarms, and potentially do more interesting stuff with its internet capability.

So, this post will document the process of me making this thing. I didn’t have many mishaps, the process is relatively smooth, and the reason it took so long is mostly me procrastinating.

For a lack of name ideas, I used a random pet name generator online, and it gave me the name "Baby Tiger". This is probably not the best name for a digital clock (it sounds like a very generic name for a cat), but I have no better ideas. Name suggestions are welcome.

The Electronic Components

I guess it’s because of watching YouTubers like GreatScott!! and DIY Perks piqued my interest and I wanted to make something of my own. And a clock with LEDs sounded like a fairly conservative thing to make that would not present much trouble, since similar hardware and design patterns seems to be done by others a lot. So with this thought, and the knowledge from YouTube videos that a kind of microcontroller⁠[1] called the Arduino would be suitable for controlling LEDs, I bought an Arduino Nano knockoff⁠[2], breadboard⁠[3], jumper wires and RGB LEDs.

The first RGB LED I got

This RGB LED is a package of 3 LEDs of colors red, green and blue. I need to power each color individually in order to display different colors. I made it to work, but there were big catches:

  1. I can’t adjust the brightness of each color components directly, so I can only have the primary and secondary colors, plus white and black (off). I had to use PWM⁠[4] in order to make fancier colors.
  2. The weirder problem was this RGB LED is unlike just 3 LEDs in parallel, the red, green and blues LEDs can’t be on simultaneously, which means I had to do PWM faster and the software needs to be a little more complicated.
  3. Each LED consumes 3 pins for the 3 color components. I was making a clock, so there eventually needs to be a large quantity of LEDs connected before displaying anything resembling time. There aren’t that many pins on an Arduino Nano. I learned about shift registers that can "expand" the number of controllable pins, but then I had to do PWM with software which felt very complicated. Shift registers will also make outputs slower, combined with the issue above, I was afraid that the speed of an Arduino Nano wasn’t fast enough.

I complained about this online and prepared to buy some shift registers to try nevertheless, then someone online suggested me to take a look at a more sophisticated RGB LED called the WS2818B. I looked it up, and it seems like a very popular choice of RGB LED. With a WS2818B, it will only need a single data pin to receive the color data, and will retain the color without the controller doing PWM. It also appears that those things can also be chained so I can have theoretically as much LEDs as I want, using just a single pin to transmit color. These features compared to the original LEDs, sounded like driving a car compared to crawling. I was carried away, and thought of expanding the project into something fancier.

I won’t make any regular old digital clock, I wanted make it to have a matrix of LEDs that functions as a screen, so that it can display more interesting things than just time. Coincidentally, I saw a product listing of 16x16 WS2818Bs pre-made into a matrix, which sounds like exactly what I want, saves me the trouble of laying out the total of 256 LEDs and soldering them.

The LED matrix, taken from the product listing web page

As I researched, the device won’t function with just a microcontroller and 256 LEDs. It will also need these less important, but still necessary things to be a decent clock:

  • A power supply. Both the Arduino Nano and the WS2818B matrix wants 5V power. According to an article I read online, a single WS2818B LED can draw 50mA of current, which sounds small. But I have 256 of them, so it multiplies to 12.8A. I couldn’t find a mains power supply that converts to 5V and is rated for more than 12.8A. What I was able to find were a mains to 12V power supply that can carry that much power, plus a converter that converts those 12V into 5V. The 12V-to-5V converter can only carry 10A though, but according to the article mentioned above, 50mA is just a maximum, so as long I don’t run it at full brightness and every pixel being white, it should be fine.
  • 5.5mm DC power barrel jack. This allows the 12V power supply to connect to the input of the 12V-to-5V converter.
  • DS1307 RTC module. This module keeps the clock running in the background, even when power is disconnected, so I would not need to set the time every time power is reconnected. I suppose it may also a bit more accurate than counting the time with the Arduino’s internal CPU clock.
  • More wires and breadboard.

At the same time, I came across something called an ESP8266. They say it’s similar to an Arduino, but it can connect to WiFi. I then excitedly decided to use that as the central microcontroller and ditched the now-dumb-looking Arduino Nano, and started daydreaming about the potentials of having internet access: I could synchronize time from the internet, and possibly displaying messages and notifications, even stream videos! (Yes, I know, playing a video on a 16x16 screen is extremely impractical. It could probably play Bad Apple though, which sounded pretty cool to me.)

Now the project has become more ambitious, I started to think of even more features that I could add to this clock.
Displaying current temperature? Yes, let’s add a temperature sensor.
Having the ability to sound alarms? Yes, let’s add a buzzer.
Buttons too small and ugly? Let’s use the 4 Cherry MX key switches⁠[5] I happened to have lying around instead of regular small tactile buttons, and use some custom key caps which I’ll worry about later.

So here are the aforementioned things I ended up having inside the clock, plus some other details:
(This photo was taken after the whole thing has been built, it obviously didn’t look like this at that stage. They were stuff plugged onto breadboards, I have a photo of that later in the article, but that photo wasn’t suitable for explaining what the components are.)

① 12V-to-5V DC converter
② 5.5mm DC barrel jack
③ Arduino Nano
④ ESP8266
⑤ DS1307 RTC module
⑥ BME280 temperature sensor
⑦ Buzzer
⑧ 5V-3.3V bidirectional logic level shifter, this allows the components operating at 3.3V (ESP8266 and BME280) to communicate with the components operating at 5V (others) without blowing up
⑨ The board that holds the 4 keys of the device, a.k.a. key board, not to be confused with a computer keyboard
⑩ Where the key board connects to the main board
⑪ Where the 16x16 LED display connects to the main board, the display is on the other side (front)
⑫ Unused connections of the display glued to the box so they don’t get in the way
⑬ Unused connections of a reset button, I decided later that this is unnecessary for normal use
⑭ Unused hole where the reset button was supposed to be

Why do I still have an Arduino Nano in the picture above? Didn’t I say I ditched it? Well, it turns out that controlling 256 LEDs with 1 pin requires a lot of work from the microcontroller. It requires very precisely timed signals so the microcontroller can’t do anything else during signal transmission, which is bad if I want to have WiFi connected because it requires some WiFi stuff to be constantly done, I also want time for my own code to run. There are tricks to use dedicated hardware to transmit these signals, but they either consume too much memory, or occupies the pin I need for other purpose. So I put the Arduino Nano back, and programmed it so that when the ESP8266 wants to update the display, it transfers the display data into the Arduino Nano, the Arduino Nano then does the time-consuming job of transmitting precisely-timed signals, while the ESP8266 carries on doing more important things. Was is a waste to put a whole Arduino just for this singular purpose? I suppose so, but it was the easiest way of solving my problem.

The Software

After I have got those components on the breadboard and connected (it didn’t look like the picture above, it was just on the breadboard), I started programming the software.

First, I decided the interactions I could have with the clock. It will have 4 buttons: , , , . When it’s powered on, it will display the current time (I’ll call it "clock mode"), pressing will turn off the display, and pressing will bring up the main menu, where the various additional functionalities (like alarms and settings) can be selected. and changes the selection, confirms the selection, and returns to an upper-level menu or the default clock mode.

Flowchart of basic interactions of Baby Tiger

While making the clock mode, I realized that there isn’t enough pixels to display everything about the current time. A 0-9 digit takes at least 3x5 pixels, each 2 digits needs to have 1 pixel between them so they don’t fuse together. It ends up being a little challenging. I have to use different colors for different parts of the time for them to look distinct. I made a separate screen to show the year number and month name when is held down. Pressing will on the other hand switch the time display into temperature/humidity and temperature/pressure obtained through the BME280 temperature sensor.

Examples of the different screens in clock mode

At this stage, I was pretty happy about what I have accomplished, so I posted its photo on social media.

What it looked like after completing the clock mode

Afterwards I made the main menu (and by afterwards I mean 1.5 years later, yes I procrastinated for that long). It shows the name of the menu item at the bottom half of the screen. Right now they are Alarms, Games and Settings. Since the screen is so small, only one option is shown at a time, and the text scrolls from right to left.

Main menu showing the "Settings" option

The settings menu consists of these options:

  1. Time: Setting the current time manually. There aren’t much to be noted, except writing the UI interactions were kind of tedious. Anyways, it works.
  2. Timezone: Because I use NTP to synchronize time with the internet, and NTP only cares about UTC, I have to take care of the local time offset locally, which is changed from here.
  3. NTP: I originally planned to make an On/Off switch for NTP, but didn’t ended up bothering, so right now it just shows the last synchronization time, and if there is an error synchronizing.
  4. WiFi: Setting the SSID and password of the WiFi network to connect to. Since the clock does not have a keyboard to type those things, I have to do it the around-about way: Let the ESP8266 make a WiFi access point for a phone to connect to, present a web page for inputting the SSID and password, receive them from the phone through HTTP, and finally try to connect to the network. Writing code for this process was the most tedious of them all (I wrote an HTTP server from scratch!). It eventually worked, kinda, although I don’t dare looking at the spaghetti code I wrote ever again.

In the alarms menu, I made 3 alarm slots. The enabled alarms are green, while the disabled ones are red. Since I don’t have enough vertical pixels to display 3 rows of timestamps, the last alarm will have its last bit cut off, and everything will get shifted up when the last alarm is selected. Going into an alarm setting (by pressing ) will let me change the hour, minute, on/off, whether it repeats on each day of of a week, and which music to play when the alarm triggers. It ended up looking pretty good, if I do say so myself.

Alarm setting on Baby Tiger. There are 3 alarms, the 1st and 3rd alarms are disabled, the 2nd alarm is enabled and set to 7:15, repeats every Friday, music set to Katyusha.

I originally planned to put some games on there, but they aren’t exactly necessary, and seemed like a lot of work, so in the end I didn’t write any. The "Games" on the main menu is just the demo music player that plays Senbonzakura.

I mentioned 2 musics that’s on Baby Tiger, Senbonzakura and Katyusha. They aren’t really musics though, as I could only play square waves from a ESP8266. It can’t play regular music file, nor does it play MIDI. These 2 tracks are just notes I typed into the code manually. (I really should write a script to convert from MIDI, if I really want many different music to select from. Doing this by hand is pretty time-consuming.)

And then I felt like the software was done enough. So the next step is to figure out how put them in a good-looking enclosure. But before that, I got to move the electronic component out of the wobbly breadboard, onto a more sturdy circuit board.

The Circuit Boards and Keys

So the plan was to have 2 separate circuit boards connected by a ribbon cable. One was going to be the main board, holding most of the stuff; the other was going to be the key board, holding the 4 key switches, as well as the capacitors and resistors for debouncing.

Let’s talk about debouncing⁠[6]. There are 2 ways of debouncing, hardware and software. I chose hardware because the article I read to learn about the topic said "It’s a hardware problem, so it’s best to be solved with hardware." and I agreed that hardware feels more elegant. The problem is, I don’t have an oscilloscope, so I just had to guess how long and how often the buttons bounce, and in turn had to guess the capacitance and resistance values in the debouncing circuit. The guesswork was a weird experience. The idea of hardware debouncing is to let the capacitor charge or discharge slowly when the button is pressed or released, so even if it bounces a little, the voltage would not change too much as to let the microcontroller think as extra button presses. That means the bigger the capacitance, the bigger the resistance, the slower the voltage changes, so the less likely for the bounces to have an effect, with the trade-off of the button press feeling more laggy, right? Well maybe my understanding is wrong, because changing to bigger capacitor apparently make the bouncing worse than having a small capacitor. Changing resistors could also make it worse – or better, it feels completely random, and the ESP8266 is so weird that some pins seems to work the best with different valued resistors than other pins. I still couldn’t understand why that is, maybe the answer will be more apparent if I had an oscilloscope. Eventually though, I figured out a circuit that worked well enough.

Schematic of the key board

I didn’t plan to draw and order a custom-made PCB, I thought just soldering stuff onto a perf board⁠[7] should work well enough for my purpose. I was wrong.

I started out making the key board since it’s the simpler of two. Then I realized what appears to be simple on a YouTube video may not be so simple if I do it myself. Those YouTubers had experiences and I didn’t. The process of realizing the circuit diagram above was slow and painful. I couldn’t keep the components in place before soldering them, it ended up resulting in none of the key switches are seated nicely, they tilted in all different directions. It’s really unideal, but what’s been done is done, I can’t do it again unless I buy new key switches. It was also difficult to make the wires connect to where I want them to connect to while not touching where I don’t want them to have contact with. After I finished making the key board, I concluded: There is no way I can do this manually for the much more complicated main board.

Schematic of the main board

Defeated, I sat back to the front of the computer, and decided to draw a PCB with KiCad. I didn’t know how to draw PCBs, but luckily it didn’t take too much time to learn with the help of guides found online. And I was glad to not go down the manual perf board soldering path, because the PCB I ended up drawing looked like this: They are all necessary connections.

PCB design of the main board, red lines are traces on the front layer, green lines are the traces on the back layer

I sent the PCB design to a company that makes custom PCBs for individuals. The board itself was not very expensive, costing US$ 4, but the shipping though, they cost $14 and was estimated to take about a month. The DHL express shipping costed $21 but is estimated to take less than a week. I chose the latter. The slow shipping was already that expensive, so it felt justifiable to buy the 1.5 times as expensive but 4 times as fast shipping method.

It took less than a week to arrive, as expected from DHL. I then soldered all the remaining components, completed with significantly less sweat than when I made the key board.

Now comes the moment of truth: If I drew the PCB wrong, then things will not work and I’ll have to spend $25 again. Or worse, I’ll blow up components. Luckily nothing seemed wrong as I plugged in power – a successful milestone.

The photo I took when posting on social media

The Enclosure

It was the time for the non-electronic part: making an enclosure for everything to sit nicely and look good in. In my imagination, I figured that the shape of the enclosure should be a rectangular box, with a shallow depth, like a picture frame. The front has the screen, covered with translucent acrylic, and behind the screen are all the control circuits. I figured that wood is probably suitable as its main building material. It’s heavy enough so the device won’t tip over, and it also sounds like a very commonly used material.

I had no experience in woodworking. I was a bit overwhelmed by all the information I needed to get started without spending too much money. There were questions like what suitable types of wood are, how to make right angled joints that aren’t easily broken, what types of glues I need, how to cut square holes, how to make a detachable backplate. A lot of the problems weren’t hard, they seemed to be pretty easy with powerful enough tools. But I didn’t want to spend that much money on powerful tools. They were really expensive. OK, they were not that expensive if I was going to use them all the time, but I couldn’t think of when the next time I use them will be, and investing hundreds of dollars into tools I could only think of using once is definitely not worth it.

To demonstrate my point above, let’s talk about how I wanted to cut 20x20mm square holes onto a piece of wood in order for the keys to poke out. What options did I have? The tools I had were an electric dill (which I bought from Ikea a long time ago) and a hacksaw. An electric drill can only dig round holes, how do I make square ones? The answer I got from the internet was to use a "router". Well, I did have a router to use, it even had 1 Gigabit Ethernet, but it’s apparently not the "router" I need to cut square holes. The router for cutting square holes was something I didn’t have, and costed quite a lot. And apparently, a router was not enough! To assist the router into cutting straight lines, I would also need a "template", and templates seemed to be quite a deep rabbit hole.

I guessed I could first drill a round hole that the diameter is the same as the side length of the square, and then use a saw to cut the corners. Like the left halt of the image below. But I could not find affordable drills bits that are 20mm in diameter, and I could not find saws that would fit into a 20mm round hole even if there were 20mm drill bits.

Circular holes are drilled first, then the material in shaded areas are removed by other means, creating square holes

So sawing were out of question, what else? Maybe using a file instead of a saw? It’s probably going to be more time-and-strength-consuming though, but I was able to find small enough files for not-too-high prices. As for drilling the round holes, I guessed using the largest drill bit my drill could hold (8mm), and drilling multiple of them should suffice. As seen of the right half of the image above.

After painstakingly researching every potential problem I though of (they were not enough), many WikiHow-reading and YouTube-watching. I settled on a design that balanced ease-of-making and looked passable.

The mockup 3D model. From left to right: front, back, back with backplate off

I originally planned to use wood for the square frame (yellow in the 3D model), the display support (orange in the 3D model, put there for the display to be glued on) and the back plate (also yellow in the 3D model). I didn’t expect regular wood to be so expensive though! So I turned to the alternatives, which are still at least made of wood fibres. Plywood, which are made by gluing thin pieces of wood together, and somewhat cheaper. And MDF, which are made by compressing wood fibres (I feel like they are similar to paper, just thicker and stronger. MDF also disintegrates with water, just like paper does.), and quite a bit cheaper. I contemplated on which to use, watched a few videos explaining the differences. It turns out plywood seems to be better because the dust is less fine and thus less harmful for the lung, and does not disintegrate with water. But I still turned to MDF since it’s quite a bit cheaper. It shouldn’t matter much for my project, I guessed.

So I went shopping for tools and materials. I bought:

  • A piece of 12mm thick MDF, very large, much more than I needed, but they don’t sell smaller ones.
  • 2 pieces of 3mm thick MDF, for some reason they had small piece for 3mm, and the size was just enough for what I needed.
  • A large file.
  • A set of small files, they only had small files in a set and not individually.
  • A handsaw.
  • Wood glue.
  • 4 clamps.
  • A square stick of cheap and soft wood for support while gluing and drilling.
  • 8mm drill bit.

Then I started cutting wood into the pieces shown below. The reason I used this shape with protrusions and slots for the side pieces was to increase the surface area of the joints. The 4 side pieces joins end-to-end, and the protrusions slots into the slots. I am not sure if this was worth the effort since this thing doesn’t need to be that strong, but everyone online seems to emphasize how important it is to increase the surface area of joints. And no one on YouTube seems to make a right angled joint by just sticking one end of a piece onto the side of another (a.k.a. a butt joint).

Wood pieces I cut. Black shapes are 12mm thick, orange shapes are 3mm thick. Units are in mm.

I tried to make the slots on the side pieces by sawing off as much material as the saw can reach and filing down the remaining. It turned out the large file I bought wasn’t suited for the job. I filed for a long time but little material were visibly removed. The small files were obviously going to be worse, since they are even finer. Now making the slots were already this hard with the files I have, making the square holes in the later steps were definitely going to be harder. So I went back to the hardware store, returned the small file set, and bought a set of rougher files. Filing was still slow with the rougher files, but at least my work could have visible progress.

Making the square holes was as painful as I imagined. Drilling the 8mm-diameter circular holes were easy with an electric drill. Removing the rest of the material in the square hole area was a long and tiring process. I filed and filed. Working from afternoon to evening to early night. Had my neighbour complaining about noise. The "square" holes were irregularly-shaped. But I was really tired, so I decided it was good enough and stopped for the moment. It later turned out the holes were not large enough to fit the keys, so I had to enlarge them a little after gluing.

The "square" holes as seen on the finished product. Don’t mind the key caps, I’ll talk about them later.

After cutting the 4 side pieces, I glued them together to make the frame. Since the protrusions and slots on the ends of the pieces were not that perfect either, the wood glue did not really make great contacts. But they still held up, which was good enough. I was really scared of the frame turning out to be not square (slanted into a parallelogram), but luckily it was square enough, after waiting 24 hours which was how long the label of the wood glue bottle said I needed to wait.

I also cut the display support and backplate, and glued the former with hot glue.

Since I originally planned the box to be made of wood, I didn’t plan to paint them. Wood grain patterns seemed pretty nice. But now I’m using MDF, I had to paint it so it is not MDF-brown-coloured. The front panel was supposed to be a black translucent acrylic in order for the screen to appear black where pixels were not lit. So I guessed I might as well paint the whole thing black. But also because it was MDF, which disintegrates with water, many paints cannot be used on it, including acrylic paint which was the one of the only paint types I could get in small quantities (I guess most paint containers were designed for people who paint walls and stuff. Buying 2kg buckets of paint just to paint this small thing seemed super not worth it for me.). I went to research online again, and concluded that I should use spray paint cans.

I went to the hardware store once again to buy the spray paint cans. The spray paint cans’ label said I need a primer as well, so I bought a can of flat black paint and a can of primer. Back home, I laid down paper of the floor of my balcony and started spraying. It smelled pretty bad even as I did it on the balcony. It was also a long process, since instructions online as well as the label said I need to wait 15 minutes between each coat. So after painting a few coats of primer and more coats of black paint, it became dark once again. Fortunately I finished before the sky was as dark as I stopped being able to see clearly.

Remember the hot glue I used to secure the display support? One corner came loose after the spray painting. So I added wood glue as it should be stronger than hot glue.

At this stage, I still did not have a way to put the back plate on. It needs to be removable as I need to access the electronics inside. I first thought of using screws, but people said screws in wood becomes loose after unscrewing. A friend suggested using magnets, which I guessed was a good solution.

I bought 5mm diameter neodymium disc magnets online. 5mm is a size that can fit into the sides of my 12mm thick side panels, and also a size I have a drill bit for. I drilled a hole on the middle of each of the 4 sides and placed magnets in them. I also taped magnets of opposite poles onto the corresponding locations on the back plate. There were more problems:

  1. My hand were not still during drilling. So the holes were not in the exact centers of each sides. They drifted a little, enough drift for me to having to adjust the locations of magnets on the back plate. Since the drifts were irregular, I had to lay the frame onto the back plate, poke the magnets into each of the 4 holes, then carefully lift the frame, leaving the back plate with the magnets on the correct location.
  2. I put the poles wrong! Same poles of magnets repel each other which was the opposite of what I want, so I had to take them off, and repeat the step above.
  3. 1 magnet pair on each side turned out to be a lot weaker than I expected (Aren’t neodymium magnets supposed to be insanely strong?). I tried drilling the holes deeper and adding more magnets. Eventually I put 4 magnets on each sides of the frame and the back plate, a total of 32 magnets.
  4. Hot glue could not make a strong bound for gluing neodymium magnets to MDF. I had to buy yet another type of glue: the 2-part epoxy. It came off once more, and had to try again with thicker layers of the glue.
  5. One magnet on one side of the back plate did not get glued well, and got broken off and stuck inside the corresponding hole on the frame. It seems to have stuck pretty tightly, so I didn’t bother getting it out and gluing it again. It became a feature.
Finished back plate, this side faces the inside so I didn’t bother painting, and the hole is for plugging power

Before putting the front panel on, I glued the display onto the display support, also with epoxy glue.

I wanted the acrylic front panel to be translucent, not semi-transparent, in order to diffuse the light from inside so I don’t see the pixels when they are off. The 200x200mm acrylic I bought from the beginning was translucent when the protective films were on, but I knew it would just be a semi-transparent black when the films were peeled off. Leaving a protective film on the finished product is definitely ugly, so I needed another light diffusing layer. I thought tracing paper would be fitting, but they were actually quite expensive and the stores I went to had them sold out. I found a piece of frosted plastic in alternative, which I think actually worked better than if I had used tracing paper. I glued one side of the acrylic to the cut frosted plastic with epoxy glue. And then with the plastic facing inside, I glued them onto the frame. It came off once and I had to glue again.

By the way, 2-part epoxy glue smelled a little gross, the B part smelled like fish for some reason.

With all these stuff done, I could finally put the electronics in. I glued the key board, main board, the 12V-to-5V converter, the DC power barrel jack in this order, with a combination of hot glue and epoxy glue. So far they have stayed in place.

Inside the enclosure after all components have been put in. It’s the same picture from before, ignore the numbers.

Completion

Plugging everything in, now it’s the most important moment of truth. If this somehow ended in smoke, I would be very upset. It shouldn’t have any problems though, as I have tested it in every stage. I was nervous, my hands trembled as I plugged in the power, my heart apparently stopped beating for a second before the display came on. But finally, my worries turned out to be needless, as the product of my hard work blinked each second with accurate time on the screen.

I called it a success.

I posted the completed photos on social media once again, and people congratulated me.

The final results. Left shows the time, right shows the temperature and humidity.

Well, it’s not flawless though. First of all, the whole thing looks totally handmade and imperfect. The surface finish is rough, and marks left by dried glue is all over the place. Some unpainted areas shows from the outside. The back plate does not attach well not only because the back of the frame is not flat at all, but also because the glue around the magnets on the back plate formed a chamfer, preventing them from going all the way in. Unlit pixels still shows though the front panel a little, though I guess it’s acceptable. And not to mention the ugly-shaped corner joints and holes for the keys. Also there’s an unoccupied hole on the left side that was supposed to house the reset button I ditched.

Second of all, the temperature measurement is a lot higher than the actual room temperature. The reason is probably the other components are dissipating a significant amount of heat so the inside becomes hot. I didn’t foresee this, I thought this thing wasn’t going to emit enough heat to affect the temperature measurement, I was totally wrong. The amount discrepancy is unacceptably high (like, about 8 ℃). Also because all the other environmental measures (humidity and pressure) are based on the temperature measurement, they are all unusable. I took off the back plate so it’s a bit better, but, like, there’s no back plate then.

It’s also not really finished. I used Cherry MX key switches, so I got to use key caps designed for a computer. But my buttons are , , and . On a computer keyboard, there are left and right arrows, but obviously no cross and circle. I could use X and O letter keys for and , but they are differently shaped from each other and the arrow keys. I saw online that epoxy resin⁠[8] is something people often use to make custom key caps, so I guess I could do that as well. But that’s another deep rabbit hole I’ll go into later in time. Meanwhile, I just randomly took 4 same-shaped key caps from a pile. They’ll eventually get replaced.

The software also doesn’t have much functionality. The excitement of having WiFi when I switched to ESP8266 did not do a lot. The only thing that currently uses WiFi is syncing time via NTP. I guess I might want to expand the software more later in time, adding countdown timers, stop watches, displaying notifications, and maybe actually playing Bad Apple.

Throughout the making of this project, it made me realize that DIY is probably not going to be a money-saving options oftentimes. The amount of money I spent on tools and materials is something I had lost count on, even though I tried to be as cheapskate as possible. Not to mention the amount of effort and time. I guess if the project is simple, and you have most of the tools, DIYing may be cheaper, I dunno. I wanted a custom digital clock that is not sold anywhere though, so I’d like to think my project was worth it for me.

That’s it. Finally I finished writing this long article which took 2 days to write. I have published all the code and design files, in case you want to know any technical details, or use them as references. 🐁


  1. A microcontroller is a micro electronic component that can be programmed to control circuits. It’s a very simple kind of computer.
  2. An Arduino Nano is basically the same as the most popular Arduino Uno, but smaller and cheaper. A Uno’s size is way too large in my opinion for something with this little processing power.
  3. A breadboard is a mainly-plastic board with holes all over them. One can insert electronics and wires onto it and have them work without soldering.
  4. PWM means turning on and off the LED so quickly that it appears to the human eye as if it’s continuously on but dimmer. Adjusting how much time it’s on verses it’s off changes how bright or dim it appears.
  5. A key switch is what’s underneath the key cap on a mechanical computer keyboard. Although it’s primarily used for keyboards, in terms of how it interacts with electronics, it’s the same as a regular button. I had the 4 key switches left over from repairing my computer keyboard.
  6. Buttons are mechanical construct, in the real world, the mechanical contacts will swing back and forth a bit when they are pushed together or released away. So pressing a button by hand once will be seen as the electrical contact has been closed and opened multiple times thus being thought as multiple key presses. Debouncing is the act of removing the effect of these unwanted openings and closings.
  7. A perf board is something like a circuit board, but with no internal connections and have a matrix holes filling the entire surface (So it doesn’t need to be custom-made). One would insert components on one side and solder and connect them on the other side. Search for images should give you a good idea on what it is.
  8. Epoxy resin is not the same as epoxy glue, although they are similar. Epoxy glue usually sets faster (tens of minutes), have a color tint, and sold in small volumes. Epoxy resin usually sets slower (about a day), are clear, and sold in larger bottles. Epoxy resin seems like a pretty popular material to make artistic objects, like custom key caps.

Unless otherwise stated, the original contents on this website are licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.While reposting, please state that the article comes from FiveYellowMice's Blog, and include a link to the original article.

ホロ's avatar

Hyper-V 和 OpenWrt 搭建软路由

笔记本上虚拟机越开越多,于是怎么给它们划分网络就是一个问题,例如代理软件什么的。

因为咱不想每一个虚拟机上就 …

HY's avatar

内容清空,重新开始

一转眼博客已经有1年多没写了。 刚好这个机会清空一下历史文章,重新开始。 也不知道这次能坚持多久_(:3」∠) […]
ホロ's avatar

咱和()的 2020 年?

就不要 不合时宜的 问为啥隔了接近三个月才写了…… (?)

以及第四年的总结 在咱的 Matters 上。

为啥这一年只写了八篇文章?

啊这……咱写字的地方越来越分散了啊……

Google Search Console 的表现,是怎么样呢?

这一年……?

因为众所周知的原因(COVID-19 啦……),于是几乎都是呆在家里, 然后被批判一番不务正业…… 那就记一下这一年玩过的游戏好了。

  • DJMax Respect V ,除了正式发售时突然降价引起抢先体验玩家不满和全程联网外加笨蛋反作弊插件以外, 只是 DJMax 这个老字号就能让咱接受前面的大部分缺点了。
  • 女神异闻录5 皇家版,给女神异闻录系列出加强版是 ATLUS 老传统了。
  • 集合啦!动物森友会,成功登上咱 Switch 游戏时间排行第一。
  • Project DIVA MEGA39s,咱为什么要买它…… FTDX 加上 DLC 它不香么……
  • Fluffy Store 和 ATRI -My Dear Moments- ,两部被推荐来看后觉得不错的视觉小说。(所以 fault - SILENCE THE PEDANT 还是没有出)
  • Untitled Goose Game,其实 2019 年在 PS4 上玩过了,今年借着在 Steam 上发售又玩了一遍。 (然而并没有人一起玩更新的双人模式……)
  • 妄想破绽和原神……一言难尽*2。
  • Halo: The Master Chief Collection,用手柄坑完了除了 ODST 以外的正常难度剧情,嗯…… 至少咱的老笔记本还跑得动。
  • 女神异闻录5 乱战 魅影攻手,第一次录下了全程 然后给友人做素材工具人(?)
  • Cyberpunk 2077,除了分不清是 Bug 还是剧情演出以外还好啦。 这话到底是赞美还是批评……
  • Spice & Wolf VR2, “什麼?你說今天12/10還有2077? 2077能有赫蘿嗎?” 新的动画鉴赏模式虽然短了点……
  • Stellaris, P社玩家没有一个无辜的……

当然除了这些以外还有些一直在玩的老游戏,也就是那些音游什么的。PSN 给咱发年度报告的时候去年游玩时间最长的 游戏还是 FTDX ……


剩下的一时想不起来了,就先这样吧。

's avatar

新的桌面工作站:HP Z2 G5 Tower

我的上一代桌面工作站是台戴尔的 Inspiron 660,购于 2013 年初。经过数年来的多次升级,它拥有了三代 i7 处理器、16GB 内存和固态硬盘。

其实这台机器的性能直到今天依然不算逊色,基本上可以满足日常使用。但是,因为一些个人原因,我开始日常需要开启多个虚拟机,于是这台机器的 CPU 就开始有些吃不消了。

考虑到这台机器已经有 8 年历史,于是我便决定让它退居二线,同时将主力工作站进行升级换代。

经过反复的挑选,我最终选中了惠普的 Z2 G5 Tower。它在这些方面非常吸引我:

  • 免工具维护
  • 极高的可扩展性,有着合理的升级路线
  • 没有光污染,但是不失颜值的机箱箱体

在我购买这台机器时,我其实已经听说了 11 代酷睿系列处理器即将发布的消息,但是我这台机器预期服役 5 年以上,感觉差上一代应该问题不大。

以及我买的配置其实听起来就感觉有点尴尬:i7-10700 / 8GB DDR4 2666 x1 / 2TB 机械硬盘,不过我自己已经有一些配件了,可以直接换上去用。

最终,成功在国内商家以 6.8k 拿下。

安装

因为卖家发的是顺丰,所以我下单以后第三天就到了。毕竟在内蒙古这种地方,这个速度已经算是很快了。

机箱的颜值确实不错,不过感觉比想象中的要略小一点。

  • 正面 IO:
    • 2 个 USB 3.1 Gen1
    • 2 个 USB 3.1 Gen2
    • 耳麦接口
  • 背面 IO:
    • 2 个 USB 2.0
    • 2 个 USB 3.1 Gen1
    • 2 个 USB 3.1 Gen2
    • 1 个 RJ-45(I219-LM,千兆以太网)
    • 线路输入和线路输出
    • 2 个全尺寸 DisplayPort
    • 1 个 VGA (Flex IO modules)

打开机箱也非常简单,只要扳动背面右侧的黑色开关即可。

后盖上粘贴的贴纸介绍了主板各个部位的用途。

中间那个横着的玩意是……显卡风扇。应该是辅助散热的,不过也给我后面的显卡安装带来了一些麻烦(见后文)。

工作站的主板。这块主板的可扩充性的确非常丰富,主要亮点有:

  • 4 条 DDR4 内存插槽
  • 4 个 SATA 3 接口
  • 两个 M.2 M Key 插槽(只支持 2280 尺寸)和一个 M.2 E Key 插槽(我这台已经预装了 AX201)
  • 4 个 PCI-E 插槽

顺便主板是前后一体贯通的,而且是非标准螺丝孔位,所以是没法更换市售主板的。不过对我来说无所谓啦。

传说中的 Flex IO modules;我这台配的是 VGA 输出。

预装的 AX201 网卡,支持 Wi-Fi 6 和蓝牙 5.0。

主板的 PCI-E 插槽,配置如下:

  • 1 个 PCI-E x16
  • 2 个 PCI-E x4(x1 信号)
  • 1 个 PCI-E x16(x4 信号)

其它配件

我的附带了一个笔记本尺寸的 DVD-RW 驱动器,不过还预留了一个空的 5.25 寸扩展槽。

700W 的电源适配器,有着 80 Plus 铂金认证。预留了两条 6+2 的显卡供电。

虽然是非标准的电源,不过使用一些高端显卡应该是绰绰有余。

Edit: 有 Telegram 群友指出这个电源适配器应该是符合 ATX12VO 标准的。电源参数看起来确实如此,但是实际上孔位和尺寸跟正常的 ATX 电源完全对不上,而且电源接口也是非标准的。

三星 8G DDR4 2666 内存。

东芝 DT01ACA200 机械硬盘(2TB / CMR);拆下来以后被我塞进 NAS 里了。

硬盘托架;这台机器可以安装两块 3.5 寸硬盘。

其它附带的东西

包装中除了主机本体,还有小册子、品字电源线、键盘和鼠标。

附带的键盘和鼠标;朴实无华,但是手感还算说得过去。

安装我自己的配件

随后,我安装了我自己已有的一些配件:

  • 显卡:ZOTAC GTX 1650 Super (4GB GDDR6)
  • NVMe SSD:铠侠 RC10 500GB
  • 内存:英睿达 16GB DDR4 2666

但是安装显卡时,我发现我扣不上机箱的显卡散热器。仔细一看,发现了问题所在:我的显卡的供电口位置很尴尬,恰好和散热器冲突。

所以,我只好先把固定散热器(?)的那个黑色的东西拆下来了,然后才有了足够的空间。拆下来以后看起来问题不大,机箱的显卡散热器还能固定住的样子。

那么把整个散热器都拆掉呢?我试了,结果机器在 POST 就会报错,抱怨风扇出现了问题。

理论上来说,我可以装个假负载,来让主板认为风扇在正常工作;但是这台机器的风扇接口也是非标准的,就有点尴尬。

使用体验

安装完毕以后,顺利开机,没有任何问题。

得益于 24G 的内存、8 核 16 线程的处理器和 Hyper-V,整体的体验是滑溜溜的,开 3 个 Windows 虚拟机都压力不大。

2021 年 4 月更新:因为发现 500G 的存储空间有点捉襟见肘,再加上 Chia 挖矿潮即将兴起,所以提前把固态硬盘换成了建兴 T10 240GB + 铠侠 RC10 1TB 的组合。很爽。

总结

感觉这台机器买的很值,相比我 8 年前的旧电脑,是一次非常巨大的飞跃。开心!

顺便一提,我在购买这台机器时,有考虑上一块更好的显卡,但是现在显卡实在是贵的太离谱了,就先把之前买的 GTX 1650 Super 装上了。(摊手

ホロ's avatar

Arch Linux 上的 GLNMP

前言

请允许咱引用一下 lilydjwg 的一段话:

我之所以现在记录这事儿,「现在」的原因是,我要在另一个系统上再测试一遍再发布出 …
RecursiveG's avatar

Ciphersuite Memo

I'm sorry if you landed in this keywords soup only to find it not helpful.

  • Key Exchange

    • DH (Diffie-Hellman): g^{xy} = {g^x}^y = {g^y}^x
    • ECDH (Elliptic-Curve DH)
    • ECDHE (ECDH Ephemeral)
    • DHE (DH Ephemeral)
    • RSA (Encryption): Generate a random bitstream and share it with the peer by encrypting using peer's RSA public key.

    A related concept is PFS (Perfect Forward Secrecy). DH offers PFS while RSA cannot.

  • Authentication
    Also known as key-signing. Commonly used together with the PKI(Public Key Infrastructure).

  • Encryption
    Used for data confidentiality.

    A related concept is mode of operation,which turns a block cipher to a stream cipher. CBC is a commonly used one. When it's used with AES, it's expressed as AES-CBC

  • Message authentication
    Used for data integrity. These algorithms are also called MAC(Message authentication code).

  • Authenticated Encryption (AE)
    Combines confidentiality and integrity. Wikipedia: Authenticated Encryption.

    • EtM (Encrypt-then-MAC): A secure way to combine encryption algorithms with MAC algorithms.
    • GCM (Galois/Counter Mode): A mode of operation, when paired with a block cipher, offers AE (actually AEAD) in one step.

    Some commonly used AE methods:

    • AES-CBC with an HMAC e.g.AES128-CBC-HMAC-SHA256.
    • ChaCha20 with Poly1305.
    • AES-GCM
  • Authenticated Encryption with Associated Data (AEAD)
    Similar to AE, but allows extra unencrypted data (associated data) to be authenticated. Roughly speaking:

    ciphertext = Encrypt(plaintext)auth_tag = Mac(associated_data + ciphertext)

    A common use case for AEAD is when encrypting a network packet, you want the packet header to stay unencrypted (for network routing purposes) but still authenticated.

  • Note about DH and curves of EC-based algorithms
    DH-based algorithms may have a “Group” option, which specifies a prime field or an elliptic curve. If a prime field is used, such as modp2048, it's normal DH. If an elliptic curve group is used, such as ecp256, it's EC-based DH.
    Some other curves may be used:

OX's avatar

做了一個Amazon Echo Dot (3rd Gen.)的固定支架

根據自己的需要製作的模型,用來固定Amazon Echo Dot第三代在牆上或者任何平面上,甚至天花板。

沒有考慮電源適配器的擺放,單純只是固定Echo Dot,一般來説,使用這個支架需要一個穩定的釘子或者螺絲。

可以使用現有的,已經固定好的螺絲或者釘子,預留了足夠的穿孔大小,一般來説不太會出現螺絲頭太大穿不過的情況。

如果使用鐵釘等較細的釘子或者螺絲時,可使用上方兩側的預留孔。

 

 

直接使用自攻螺絲固定時,可直接在中間預留的凹槽處鑽入。

 

 

下載模型檔案(STL):echo dot 3_1.5-stl

模型檔案以MIT許可證授權使用和修改及再發佈。

 

這篇文章 做了一個Amazon Echo Dot (3rd Gen.)的固定支架 最早出現於 OXの胡說八道

's avatar

二之路

我很早以前就像写一点东西记录一下自己二次元的心路历程了。我的记性算是差人一等的,很多年前的事情也记得七零八落的了。也正是因为如此,我希望能在脑子变得一干二净之前能尽可能多的记录下来,所谓“salvage”大概是如此吧。因为记忆问题,如果有差错也大概死无对证了。

Phoenix Nemo's avatar

在 Linux 系统中升级超微 BIOS 固件

最近突然有客户找来说 BIOS 进不去了呀…看截图 stuck 在 POST Code AB 大概就知道什么情况了。

这不就是经典的 y2k bug 再现嘛…

一般情况下,升级超微 BIOS 固件的推荐方式是制作 DOS 启动盘引导系统升级,不过现在 BIOS 进不去也没有物理 access 就只好在 Linux 里操作啦。

获取设备信息

简单命令 lshw

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
~> lshw | head -n 25
localhost
description: System
product: X9SCL/X9SCM (To be filled by O.E.M.)
vendor: Supermicro
version: 0123456789
serial: 0123456789
width: 64 bits
capabilities: smbios-2.7 dmi-2.7 smp vsyscall32
configuration: boot=normal chassis=desktop family=To be filled by O.E.M. sku=To be filled by O.E.M. uuid=[redacted]
*-core
description: Motherboard
product: X9SCL/X9SCM
vendor: Supermicro
physical id: 0
version: 1.11A
serial: [redacted]
slot: To be filled by O.E.M.
*-firmware
description: BIOS
vendor: American Megatrends Inc.
physical id: 0
version: 1.1a
date: 09/28/2011
size: 64KiB
capacity: 8128KiB

X9 主板不是 2015 年就 EOL 了吗这可真是够老了…

总之主板型号是 X9SCM 于是在超微找到了新版的 BIOS 固件。下载到系统中解压得到一堆文件,其中 X9SCM1.106 这个文件就是需要的 BIOS 固件本体。

编译 SUM 内核模块

Supermicro Update Manager (SUM) 是用于在系统中控制 BIOS/BMC 的程序。首先下载并解压,得到 sum 二进制文件和一堆其他东西。在 driver 目录中发现了对应发行版预编译的内核模块,但是直接 insmod sum_bios.ko 出错,好在它也提供了源码,那么就直接编译吧。

首先安装对应内核的 Linux 头文件,搜索 linux-headers 一般都可以找到。

1
2
~> uname -a
Linux localhost 4.19.0-13-amd64 #1 SMP Debian 4.19.160-2 (2020-11-28) x86_64 GNU/Linux

然后

1
~> apt install linux-headers-4.19.0-13-amd64 build-essential # 还需要 make 和 gcc

进入 driver/Source/Linux 执行 make,如果成功编译,则 insmod ./sum_bios.ko

嗯,这次没有报错了。

升级 BIOS

升级命令和其他主板商以及 RH 系的包命名风格一样喜欢大小写混合 = =…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
~> ./sum -c UpdateBios --file ../X9SCM1.106/X9SCM1.106
Supermicro Update Manager (for UEFI BIOS) 2.5.1 (2020/11/12) (x86_64)
Copyright(C) 2013-2020 Super Micro Computer, Inc. All rights reserved.

WARNING: BIOS setting will be reset without option --preserve_setting
Reading BIOS flash ..................... (100%)
Writing BIOS flash ..................... (100%)
Verifying BIOS flash ................... (100%)
Checking ME Firmware ...
Putting ME data to BIOS ................ (100%)
Writing ME region in BIOS flash ...
- Update success for /FDT!!
- Updated Recovery Loader to OPRx
- Updated FPT, MFSB, FTPR and MFS
- ME Entire Image done
WARNING:Must power cycle or restart the system for the changes to take effect!

至此就基本完成啦。然后直接重启即可生效。

不过还是需要注意一下,升级固件都是有变砖风险的,某些情况下需要先联系硬件厂商支持确定升级路线。

以及新版 X10 开始升级 BIOS 需要激活 license 了… 嘛。听说超微的密钥早就被提取出来写了算号器了(什

最后的最后,提醒各位到 2038 年只有 17 年了哦(笑

RecursiveG's avatar

IPsec 配置备忘 Part9 - RouterOS

这篇来填一个在 Part1 的时候挖的坑,简单介绍一下怎么在 RouterOS 和 strongSwan 之间配置一个 Site-to-Site 的 IKEv2 VPN。如果你还没有动手实际配置过 strongSwan,我强烈建议你先读完至少 Part1~5 和 Part7,并且自己动手配置一个能用的 strongSwan 服务端。这样至少能保证你会配置 strongSwan,否则同时学习 RouterOS 和 strongSwan 两种配置方法会让人云里雾里。

网络结构

RouterOS 做路由器,用 DHCP 给内网设备分配192.168.50.0/24段中的 IP 地址。并且用 IPsec 的 Tunnel 模式将所有来自此 IP 段的数据转发至服务器22.22.22.22。路由器本身的 IP 并不重要。

阅读基本 RouterOS 命令

在本文中我主要使用 RouterOS 命令来表示具体的配置,但是实际情况下调试 WebUI 会更方便。这里提供一张简图解释怎么阅读 RouterOS 的命令:

RecursiveG's avatar

Flexget+systemd.timer 配置

之前一直都是手动检查每周新番并添加到 Transmission 中的,最近尝试把这一流程自动化一下。简单搜索了一下发现了 FlexGet 这个工具。支持 Transmission 也能在 Linux 下运行,就决定是它了。

安装到用户目录

ArchLinux 源里并没有这个包,又考虑到这是个 Python 程序,所以就决定直接用venv了:

1
2
3
4
5
6
mkdir ~/.config/flexget
cd ~/.config/flexget
python -m venv virtualenv
source virtualenv/bin/activate
pip install flexget
pip install transmission-rpc

配置文件

配置方法可以看教程也可以看官方文档。我就只简单贴一下。

~/.config/flexget/config.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
templates:
transmission:
transmission:
host: 'https://domain-name.com/transmission/rpc'
port: 443
username: 'your-username'
password: 'your-password'

tasks:
这里随便写:
rss: 'https://mikanani.me/RSS/...'
accept_all: yes
template: transmission
transmission:
path: '/folder/path/on/server'

Systemd 配置

~/.config/systemd/user/flexget.service
1
2
3
4
5
6
[Unit]
Description=Refresh RSS with flexget

[Service]
Type=oneshot
ExecStart=/home/recursiveg/.config/flexget/virtualenv/bin/flexget execute

用户登录后 5 分钟进行同步,然后每两小时检查一次。

~/.config/systemd/user/flexget.timer
1
2
3
4
5
6
7
8
9
[Unit]
Description=Run flexget on login then every 2hrs

[Timer]
OnStartupSec=5min
OnUnitActiveSec=2h

[Install]
WantedBy=timers.target

一些可能会用到的命令:

1
2
3
4
5
6
7
8
# 启用并运行定时器
systemctl --user enable --now flexget.timer
# 立即检查
systemctl --user start flexget.service
# 检查定时器情况
systemctl --user list-timers
# 检查日志
journalctl --user-unit flexget.service -f
AlisterTT's avatar

2020年最后一天搞崩了VPS,2021年第一天修好了它。

这个VPS是2017年部署的了,当时随便选了操作系统ubuntu 16.10,一直没管升级,结果今年一看,源已经都不能用了,全世界都找不到源,就瞎鼓捣,一个autoremove把php给删了,这下瞎了,我甚至没有提前备份WordPress的数据。

用dump备份了数据库,www文件夹全部拷贝到本地,服务器重装系统,装了UBUNTU 20.04 LTS,NGINX PHP还有V2RAY倒还好配置,MySQL卡了半天。因为UBUNTU 20带的MySQL是8.0了,相比之前5.7变化比较大,主要是用户权限这一块,重来了好几次,最后干脆装回了5.7。

实际操作顺序大概就是,先安装配置好V2RAY,配置BBR,然后apt无脑安装NGINX和php,配置NGINX文件,安装phpmyadmin,安装配置mysql,添加WordPress数据库,安装WordPress,然后把dump备份的sql文件导入覆盖wordpress数据库,把之前的wp-content文件夹里的内容恢复,设置html目录权限777,齐活,差不多就这样吧,懒得打字了。

's avatar

我的 2020

好耶,我终于把 2020 年勉强过完了。

成就

我在 2019 年终总结里写道:

待定!计划赶不上变化的。

结果,受到 COVID-19 疫情的影响,今年的大计划其实几乎都泡汤了(包括计划参加的一个比赛、2020 年夏天的面基出游计划等)。

所以,总体上感觉今年是碌碌无为的一年。不过没办法……

买买买

不过今年买到了不少很棒的新硬件:

  • WI-1000XM2
    听感很好,佩戴起来相当舒适,而且 10 个小时的续航还是很香的。
  • 自组装台式机
    我第一次亲自从头开始组装的台式机,虽然有些配件选择上的遗憾,不过点亮后还是很有成就感。
  • 一加 8T
    强大的骁龙 865、65W 快充(虽然是私有协议)、滑溜溜的 120Hz 屏幕、很强的可折腾度……用起来太爽了!
  • AirPods Pro
    出门使用还是很方便的,包括超级简单的多设备切换功能!

今年并没有购买很多专辑,不过还是感觉这些是很不错的:

博客

今年的确没有写很多博客,不过还是做了不少工作,让它「符合潮流」:

  • 将评论系统后端用 TypeScript 进行了重构,修正了很多错误
  • 给自己博客增加了暗色模式,并支持跟随系统切换
  • 给自己写了一套全新的卡片式博客主题,使用了新的设计语言

2021 年计划?

SgDylan's avatar

同 2020 道别、相约 2021

再次,同样很普通地,为 2020 划上句号吧。


imi415's avatar

STM32H7-QUADSPI XIP及优化(WIP)

H750的128K真的不够用
RecursiveG's avatar

在 GNS3 中使用 ArchLinux

之前在折腾 strongSwan 配置的时候需要多台电脑互相连接做测试,用实机各种不方便。比方说,我不想暴露真实 IP,就只能在发布前手工编辑配置文件,也不知道编辑过后的文件到底能不能工作。于是尝试折腾使用 GNS3 来搭建一个虚拟的网络环境。

安装 GNS3

你可以尝试从 AUR 安装 GNS3,但是我之前试了几次都不是太成功,于是还是把 GNS3 装进了 virtualenv 里:

1
2
3
4
5
6
7
8
9
# 创建并进入 virtualenv
virtualenv -p python3.9 virtualenv
source virtualenv/bin/activate
# 安装 GNS3 及 PyQt5
pip install gns3-server gns3-gui pyqt5
# 安装一些其他的依赖(可能有漏的,请根据 gns3 的出错消息自己安装)
yay -S vpcs dynamips
# 启动 GNS3
gns3

GNS3 支持好几种方式来运行虚拟网络中的“节点”,我这里使用 Docker 来运行虚拟的 Archlinux 系统。因此也需要先安装:

1
2
3
sudo pacman -S docker
sudo usermod -aG docker `whoami`
sudo systemctl start docker

同时建议安装 Wireshark 方便抓包调试。

连接因特网

进入 GNS3 创建 Project 以后就可以尝试把左侧列表里的设备往中间画布上拖了。但是你会发现不仅设备类型少的可怜而且也基本拖不上去。这时我们需要自己创建设备节点的模板。进 Preferences,在最下面的 Docker containers 里点 New,Image name 输archlinux:base-devel,其他的都默认,Adapters 可以按自己需要指定数量。

点 OK 后,左侧的设备列表里就多了一个设备。拖到画布上,右键 Start,再右键 Console 就可以看到 ArchLinux 的命令行界面了。

GNS3 默认使用 xterm 作为终端模拟器,如果你像我一样使用 Gnome Terminal,需要先去 General - Console applications 把启动终端的命令改成

gnome-terminal -t "%d" -- telnet "%h" "%p"

这个新创建的 Archlinux 节点还是空空如也的,除了基本的系统什么也没有,我们可以把它连接到实际的网络上,这样就能用 pacman 安装软件包了。先从设备列表里拖一个“Cloud”设备出来,然后点左侧边栏最下面的“Add a link”切换到连线模式,点 Cloud 节点,选择物理机上用于联网的接口,再点 Archlinux 节点,选择要连接的端口,这样一条连线就接好了。Archlinux 节点被直接桥接到了外部接口上,和宿主机位于同一网段。

由于 Archlinux 的镜像不带 dhcpcd 无法自动获取 IP,只能手动设置一下咯:

ip link set eth0 upip addr add 192.168.1.222/24 dev eth0ip route add default via 192.168.1.1 dev eth0echo nameserver 1.1.1.1 > /etc/resolv.conf

不过实际测试以后发现这个速度实在是很残念,可能还是要写 Dockerfile 把镜像配置好再用才行。

violet's avatar

写在一年之际(二)

上篇写了猫,这篇写我吧。我其实非常不想谈这段经历,想起来就觉得挺难受的。

去年因为这样那样的原因以及一些骚操作加自尊心,本来有个亚麻 offer 也浪费了,当时的想法是老子来了之后再找,我要是知道后来发生啥非得抱着人大腿把 offer 求回来。

远程工作

这里要非常感谢我在前东家的老板,帮我办了几个月的远程办公,一定程度缓解了我找工作的压力。虽然远程工作没有很重的业务需求,不过也非常锻炼人的沟通能力,我以前觉得沟通对于我来说小菜,后来发现如果涉及到语言障碍和思维方式其实还是门深的学问。当然不要来跟我杠我的英语能力,我在口语上没有啥问题,虽然跟 native speaker 拼不过,但是不算差的那派。主要还是跟人沟通的思维方式上,如何进行有效的沟通也是一门学问。

刷题

老实说我不会刷题,上大学的时候因为 C++ 的作业是 ACM 题,我真是哭了又哭,反正我也不是啥好学生,题是真刷不动。但是为了找工作不得不开始刷,Leetcode 买了会员,分门别类开始学习。我其实更想说明区分刷题和学习,刷题只是过了一遍题,学习是学习怎样写这样的题,怎样的方式可以优化,遇到题想到考点在哪里。随着深入学习还要脱离编辑器的辅助,努力追求正确率,都是需要练习的事。人老说做题家刷题家,我无所谓,反正是面试敲门砖而已,我做好自己就行,自己躺地上嫌别人学习那我没得办法。

面试

我一直怀疑2020是我的本命年,甚至我追问了很久我妈是不是生错时间了。由于众所周知的原因,3月开始 lockdown,当时又面了一次亚麻,但是因为 virtual 面试写题的时候有点慌乱,没有 bug free 所以就挂了。之后很长一段时间网上也鲜有新职位,我就老实刷了一段时间题。6月开始不断投简历面试,怎么说……就是觉得差点缘分,有面着面着没信的,有面试完全没问题我还教面试官怎么写回头就跟我说实在抱歉,有 OA 做完明明 90% 以上但还是跟我 unfortunately 的,有等着安排面试时间回头跟我说他们找到人了,有以我没有 PR 拒的,更不要说简历投出去石沉大海的。期间也有几个猎头在紧密联系,不过都是些 start up,一个脾气不对就挂了(我还没说他们给我乱安排面试时间还放我鸽子),总之就是一刷邮箱眼泪就掉下来。我从来没有经历过如此低谷的时刻,每天都在自我反省到底我哪里做错了觉得我也没有这么差劲吧,脾气暴躁跟大柱一言不合就摔电脑,一刷 SNS 看大家的工作生活如此丰富多彩就开始难过。还有些人落井下石给我添堵我谢谢你啊。

很长一段时间都不想上网,啥都不想干,完全靠着大柱和几个朋友的支持坚持过来。大柱在我哭我撒泼我沮丧我难过的时候乖乖地抱着我。悦姐看我不说话不理人找我视频聊天,wandou 也在鼓励我,大毛还跟我一起动森聊了会天还给我寄了口罩,现在想起来都是我想流着眼泪感谢的人。

好在投了好久简历之后终于接到现在这家的 offer,在面试的时候就让人觉得很舒服,面试官(我后来知道是个士大夫)水平真是高,好多东西我觉得没问题,经过他一点播才发现噢!有道理,而且还有几个面试官聊过之后觉得真不错,有了 offer 就马马接了。事实证明这家真的不错,虽然公司小,但是同事水平是真高,我以前不觉得自己拉胯,现在发现最拉胯的是我(我要赶上!)

爱好

众所周知我是个指甲油爱好者,今年最大的变化是开始拍视频。一开始只是心情难过找点事干,一开始买了个手机支架开始涂开始拍,一年过了之后涂/印花/拍摄/剪辑的水平突飞猛进,甚至买了非常棒的相机和镜头搞得更专业一点。好多人都说开美甲店啥的,但那不是我的兴趣:),我还是好好拍视频玩玩就好。

没啥好展望的新的一年,世界回到正轨就好,找回失去的一年。

violet's avatar

写在一年之际(一)

一直在想写一个今年的总结,一拖再拖到了现在,今天早上被 Google 相册提醒,原来到加拿大已经一年整了。

我不是一个特别喜欢说情绪说经历的人,说多了都是矫情,甚至去年出国的时候也是跟交好的人吃了几顿饭然后就摸了出来,不过还是有一些事情值得记录一下。

拖家带口

自从开始准备来加拿大之后就在搜索如何带猫出国,我的功课如下。

适用地区:

北京

相关机构:

北京观赏动物医院、通州海关

加拿大海关要求:

超过一个月的狂犬疫苗证明

提前准备:

1. 超过一岁没有生病的猫(不要带小猫上飞机)

2. 符合航班要求的猫包(我带进机舱,加航的要求是55x40x27cm,比较奇葩的一个猫包尺寸,你买买就知道了,尽量符合高度限制就行)

3. 尿垫、便携猫砂盆和小包猫粮

办理过程:

1. 在出发前至少一个月(我提前了三个月)去北京观赏动物医院去打狂犬疫苗,说清楚是为了办出境,他们会建议一并注射芯片,加好医院联系出境的联系方式。

2. 确定人的行程后立刻打电话给航空公司买猫的票,能带进机舱的收费标准是100加币,每趟航班的宠物数量有限,一定要赶快打电话预定。另外猫算一件随身行李,所以理论上会少一个包,但很少有人查随身行李有多少件所以要求也不是特别严格。

3. 买好机票后立刻联系医院方,说明出发时间和出发地点,对方会建议一个时间去医院做体检和准备申报材料。

4. 带上护照、疫苗本和猫去医院体检,医院会帮忙整理材料申报给海关,医生建议2天后去海关处拿申报材料,但也说一般第二天就可以去拿。

5. 体检后第二天带猫和护照疫苗本去通州海关缴费、给猫查体温做基本检测以及拿到通关文书。

6. 出发哄骗吃好拉好(但明显不会听话不会拉撒)。带猫去机场 checkin,说明带猫。过海关的时候拿通关文书敲章。

7. 落地走申报通道,还是拿那堆通关文书,交进口税(21刀?30刀?)

中间趣闻:

狂犬疫苗:北美这些国家是消灭了狂犬病的国家,所以带宠物入境是需要注射狂犬疫苗的。狂犬疫苗非常容易致敏,麻达在注射了狂犬疫苗后开始出现了摇头晃脑,爪子特别烫的症状。我找护士看了看,对方说没事。但是在我带猫回去的路上开始呕吐而且出现了应激反应,赶快回医院,这个时候小猫咪已经出现了水肿,整个脑袋肿了起来,鼻梁老高。打了抗过敏药之后观察了一个小时才回去。如果大家要打狂犬疫苗一定要多观察一会,有任何异常一定要找医生看。另外防杠声明:猫三联里不包含狂犬疫苗,我们注射过猫三联。如果猫不出门的话狂犬疫苗一般不是必须的,因为根本没有感染源。

注射芯片:加拿大是不要求注射芯片的,但是我在打疫苗的时候医院强烈建议注射。我后来才知道去海关办通关文书的时候是要扫描芯片确认是疫苗本上的这只猫。

通州海关:我印象里政府工作人员都是冷冰冰而且给办事就算不错了,这次遇到了一个特别和蔼的阿姨,非常亲切,眼睛一笑眯一条缝。还祝我们一路顺利。

机场安检:安检的几个工作人员没有遇到过带猫过安检的情况。让我抱着猫过门,猫包单独过X光机。小哥很犹豫地问我它咬人吗?我说不咬随便抱!小哥还是很害怕,我就举着小猫咪让他摸了摸猫头猫腿猫肚子。

起飞和落地:虽然直飞只需要11个小时,但是加上提前出发和落地后到住处差不多要22个小时了。出发前各种哄骗小猫咪上厕所也没成功,而且怕中间饿我们还偷偷带了点冻干。但小猫咪精神明显不好,什么都不吃,刚开始的时候还呼呼大睡,后半段不耐烦开始小声叫。我带去洗手间放出来活动了活动终于好了点。入关的时候 CSBA 说你的猫呢,我举猫包起来给她看,小猫咪惊恐地瞪大了眼睛,她直呼 cute!我其实有点心酸,我是再也不想带猫再折腾一次了,人都觉得11个小时难熬,对于一只小猫咪来说真的是难上加难。

SgDylan's avatar

简单鉴别常见有损音源编码器

最近写 FLAD 的时候发现,可以用肉眼简单辨别立体声音频使用的有损编码器,在此简单记录。

OX's avatar

日本國內送金でチャールズ・シュワブ國際投資口座に入金する方法

チャールズ・シュワブ(Charles Schwab)の公式入金ガイドでは、シティバンク(Citi Bank)の支店にあるシュワブの受取口座に資金を送金するために、高い手數料がかかられる海外送金って方法のみになっている。

実際、現地の銀行口座(日本など)を持っていれば、現地の電信送金を使ってシュワブの口座に入金することができる。

まず、シュワブは米ドルだけでなく、日本円建て送金も受けられる、ドル以外の入金する場合はシティバンクがオープン為替レートで米ドルに両替し、ドル建てで投資口座に入金する。

國內送金で入金する時、最初に迎える問題といえば、シュワブ日本の入金口座は10桁であること。(日本の銀行システム的には口座番號の上限が7桁となっている)

電話でシティバンクに問い合わせするところ、シティバンクは、國內の地方銀行が國內振込で受取人の口座番號を正しく記入できないことを知っており、これを迴避方法をおしえてもっらた。

それは振込用紙にで10桁の受け取り口座番號を前の7桁切り取って受け取り人番號に書いて、殘りの三桁は受取人名義の前に書くこと。

ここでは一例をお參考に

受取人口座番號:0159051

受取人名義:404 Charles Schwab & Co.,  Inc.

ですが、受取人口座番號欄に存在しない番號になってるため、銀行のシステムがになるのは當然のことである、そのため、ネット銀行サービスは使えずに、銀行の窓口に行き、振込用紙を使って振り込むというやり方になる。

まだ、窓口で手続きしでも、當然エラーが出る、その時には銀行の人をそのまま実行しなさいと説得する努力が必要となる。

窓口で送金手続きが完了するとすぐに日本のシティバンク側に引き継がれ、當番のスタッフが受取人の名前の前に入力された3桁の番號を元に、正しい10桁の口座番號を手動で修正して送金を成功させる。

まだ、海外送金の場合、送金伝票にメッセージ欄があるが、國內送金の場合はそのような欄がない、これを解決するにはシュワブ投資口座の名義と番號を振込依頼人名に詰めて書けばよい。しかしそれをそのままに書いてだけではなく、前に「FORTHER CREDIT TO」を入れどいてのは重要のポイント。

「FOR FURTHER CREDIT TO YAMADA YUKI 2740-1234」

まだ、振込依頼人名の文字數は上限があり、だいたいの銀行は48文字までになってるが、これは事前に取引金融機関に確認すると無難だろう。

振込依頼人名は何文字まで入力できますか? – 三井住友銀行

もちろん、名前自體が48文字以上であって方もおるだろう(これはレアと思うが)、それならば、シュワブに(短い)別名を追加したいって書類を提出することによって、この問題を迴避するできると思う。具體的にはシュワブさんに聞くこと。

もう一つ気をつけなければならないのは、日本で送金用紙に記入する際に「フリガナ」欄には、全てアルファベットの大文字で記入すること。

まとめ

  1. 銀行の窓口に振込用紙を使え
  2. 送金伝票の受取人口座番號欄に、10桁の口座番號の最初の7桁を書き、殘りの3桁は受取人の名前の前に書くこと。
  3. 振込用紙には、英數字、符號だけしか書くこと、カタカナ書けずに(これ重要)。

もしうまくいけば、本來6,000円程度の費用をかけなければならないことをただ800円程度で済ませる。

しかも國內送金なので、対応する送金は30分以內に日本のシュワブのシティバンク口座に送金できるので、海外送金の2営業日や7営業日よりもはるかに早い。

最後までお読みいただきありがとうございました。

這篇文章 日本國內送金でチャールズ・シュワブ國際投資口座に入金する方法 最早出現於 OXの胡說八道

OX's avatar

使用日本國內匯款方式入金Charles Schwab International投資賬户

前略。

Schwab給出的官方入金指引要求使用手續費高昂的海外送金(International Wire)方式給Schwab在花旗銀行(Citi Bank)的各地分行開設的收款賬户轉賬入款。

實際上,如果有當地的銀行賬户(比如日本的)是可以通過一種曲綫救國的方法,使用本土轉賬的方式給Schwab賬户入金的,接下來我以日本的實際情況給出具體的操作方法。

首先是Schwab除了接受USD匯款,其實還接受多種貨幣匯款,然後由Citi Bank按照當天公開匯率兑換成美元入金到投資賬户上,具體的收款賬户在Schwab的官網公開文件上有記載,你可以在這裏看到。

Schwab要求匯款時提供對應的收款賬户的户名信息,包括開户人的名字(Alias Name也是可以被接受的)和八位數的賬户號碼(Account Number)。這裏有一個隱性的必要信息就是賬户的持有人的身份證件住址,但是實際操作上這個並不是必要的,雖然如果是通過國際匯款(a.k.a 海外送金、International Wire)理所當然地就需要填寫送款人的住址信息,但是其實這不是必要的。

另一個問題是Schwab提供的日本花旗銀行的收款賬號有十位數,而日本銀行系統最長可以錄入的賬號長度是七位數,看似技術上就不可行,但是其實有方法可以補救。

日本花旗銀行知道日本本土銀行通過國內轉賬的方式無法正確填寫收款人的賬號,所以提供了一種補救的方法,那就是匯款時在收款賬户號碼一欄上填寫賬號的前七位數,剩下的三位數寫在收款賬户名的前面。

這是一個例子:

受取人口座番號:0159051

受取人名義:404 Charles Schwab & Co., Inc.

通過這種方式匯出的匯款請求會由花旗銀行負責入賬的操作員手動修正為正確的十位數賬户,使匯款可以正常入賬,這是我親自打電話給花旗銀行日本分行的工作人員詢問,對方給出的方法。

而日本幾乎所有銀行的網上銀行系統都會在執行匯款之前檢查對應收款賬户和收款人名是否匹配,如果不匹配則無法執行,所以為了繞過這個問題,你需要去銀行櫃枱匯款,使用紙質的匯款單。

而為了讓這種操作可行,還需要有匯出銀行方面的合作才行,具體來説,因為收款賬户實際上是十位數,只寫前七位數的時候系統理所當然的會報錯,因為目標賬户實際上並不真實存在,你需要説服負責匯款的銀行工作人員無視系統的報錯,實行這筆匯款業務。

只要這筆匯款被提交,這筆匯款的信息就會被日本的花旗銀行系統接管,再由當班的工作人員根據收款人名義前填寫的3位數字手動補足成10位數的正確的賬户號碼使這筆錢成功入賬。

然後是匯款附言的問題,海外送金時,匯款單上有提供附言的欄位,但是日本國內匯款並沒有提供這個欄位,那麼怎樣才能把Schwab賬户名和賬户號碼寫進匯款單裏面呢?其實很簡單,那就是寫在匯款名義人(振込依頼人名)一欄上。

比如JOHN SMITH 2740-1234,但是需要特別注意,光這麼寫是不可以成功入金的,你需要寫得很清楚,要在前面寫上“FOR FURTHER CREDIT TO”,因為相比使用海外匯款的方式,日本國內轉賬實際上少了非常多的信息(比如匯款人的住址,電話號碼等),你需要加上這句話,讓Schwab的老頑固放心,給你入金。那麼振込依頼人名一欄最後看起來就會像是這樣:FOR FURTHER CREDIT TO JOHN SMITH 2740-1234。

那麼又出現了一個你可能會碰到的問題,那就是振込依頼人名這一欄最長只能寫48個字符(包括空格和任何標點符號),而有部分的日本銀行,甚至只能允許填寫20個字符,這明顯不夠,所以選擇一家可以允許填寫48個字符的銀行就成為了成功與否的關鍵,好消息是日本幾大銀行都允許填寫48個字符,其中就包括三井住友銀行(SMBC Bank)。

振込依頼人名は何文字まで入力できますか? – 三井住友銀行

 

當然可能你的名字非常長,甚至名字本身就超過了48個字符(這很少見,但是確實有可能),那麼你就需要通過提交添加一個更短的Alias Name申請給Schwab來規避這個問題,具體的操作可以打電話問Schwab的專員索要對應的表格,只要你申請給自己添加一個別名的請求獲得通過,你就可以使用那個更短的名字來執行匯款。

另外一個需要特別注意的問題是,填寫日本國內的匯款單時,都會要求填入フリガナ,你需要一律填寫英文大寫字母。

總結

  1. 去銀行櫃枱使用紙質匯款單實施匯款。
  2. 將十位數的收款賬號拆成兩部分,前七位填在匯款單的收款賬户號碼框上,剩下的三位數寫在收款人名義的前面。
  3. 振込依頼人名填入 FOR FURTHER CREDIT TO YOUR NAME 2740-1234
  4. 匯款單上的所有フリガナ不能出現任何除了英文、阿拉伯數字、標點符號以外的任何字符,特指片假名。

如果你成功了,你就可以僅僅使用大約800JPY左右的成本來解決平時需要花費6000JPY左右的海外送金手續費才能做到的事情。

並且因為是日本國內匯款,對應的匯款都可以在30分鐘內到達Schwab在日本花旗銀行開設的收款賬户上,相比海外送金快則兩個工作日慢則七個工作日的到賬時間明顯快非常多

謝謝閲讀。

 

這篇文章 使用日本國內匯款方式入金Charles Schwab International投資賬户 最早出現於 OXの胡說八道

RecursiveG's avatar

IPsec 配置备忘 Part8 - iOS 客户端

⚠ 天坑预警 ⚠

我在 iOS 12/13/14 各一台设备上测试过,但是测试的时候不是次次都能工作。由于 iOS 的坑实在太多,以及不同版本的 iOS 的行为都不太一样,如果你碰到了我没碰到的坑我只能祝你好运 (

接 Part6。折腾完 Android 以后我们来折腾一下 iOS。基本原理都是一样的,只是需要把苹果那一套 Vendor-specific 的配置选项翻译成 strongSwan 的,这样才能和服务器上的 strongSwan 互相通信嘛。由于 iOS 上的 IKEv2 客户端不是 strongSwan 而是苹果自己魔改的不知道什么版本,所以坑比起 Android 客户端更多。幸好 strongSwan 项目已经帮我们都踩了不少坑了:见 iOS (Apple iPhone, iPad…) and macOSIKEv2 Configuration Profile for Apple iOS 8 and newer

坑坑坑

由于本 Part 是基于 Part6 的,所以我们先来列举一下会需要我们做调整的 iOS 的坑(大部分在 strongSwan 的文档里已经提到过了):

  1. iOS 的 local_id 和 remote_id 全部都是 FQDN 类型,意味着我们需要按照 Part7 的说明给证书加上dns_name的 SAN。
  2. iOS 不允许 p12 证书使用空密码。
  3. iOS 12 还不支持 ed25519,所以我们需要改用其他算法。
  4. iOS 的 mobileconfig 全是坑。
  5. iOS 需要在配置描述文件显式指定 CA 的 CN 才会发送 CERTREQ。
  6. 你需要在服务端配置文件的 pool 里指定一个 DNS,否则 iOS 连上后无法上网。

基本流程是:生成密钥和证书;生成 iOS 的mobileconfig配置描述文件;想办法把这个文件安装到 iOS 设备上;最后尝试连接。由于 iOS 的配置文件比 Android 的复杂许多,所以我写了个 Python 脚本来负责生成,如果你用 macOS 也可以从苹果下载官方的配置工具。

's avatar

缪可消失之日

喜欢缪可的人通称缪客。大家都是缪客。

好吧,不是所有人,但是学校里的很多人,我认识的,我不认识的,都喜欢缪可。如果放学后有看到一群人围成一圈,像是在举行神秘仪式的邪教徒一样,那准保是在缪可。有的人喜欢缪可之甚,会在上课偷偷摸摸地缪可,被老师发现叫到后面罚站(现在这个时代肯定不能随便叫学生罚站了)。我们学校甚至有缪可社,不少学生都有加入,他们会隔一个周末,在学校的足球场上举办大型缪可,学生们围成的圈有时候会特别大,大到跑道上。不过有的学生不喜欢大规模的活动(比如我就只会做到放学经过社办门口进去看一看的程度)。所以足球场上的盛景,也是一位缪友告诉我的。

我不太想说,但是有人喜欢自然有人无感,甚至反感。二狗(他说他家里人也管他这么叫,不仅因为他是老二,而且是狗年出生)大概就是其中一位。他就不是很喜欢随大流,他的一句口头禅就是“干嘛学那些人”。我觉得这可能跟他有个优秀的哥哥有关,虽然二狗从来不跟我们过多提这个哥哥。

我问过他:“二狗试试缪可吗?”

他顿了一下,摇了摇头,“最近太忙了,没时间”。我也就没再问过他了。

或许是知道缪可在学校里的人气,学校外面的街角那里,最近还有立缪可的广告牌,特别大的一张喷绘布。广告牌里的明星我虽然不熟悉,但是不得不说,她缪可的样子确实有点酷。

所以今天,我以为也是上上课,课间和朋友聊天的时候提到几句缪可,放学之后稍微缪可一下,这样平凡的一天。我错了。


早上我看群里的消息,都是在讨论这个:缪可公司出了一个大丑闻。因为没有主流媒体报道,我只能从各个地方流传的消息里翻出个一二。虽然我自己对这类丑闻无所谓,但我大概知道,缪可完了。

不过我来到教室后,见到的又是另一番生龙活虎的景象:同学们或多或少都在讨论缪可,连一些就我所知从不缪可的人也加入了讨论。

“唉,缪可是挺好的,可惜被这个公司给毁了。”

“虽然我不是缪客,但是整这么一出,确实是要完了。”

“门口的那个广告牌估计要被砸了。”

我不忍心加入讨论,便拿出书来看,不过关于缪可的声音还是不断地传进我的耳朵。我只好装睡,用胳膊挡住耳朵直到上课铃响。

下课时,有些不缪可的人也会问我一句对这件事的看法,我回道,我能有什么看法,缪可要玩了呗。他们听到便嗤笑一声,继续聊别的了。有人在教室里对那位被罚站的同学大喊一句“今天还在课上缪可吗”,然后一阵哄笑。那位同学只是摇摇头,没说话。

放学后,本来司空见惯的缪可小团体也不见了。我经过缪可社办的时候,发现社办的牌子已经被卸下来,房间里不同寻常地冷清,偌大的房间里只有两个同学,一位在写作业,另一个在看手机,两个人我都有点印象。我问社团怎么了,看手机的同学抬了头望了我一眼,说:“决定解散了。”是嘛,我回答道,然后默默地离开。这是我最后一次进缪可社的房间。

路过街角,那个缪可的广告牌被人砸破了。破洞的位置大致在那位明星的脸附近。周围围了一圈人,有的人说“草”,有的人在拍照。我加快了脚步,想要把这个景象扔在脑后。

我知道从今天起,没有人敢在白天缪可了。

晚上在床上辗转反侧,理性告诉我,别去想缪可的事了,但是我就是止不住地去想,一旦想到,就止不住地难过。我问自己:“缪可本来不该是给人带来快乐的事情吗?为什么我现在这么难过?”

我笑了。我决定忘了它。


几天之后,再去缪可社的时候,大门已经紧锁,门上贴着一张纸:

“虽然我们是喜爱缪可的一群人,但是我们无法容忍缪可公司的所作所为。所以我们决定,在缪可公司给出回复并作出道歉之前,无限期停止缪可社的活动。缪可社”

街角那个被打烂了脸的广告牌,第二天也拆了,只留下空空的铁架子。广告牌上的明星公开道歉,并宣布停止与缪可公司的一切合作。

二狗有问我:“最近还在缪可吗。”

我回答道:“没了。”

“哦。”他说道。然后他就没再问过我了。

RecursiveG's avatar

IPsec 配置备忘 Part7 - 证书 II

接 Part2 与 Part6。尝试折腾一下除了“以证书 DN 作为 id”以外的证书使用姿势,如果有错误或者与本文解释相冲突的情况欢迎在评论指出。

IKEv2 证书认证

在 IKEv2 里,一方需要认证另一方基本只需要两样信息IDAUTH。ID 就是之前配置文件里反复出现的那个,AUTH 一般是使用证书私钥对某些数据的签名,具体细节请参考 RFC。证书则是把两者关联了起来:如果对方给出的 AUTH 能通过证书验证,那么对方就是这份证书所表示的那个人,同时这份证书又是颁发给 ID 的,那么对方就是 ID。

验证者要取得对方的证书有几种方式:

  • 管理员可以直接把证书塞进验证者的/etc目录里
  • 被验证者可以自己把证书发送给验证者(send_cert = always参数)
  • 验证者可以向被验证者请求证书(send_certreq = yes参数)。当然被验证者也可以选择不发送证书(send_cert = never参数),只是验证会失败就是了。

另外如果验证者既不询问证书(send_certreq = no),被验证者也不主动发送证书(send_cert = ifasked),验证一样会失败。

strongSwan 在尝试匹配 ID 和证书的时候会检查 Subject DN 和 SubjectAltName (SAN)。我们之前一直在使用 Subject DN,而 SAN 则允许我们使用域名甚至 IP 作为 ID。另外,虽然我一直称呼“域名”或是“IP”,但是实际上只要 SAN 和 ID 匹配即可,这个“域名”到底是不是我们的并没有关系。(当然只有自签才能签出这种证书)

Subject Alternative Name

要颁发带有 SAN 的证书只需要在 tmpl 文件(参见 Part2)中添加如下内容:

# 域名 SANdns_name="san.hosta.com"# IP 地址 SANip_address = "fd00::1"

需要注意的是,SAN 是区分类型的,比如上文的 DNS 和 IP,而 IKEv2 使用的 ID 也是分类型的(FQDN,IP,etc.)。类型需要匹配才能认证成功。有的教程会使用形如@xxx.xxx.xx.x这样的 IP,可能原因是,某些客户端使用 IP 作为 ID 但是却标记为 FQDN,或者是生成证书的时候将 IP 标记成了域名 SAN。这种情况就需要给 IP 添加前缀@来强制让 strongSwan 将其当作域名 ID。具体的解析规则可见 Identity Parsing 文档。

除了在证书生成上的这些零碎注意点之外,我觉得另一点导致 IKEv2 很难配置的因素是,strongSwan 允许省略很多参数,而不同的平台会给这些被省略的参数提供不同的默认值,导致你以为的设置和程序实际使用的设置出现偏差。更不用说有的平台还有一些稀奇古怪的 BUG。

Android Client w/o DN

这里我们尝试重复 Part6 中的实验,只是不出现 DN,全部用域名代替。同样的,只有有变化的部分才有注释。首先重新生成证书加入 SAN,你只需要重新用 CA 私钥签发服务器证书即可:

1
2
3
4
5
cn = "server common name"
# 域名 SAN,需要和 ID 相匹配
dns_name = "vpn.server.com"
activation_date = "2020-01-01 00:00:00 UTC+0"
expiration_date = "2021-01-01 00:00:00 UTC+0"

然后先看客户端 Profile 的变化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
jq -n \
--arg uuid `uuidgen -r` \
--arg name "My server"\
--arg type "ikev2-cert"\
# 注意这里(以及下面的 json 里)去掉了 remote.id。在 Android 客户端上,如果不指定
# remote.id,那么 ID 就默认是 remote.addr 中的值。
#
# 用服务器的域名代替了 IP 地址,目前客户端似乎还是会优先使用解析出来的 IPv4 地址,
# 所以后面 JSON 里的 ipv6-transport 配置也不用了。
--arg addr "vpn.server.com"\
# 这里换成了 CA 证书,注意下方新增了 remote.certreq 配置项。
# 虽然这个配置似乎默认就是 true,不过还是加上以防万一。
--arg servercert "`sed '/-----/d' ca-cert.pem`"\
--arg localbundle "`sed '/-----/d' client-p12bundle.pem`"\
'{
uuid:$uuid,
name:$name,
type:$type,
remote:{
addr:$addr,
cert:$servercert,
certreq: true
},
local: {
p12:$localbundle
}
}' > profile.sswan

主要变化之一是省略了 remote.id 并将 remote.addr 从 IP 改成域名。注意这里不是不设置 ID,而是采用客户端的默认值(remote.addr)。和服务器配置中的省略 remote.id(%any)有巨大不同。之二是使用 CA 证书而不是直接使用服务器证书,至于为什么需要设定 certreq 请参考第一段。

再看服务端配置变化:

server.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
connections {
android-connection {
version = 2
# 由于客户端优先采用 IPv4 解析,这里就需要改成 IPv4 的地址了。
local_addrs = 12.34.56.78
remote_addrs = %any
proposals = aes256gcm128-sha512-x25519
pools = ip4pool
local {
# 和客户端设定的 remote.id 保持一致(
# 恰好是客户端设定的 remote.addr (
# 恰好是服务器的域名
# )
# )
id = vpn.server.com
auth = pubkey
}
remote {
id = %any
auth = pubkey
}
children {
child_sa {
local_ts = 0.0.0.0/0
remote_ts = dynamic
mode = tunnel
esp_proposals = aes256gcm128-sha512-x25519
}
}
}
}

pools {
ip4pool {
addrs = 10.10.10.100-10.10.10.150
}
}

这样我们就配置好使用域名作为 ID 的 strongSwan 服务器了。

RecursiveG's avatar

IPsec 配置备忘 Part6 - Android 客户端

接 Part4,终于要开始准备搭一个能用的 VPN 服务器了。另外,如果你要拿这个配置去翻墙请自便,但是不对实际效果做任何保证,本文只考虑传统的 VPN 使用场景。

基本上,服务端的配置和 Part4 中的一致,这里着重介绍如何配置客户端。配置使用 Play Store 上的 strongSwan客户端,版本为 2.3.1。

服务器配置

首先,这个客户端似乎还不支持 ed25519 证书,因此我们需要改为使用 ecdsa 证书。完整的证书生成操作请看 Part2,在生成私钥时指定--key-type ecdsa即可。现在假设你已经生成好了所有 6 个文件:ca-key.pem,ca-cert.pem,client-key.pem,client-cert.pem,server-key.pem,server-cert.pem

另外,这次我们会在服务器上配置 NAT,所以不再需要手动在服务端配置一个 IP 了。假设服务端eth0接口的公网 IP 是2000::1。首先将ca-cert.pem,server-key.pem,server-cert.pem三个文件移动到服务器上正确的地方。然后编写配置文件,同样的,这里只注释和 Part4 中不同的地方。

server.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
connections {
android-connection {
version = 2
# 服务器的地址。根据官方文档,服务器内核版本需要大于等于 5.8
# 才能支持 Android 客户端使用 IPv6 地址连接
local_addrs = 2000::1
# 接受客户端来自任何地方
remote_addrs = %any
proposals = aes256gcm128-sha512-x25519
# 只分配 IPv4 的虚拟 IP
pools = ip4pool
local {
# 请按照实际情况修改 id
id = CN=server common name
auth = pubkey
}
remote {
id = %any
auth = pubkey
}
children {
child_sa {
# 允许客户端将去往所有目的地的流量发送给服务端
local_ts = 0.0.0.0/0
remote_ts = dynamic
mode = tunnel
esp_proposals = aes256gcm128-sha512-x25519
}
}
}
}

pools {
# 只保留 IPv4 池
ip4pool {
addrs = 10.10.10.100-10.10.10.150
}
}

配置完毕后systemctl restart strongswan

客户端配置

在客户端上,我决定创建一个可以直接导入的 Profile 文件,避免手工输入一大堆地址(要记得我在用 IPv6)。首先需要把 client-key.pem 和 client-cert.pem 合并成一个文件,注意 bash 本身是不支持多行命令和注释穿插写的,在执行的时候需要手动移除注释:

1
2
3
4
5
6
7
8
9
10
11
certtool \
--load-privkey client-key.pem \
--load-certificate client-cert.pem \
# 名称随意
--p12-name "Key Cert Bundle" \
# 空密码
--empty-password \
# 合并成 PKCS12 格式
--to-p12 \
# 需要指定 3des-pkcs12,否则 Android 系统无法正确导入
--pkcs-cipher 3des-pkcs12 > client-p12bundle.pem

新生成的文件是client-p12bundle.pem。然后我们参照 strongSwan 的文档创建可以直接导入应用的 Profile 文件。当然你也可以手动导入证书再手动配置 Profile。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
jq -n \
# 生成一个随机的 UUID
--arg uuid `uuidgen -r` \
# Profile 的名称,可以随意写
--arg name "My server"\
# 认证类型
--arg type "ikev2-cert"\
# 需要手动指定 remote id,否则服务器的地址将被当作 id,导致认证失败
# 当然你也可以在创建证书的时候就把服务器地址写在证书里,避免手工指定 DN
# 注意:id 和服务器地址和证书有复杂的检验关系,填写不当容易造成各种奇怪的
# 身份验证错误。
--arg remoteid "CN=server common name"\
# 服务器的地址,我这里使用 2000::1 代替了实际地址,使用 IPv4 和域名也是可以的。
--arg addr "2000::1"\
# 嵌入服务器证书,注意这里我直接嵌了服务器本身的证书。嵌 CA 证书应该也是
# 可行的,但是我没试。
--arg servercert "`sed '/-----/d' server-cert.pem`"\
# 嵌入客户端私钥和证书
--arg localbundle "`sed '/-----/d' client-p12bundle.pem`"\
'{
uuid:$uuid,
name:$name,
type:$type,
remote:{
id:$remoteid,
addr:$addr,
cert:$servercert
},
local: {
p12:$localbundle
},
"ipv6-transport": true
}' > profile.sswan
# 根据官方文档,服务器内核版本需要大于等于 5.8 才能支持客户端使用 IPv6 地址
# 连接。同时需要设定 ipv6-transport 为 true。如果你使用 IPv4 则不需要此设置。
# 另外这里没有指定 local.id,根据文档,在没有指定 local.id 的情况下,客户端程序
# 会自动使用客户端证书的 DN 作为 id

最后将生成的profile.sswan文件拷贝到手机上并导入即可。然后试一下能否成功建立连接。

NAT 配置

然后这样配置完了,虽然能连上服务器,但是依然不能访问网络,我们还需要在服务器上配置一下 NAT。一般是一条防火墙的masquerade规则。这里只简单把配置放出来给自己做个备忘,不做细讲:

nftables.conf
1
2
3
4
5
6
7
8
9
10
table ip nat {
chain prerouting {
type nat hook prerouting priority 0;
}

chain postrouting {
type nat hook postrouting priority 100;
ip saddr 10.10.10.0/24 meta oifname eth0 masquerade
}
}
RecursiveG's avatar

IPsec 配置备忘 Part5 - 防火墙配置

记录一下使用到的端口以及需要做的防火墙配置,不一定能覆盖所有场景,如果有漏掉的规则欢迎留言补充。

TL;DR 在两端均放行:

  • UDP 500
  • UDP 4500
  • ESP 协议

最基本的 IKEv2 使用 UDP 500 端口进行通信。当密钥交换完成后,Linux 内核会将加密了的数据包封装在 ESP 中发送。所以整个包结构是:

Ethernet - 外层IP - ESP - 内层IP - <...>

但是我们也知道,所有除 UDP 和 TCP 以外的四层协议都不能很好地穿过防火墙和 NAT,于是给 ESP 套一层 UDP 就是很自然的事情了:

Ethernet - 外层IP - UDP[dport=4500] - ESP - 内层IP - <...>

这层多出来的 UDP 的端口号就被人为规定成 4500 了。另外由于一些我没有搞明白的原因,strongSwan 会在某些情况下使用 4500 进行 IKE 通信,即使并不需要 ESP UDP 封装。

在默认配置下,strongSwan 需要所有三种规则:使用 UDP 500 和 4500 (即使没有 NAT)进行 IKEv2 协商,然后内核发送 ESP 包。如果有 NAT 存在,strongSwan 会使用 UDP 4500 对数据进行封装而不使用 ESP。

如果你不想放行 4500 又不想影响非 NAT 流量,可以在配置文件中设置mobike = no。你也可以使用encap = yes选项在没有 NAT 的环境中模拟 NAT,强制使用 UDP ESP 封装。如果你能确保你的所有 ESP 流量都是 UDP 封装的,那么不放行 ESP 也是可以的。

如果你使用不封装的 ESP,那么你需要在连接两端都放行 ESP 数据包,不然可能会出现奇怪的现象。比如,你必须先从 A ping B,然后才能从 B ping A,直接 ping 不通,之类的。

用于nftables.conf的放行规则如下:

1
2
3
4
5
udp dport 500 accept
udp dport 4500 accept
# 外层 IP 可能是 IPv4 也可能是 IPv6,需要两条规则来放行所有 ESP 包
ip protocol esp accept
ip6 nexthdr esp accept
's avatar

USTC Hackergame 2020 - Writeup

USTC Hackergame 2020 - Writeup
RecursiveG's avatar

IPsec 配置备忘 Part4 - Virtual IP

第四篇主要讲一下怎么给客户端下发内网 IP ~
Part1 传送门Part2 传送门Part3 传送门

Virtual IP (VIP)

接 Part3,有了 Tunnel 模式以后我们实际使用的 IP 地址就不用受制于机器的实际 IP 了。但是手动给每个客户端手动分配一个地址显然是不切实际的。于是我们可以使用 Virtual IP 功能自动向连入的客户端分配一个内网 IP,就像 DHCP 或者 SLAAC 那样。

场景配置

与之前完全对称的配置不同,使用 Virtual IP 时需要区分服务端和客户端。先在服务端配置将要分配的 IP,然后由客户端发起连接,服务端就会将配置好的 IP 分发出去。我使用 HostA 作为服务端,HostB 作为客户端。HostA 将会给 HostB 分配 IPv4 与 IPv6 各一个。使用的 Virtual IP 段是fd01::100-fd01::20010.10.10.100-10.10.10.150

hosta$ ip -br addreth1         UP             fd00::1/64 fd01::1/128 10.10.10.1/32hostb$ ip -br addreth1         UP             fd00::2/64

和 Part3 相比,HostA 这里有一些与之前不同的地方,一是内部 IP 全部放在了 eth1 上(而不是 lo 上);二是内部 IP 的前缀长度都是最大值;三是增加了一个 IPv4 的内部 IP,用于和分配的 IPv4 Virtual IP 通信。同时 HostB 也不再手工分配fd01开头的内部 IP 了,将由 strongSwan 自动配置。

当连接建立后,我们应该能看到在 HostB 的 eth1 上出现两个新的,自动分配的 IP。且分配到的 IPv4 地址与 10.10.10.1 之间的通信是加密的,分配到的 IPv6 地址与 fd01::1 之间的通信是加密的。

配置文件

配置文件基于 Part3 修改而来,有变化的部分已添加注释:

hosta.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
connections {
conn_hosta_hostb {
version = 2
local_addrs = fd00::1
remote_addrs = fd00::2
proposals = null-sha-modp2048
# 指定要使用的 IP 池
pools = ip6pool,ip4pool
local {
id = CN=HOSTA_COMMON_NAME
auth = pubkey
}
remote {
id = %any
auth = pubkey
}
children {
child_sa {
# Local TS 加上新增的 IPv4 地址
local_ts = fd01::1/128,10.10.10.1/32
# Remote TS 设置为 "dynamic"
# strongSwan 会自动将其替换成分配出去的 Virtual IP
remote_ts = dynamic
mode = tunnel
esp_proposals = null-sha-modp2048
}
}
}
}

# 定义 IP 池
pools {
# IP 池的名称
ip6pool {
# 池中的 IP,也可以使用 fd01::100/120 这样的表示法
addrs = fd01::100-fd01::200
}
ip4pool {
addrs = 10.10.10.100-10.10.10.150
}
}
hostb.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
connections {
conn_hosta_hostb {
version = 2
local_addrs = fd00::2
remote_addrs = fd00::1
proposals = null-sha-modp2048
# 向服务器请求 VIP,0.0.0.0 代表任意 IPv4
# :: 代表任意 IPv6
vips = 0.0.0.0,::
local {
id = CN=HOSTB_COMMON_NAME
auth = pubkey
}
remote {
id = CN=HOSTA_COMMON_NAME
auth = pubkey
}
children {
child_sa {
# 类似 HostA 的 Remote TS,dynamic 会被自动替换
# 成从服务端接收到的 VIP
local_ts = dynamic
# 增加服务器的 IPv4 内网地址
remote_ts = fd01::1/128,10.10.10.1/32
mode = tunnel
esp_proposals = null-sha-modp2048
}
}
}
}

链接测试

与 Part3 中的对称链接不同,这次你必须从客户端发起连接,也就是从 HostB 执行如下命令:swanctl -i -c child_sa。连接建立后,你应该就能看到自动分配的 IP 了:

hostb$ ip -br addreth1         UP             fd00::2/64 fd01::100/128 10.10.10.100/32

此时再从 HostB 分别 ping fd00::1fd01::110.10.10.1,你应该能看到前者没有加密,而后两者的 ICMP 包被包在了fd00::1 <---> fd00::2的 IPv6-ESP 包里:

RecursiveG's avatar

[娱乐向] Samsung 980 Pro RAID 性能测试

三星的新 SSD 980 Pro 已经发售一段时间了,前两天看到 Amazon 上 1TB 有货,赶紧下单两条。今天到货,于是装机测一波速度。打算用来做系统盘,所以自然就是用来组 RAID-0 咯。于是用 fio 分别测试了一下 btrfs 和 mdadm 组 RAID 的性能。测试完全不严谨,参数是用脸滚键盘滚出来的,放出来仅供各位一乐,为什么是娱乐向你看数据就知道了。同时拉上了打酱油的 960 Evo(我现在的系统盘),以及完全是搞笑用的/dev/shm

场景连续读取(MiB/s)连续写入(MiB/s)4K 随机读取(kIOPS)4K 随机写入(kIOPS)
980 Pro 单盘 EXT463704725330125
980 Pro 单盘 BTRFS6264272013763.7
980 Pro mdadm RAID-0 EXT4121869426298115
980 Pro BTRFS RAID05937393213363.3
/dev/shm62905541792571
960 Evo 单盘 XFS296341019931.3

Emmmm, mdadm RAID0 比内存快……这很合理……以及 btrfs 你的 RAID 性能还能更烂一点吗?

测试用设置在此,测试/dev/shm的时候关掉了direct以及把文件大小改成了1g:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[global]
ioengine=libaio
direct=1
time_based
runtime=60
numjobs=1
iodepth=32
group_reporting
size=10g

[seq_read]
stonewall
bs=1M
rw=read

[seq_write]
stonewall
bs=1M
rw=write

[random_read]
stonewall
bs=4k
rw=randread

[random_write]
stonewall
bs=4k
rw=randwrite
RecursiveG's avatar

IPsec 配置备忘 Part3 - Tunnel 模式

第三篇简单介绍一下 IPsec 的 Tunnel 模式,没看过前两篇的快去看~
Part1 传送门Part2 传送门

Tunnel 模式简介

前两篇中我们使用的都是 Transport 模式,但是实际使用中,更常用的是 Tunnel 模式。Transport 模式只加密四层及以上数据,而不修改 IP 头,原始的 IP 头将会原样传输。这意味着我们只能进行点对点传输,因为只有一个 IP 头,我们无法告知对方服务器我们实际要访问的地址。Tunnel 模式则是连原始的 IP 头也一起加密,然后再在前端添加一个新的 IP 头,这样服务器在收到数据包后,可以解密并读取内部的 IP 头,再转发给实际的目标服务器。

配置场景

这次的场景在 Part2 的基础上略有改动:在 HostA 与 HostB 的lo接口上分别添加fd01::1/64fd01::2/64:

hosta$ ip -6 -br addrlo               UNKNOWN        fd01::1/64 ::1/128eth1             UP             fd00::1/64 [--omit--][--omit--]hostb$ ip -6 -br addrlo               UNKNOWN        fd01::2/64 ::1/128eth1             UP             fd00::2/64 [--omit--][--omit--]

在没有建立连接的情况下,fd00::1 和 fd00::2 可互 ping,fd01::1 和 fd01::2 不可互 ping。在建立连接后,fd00::1 和 fd00::2 可互 ping,但是不加密,fd01::1 和 fd01::2 可互 ping 且流量加密。

配置文件

配置文件也是在 Part2 的基础上改动而来,变化部分已加注释

hosta.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# hosta
connections {
conn_hosta_hostb {
version = 2
local_addrs = fd00::1
remote_addrs = fd00::2
# 使用 NULL 加密以方便抓包观察
proposals = null-sha-modp2048
local {
id = CN=HOSTA_COMMON_NAME
auth = pubkey
}
remote {
id = %any
auth = pubkey
}
children {
child_sa {
# Traffic selector 改为 fd01::*
# 这意味着 fd00::* 不被选中,也就不会被加密
local_ts = fd01::1/128
remote_ts = fd01::2/128
# 传输模式改为 Tunnel
mode = tunnel
esp_proposals = null-sha-modp2048
}
}
}
}
hostb.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
connections {
conn_hosta_hostb {
version = 2
# 交换 local 与 remote
local_addrs = fd00::2
remote_addrs = fd00::1
proposals = null-sha-modp2048
local {
# 使用 HostB 的 id
id = CN=HOSTB_COMMON_NAME
auth = pubkey
}
remote {
id = %any
auth = pubkey
}
children {
child_sa {
# 交换 local 与 remote
local_ts = fd01::2/128
remote_ts = fd01::1/128
mode = tunnel
esp_proposals = null-sha-modp2048
}
}
}
}

链接测试

启动 strongSwan 和 Wireshark,在 HostA 上,可以 ping fd00::2 但是不能 ping fd01::2。然后用sudo swanctl -i -c child_sa建立连接,依然可以 ping fd00::2 但是数据不加密,同时能够 ping 通 fd01::2 了。抓包可以看出明显的ETHERNET-IP-ESP-IP-ICMP的包头层次,并且外层 IP 使用 fd00::* 进行数据传输,内层 IP 使用 fd01::* 的实际目的地址:

RecursiveG's avatar

IPsec 配置备忘 Part2 - 证书

作为系列的第二篇文章,讲解基本的证书原理和配置方法。没看过第一部分的快去看~
传送门:IPsec 配置备忘 Part1

证书认证基础

我们在 Part1 中看到,PSK 认证的基本思路是使用一个只有通信双方才知道的暗号,如果能确认对方确实知道这个暗号,那么认证就成功了。证书认证的思路非常不同:假设 A 需要向 B 证明自己的身份,同时 A 知道 B 信任 C,那么 A 可以向 C 索取一份“介绍信”,当 B 询问 A 的身份时,A 可以向 B 展示这份 C 出具的“介绍信”,如果 B 能够确认这份“介绍信”确实是由 C 出具的,那么认证就成功了。注意这个认证是单向的,假设 A 也信任 C,那么 B 也可以通过向 C 索取“介绍信”来向 A 证明自己的身份。在 PKI 体系中,A 和 B 持有各自的“私钥”,C 作为 Certificate Authority (CA) 向 A/B 颁发证书(即“介绍信”)。同时,CA 也会向自己颁发一份证书并分发给 A/B,A/B 使用 CA 的证书来确认 B/A 出示的证书确实为 C 所颁发。

RecursiveG's avatar

IPsec 配置备忘 Part1 - IKEv2 基础

俗话说得好,配置 IPsec 隧道只有零次和无数次,在被 strongSwan 折磨了 N 次以后,我终于决定要把之前试过的配置都记录下来,于是就有了这个系列。我计划基本上每个 PART 会介绍一个(或几个)特定场景下的配置,配置文件样例以 strongSwan vici 为主,之后可能会介绍 iOS, Android 或者是 Mikrotik 路由器的配置方法,如果我能坚持不鸽写到那里的话(画外音:你这 FLAG 立得……) FLAG 回收了。如果各位有想看的配置场景欢迎留言告诉我,会考虑先写。

IKEv2 与 IPsec 基础

严格来说 IKEv2 不是 VPN,它的全称是 Internet Key Exchange,只是一种用于交换密钥的协议罢了。密钥在计算机里一般就表示为一串固定长度的二进制数据,密钥交换就是指在两台设备之间约定一个相同的二进制串,就像两个密友之间约定暗号一样。一旦密钥交换完毕,IKE 的使命就结束了,具体怎么用约定好的密钥加密数据不是 IKE 解决的问题。在 Linux 系统上,实际的数据包加密解密是由内核的 XFRM 框架负责的,你可以使用ip xfrm命令看到配置好的密钥以及加解密使用的算法。事实上,不使用 IKEv2 而完全手动“交换”密钥是可行的,比如朴素VPN:一个纯内核级静态隧道。你可以看到作者直接使用ip xfrm {policy,state} add指令设定密钥,然后内核就会自动用设定的密钥加密流量。

然而,手动管理内核状态是复杂的,人工分发密钥也不怎么安全,这时就轮到 strongSwan 登场啦(或者说,任何实现了 IKE 的 Daemon 服务)。两台服务器的 strongSwan 使用 IKEv2 协议交换密钥,解决了密钥分发的问题。随后 strongSwan 会把交换得来的密钥设定进内核,这样内核就会自动加密指定的流量了。

从数据包层面上看,IKE 是7层协议,密钥交换使用特殊的 UDP 包完成。而一般被加密的数据包会使用 ESP 封装,ESP 头一般紧跟在 IP 头后。ESP 也可以被封装进 UDP 用以穿越 NAT。

没有 TUN 设备

内核 XFRM 的工作方式和基于 TUN 设备的 VPN 很不一样。一般基于 TUN 的 VPN 会加密所有进入 TUN 设备的流量,因此你可以直接使用路由表来控制哪些流量走 VPN,哪些不走。而 XFRM 的匹配基于策略(i.e. 源地址+目标地址+一些别的),如果某个数据包匹配到了一个策略,这个数据包就会根据这个策略指定的方式被加密。

比方说有A [fd00::1]B [fd00::2],如果你从 A 发送一个数据包到 B,普通情况下这个数据包是明文的。如果你在 A 配置了src=fd00::1,dst=fd00::2,encrypt=<...>的策略并再发一个数据包,这个包就会自动被加密。B 收到了这个数据包,但是它并不知道该如何解密,所以你必须同时在 B 配置一条src=fd00::1,dst=fd00::2,decrypt=<...>的策略,这样 B 才能解密。对于从 B 到 A 的流量也需要类似的两条策略。使用 IKEv2 的话,这些策略 strongSwan 都会自动帮你设置好,无需操心。于是你会发现,尽管我们仍然在使用节点本身的 IP,但是流量却已经被加密了。

对于那些必须使用路由表或是策略匹配不是很有效的场景, Route-based IPsec VPN 也是存在的。我也许会在未来的某一期讲。

RecursiveG's avatar

Linux + Windows 10 多系统安装 U 盘

Update: Windows 的引导程序似乎有些问题,如果在同一块 U 盘上写入多个 ISO 分区的话,似乎引导会错乱,最终启动的安装程序版本不是引导程序所在分区的版本。所以暂时一个 U 盘还是只能放一个 Windows 版本。垃圾巨硬。

日常折腾中总免不了要用 LiveCD 修理一下系统,或者是重装一下 Windows 之类的。这时候制作一个引导用的 U 盘基本是最方便的选项了。有不少工具都能创建 U 盘引导,比如 ArchLinux 的 ISO 镜像可以直接用dd写入,Windows 的安装盘也能用 Rufus 创建。不过在使用上还是有些不便,比如dd会覆盖整个U盘,在ISO之外不能再存储其他文件。Rufus 只能在 Windows 上运行,而且一只 U 盘也只能放一份 ISO。于是尝试搞明白怎么把 Linux 的 LiveCD 和 Windows 的安装 ISO 写入到同一只 U 盘就很有必要了。

我个人使用的设备都支持 UEFI,所以这里制作的启动盘也只支持 UEFI 启动,需要 MBR 模式启动的读者请往它处寻。当然,Secure Boot 是要关掉的。制作过程我使用 Linux,纯 Windows 用户现在也可以退出了。基本上,我们需要创建一个 EFI 系统分区(EFI System Partition, ESP),其中包含基本的引导程序(Grub2)和 Linux LiveCD 的 ISO 文件。由于 Windows 的安装程序无法以 ISO 形式被引导,因此我们需要给每个 Windows ISO 文件创建一个分区,并将 ISO 中的内容解压进去。但是分区一旦创建不像文件那么好修改,所以创建每个 Windows ISO 分区的时候我都留了一些额外空间,以备以后 ISO 大小变化,这也意味着这些空间就基本浪费了。That's sad but I guess it's how things work.

另外,购买一个优质的 U 盘还是有必要的,不然不管是创建启动盘还是安装系统都会慢得让你痛不欲生。建议用之前先给 U 盘测一下速,什么拷贝速度只有 2MB/s 的金士顿可以直接进垃圾桶了。至于 U 盘大小取决于你要放多少个 ISO 文件和多少个 Windows 分区,一般 Linux 镜像大小在 500MB~3GB 的都有,Windows 10 的分区一般每个需要 5~6GB.

farseerfc's avatar

關於 swap 的一些補充

上週翻譯完 【譯】替 swap 辯護:常見的誤解 之後很多朋友們似乎還有些疑問和誤解,於是寫篇後續澄清一下。事先聲明我不是內核開發者, 這裏說的只是我的理解, 基於內核文檔中關於物理內存的描述 ,新的內核代碼的具體行爲可能和我的理解有所出入,歡迎踊躍討論。

誤解1: swap 是虛擬內存,虛擬內存肯定比物理內存慢嘛

這種誤解進一步的結論通常是:「使用虛擬內存肯定會減慢系統運行時性能,如果物理內存足夠爲什麼還要用虛擬的?」 這種誤解是把虛擬內存和交換區的實現方式類比於「虛擬磁盤」或者「虛擬機」等同的方式, 也隱含「先用物理內存,用完了之後用虛擬內存」也即下面的「誤解3」的理解。

首先,交換區(swap) 不是 虛擬內存。操作系統中說「物理內存」還是「虛擬內存」的時候在指程序代碼 尋址時使用的內存地址方式,使用物理地址空間時是在訪問物理內存,使用虛擬地址空間時是在訪問虛擬內存 …

RecursiveG's avatar

在 Raspberry Pi 4B 上安装 ArchLinux


很久之前就买了一个树莓派,不过一直在吃灰,正好最近有空就再拿出来折腾一下。原装系统是 32 位的,那么就必定要换一个 64 位的啦,不然对不起这 64 位的 CPU 呀。秉承“Arch大法好”的理念,我就决定用 Archlinux ARM 了。我非常建议先用原版系统更新 Bootloader 和 EEPROM到最新版本。这样可以避免各种奇怪的 bug 和使用一些新加入的功能,比如从网络启动什么的。

ArchLinux ARM 其实已经提供了树莓派的安装教程,基本上只要跟着做即可,我用的是 AArch64 镜像,并且把根文件系统从 ext4 换成了 f2fs,希望在 SD 卡上能有一点点加成效果。装完以后发现串口没有输出,自然不能忍,继续折腾。RPi 4B 一共有两个串口控制器,一个 PL011,另一个被称作 MiniUART。默认情况下,PL011 连接到蓝牙模块,并且 MiniUART 被禁用,但是我们可以通过 config.txt 加载 dtb overlay 来调整。一些常见的配置有:

  • 启用 MiniUART 串口,PL011 继续负责蓝牙
  • 禁用蓝牙,让 PL011 负责串口通信
  • 启用 MiniUART,让 MiniUART 负责蓝牙,PL011 负责串口

但是 ArchLinux ARM 使用 U-Boot 来启动内核,并不遵循 config.txt (╯°Д°)╯ ┻━┻

那么我们只能把 U-Boot 干掉了 (<ゝω・)☆

使用 MiniUART 作为串口

SD 卡的 \boot 目录里需要这么7个文件,RPi 4B 的 bootloader 才好启动 Linux 内核:

  • config.txt: 主要配置文件,uboot-raspberrypi 有提供,但是我们手写。
  • start4.elffixup4.dat: 第二阶段 Bootloader, 由 raspberrypi-bootloader 包提供。
  • rpi4.dtb: RPi 4B 的 Device Tree 文件, linux-aarch64 包中提供了一个基于上游代码的,位于 /boot/dtbs。但是我试了几次都不能正常启动,所以还是从 Raspberry Pi 官方的 Github 下载了一份。
  • Image: 内核可执行文件,由 linux-aarch64 包提供。
  • initramfs-linux.img:由 mkinitcpio 程序生成。
  • cmdline.txt: 内核参数文件,手写。

那么直接上配置:

1
2
3
4
5
enable_uart=1                               # 启用 MiniUART
kernel=Image # 指定内核文件的名称
arm_64bit=1 # 要求以 64 位模式启动,否则默认是 32 位
device_tree=rpi4.dtb # Github 上的 bcm2711-rpi-4-b.dtb 文件,我改了个名
initramfs initramfs-linux.img followkernel # 指定 initramfs 文件

start4.elffixup4.datcmdline.txt 都是原名,就无需写进 config.txt 里了。

1
console=serial0,115200 root=PARTUUID=e10d384f-02 rootfstype=f2fs rootflags=rw elevator=deadline audit=0 rootwait
  • PARTUUID 需要改成你自己的,可以用 sudo blkid 查看
  • rootflags f2fs 似乎默认以只读挂载,会导致没有办法登录。
  • audit=0 关掉 audit,否则内核信息撒得满地都是。

全部折腾完以后把 SD 卡塞进树莓派,应该就能在串口看到登录界面了。

使用 PL011 作为串口

我在安装的时候碰到一个 MiniUART 的 BUG,串口的 Baudrate 不对,内核输出一片乱码。可以尝试使用 PL011 作为串口,也可以升级内核解决。使用 PL011 需要在 boot 分区里加一个新的文件

  • overlays/disable-bt.dtbo: 需要从 Github 上下载,用来禁用蓝牙,并且让 PL011 负责串口通信。

同时需要修改 config.txt 加上 dtoverlay=disable-bt 以启用。此时 enable_uart=1 不再是必要的了。

登录之后

登录之后建议先把 uboot-raspberrypi 卸了,然后 dhcpcd 连上网 pacman -Syu 一下,再重启确认一下启动过程都正常。之后就是标准的 ArchLinux 服务器配置过程:时区, 网络, 防火墙, etc. 搞定以后我们就有一台 AArch64 服务器了。

暂时没有 GUI 的需求,相关的配置就留到下次再折腾了。

's avatar

中秋打油诗一首

故国路漫漫,佳节灯阑珊。

遥望人结伴,俯视影落单。

一碗白米饭,半瓶百岁山。

曲尽人已散,孤苦不堪言。

farseerfc's avatar

【譯】替 swap 辯護:常見的誤解

這篇翻譯自 Chris Down 的博文 In defence of swap: common misconceptions原文的協議CC BY-SA 4.0 ,本文翻譯同樣也使用 CC BY-SA 4.0 。其中加入了一些我自己的理解作爲旁註,所有譯註都在側邊欄中。

翻譯這篇文章是因爲經常看到朋友們(包括有經驗的程序員和 Linux 管理員)對 swap 和 swappiness 有諸多誤解,而這篇文章正好澄清了這些誤解,也講清楚了 Linux 中這兩者的本質。值得一提的是本文討論的 swap 針對 Linux 內核,在別的系統包括 macOS/WinNT 或者 Unix 系統中的交換文件可能有不同一樣的行爲, 需要不同的調優方式。比如在 FreeBSD …

's avatar

在新款 MacBook Pro 以 EFI 的形式安装 Windows 10(2020 更新)

本教程不适用于 ARM Mac!

为什么?

最近我想玩 Minecraft Windows 10 Edition,但是我在学校,我自己的电脑只有一部 MacBook Pro 2017。

那为什么不用 Bootcamp 呢?

因为我也不知道为什么,只有无尽的黑屏与 Windows 10 安装向导初始化的画面。我无法开始安装。

而且 Bootcamp 还有其它的缺点,具体可以看 这里

顺便少数派那个教程有点过时了,我在我的新款 MacBook Pro 安装时撞了些坑,所以决定写个新教程,造福人类。

准备材料

  • Windows 10 ISO
  • UNetbootin
  • 8G 以上的 U 盘(建议使用 USB 3.0 的)
  • USB Hub(建议使用 USB 3.0 的)
  • 支持 Windows 的键鼠套装(在安装完整的 Bootcamp 驱动以前,内置键盘和触摸板用不了的)
  • 机智的你

如果你使用的是带 T2 芯片的新款机型,请先根据 官方说明 允许通过外部 USB 设备启动。

我的安装环境

  • 机型:MacBook Pro (13-inch, 2017, Two Thunderbolt 3 ports)
  • 操作系统:macOS 10.13.5 (17F77)
  • 磁盘:256GB,只有 macOS 分区

分出 Windows 分区

假如你打算留下 macOS,请使用这个命令调整 macOS 分区大小:

diskutil apfs resizeContainer disk1 200GB    # 200GB 指你给 macOS 留的分区大小

这些数值可以酌情调整。但是,请确保有足够的剩余空间。

制作 Windows 10 安装盘

下载好 Windows 10 ISO,插上你的 U 盘,然后先格式化一下:

我们把 格式 设置为 MS-DOS (FAT)方案 设置为 主引导记录

然后我们打开 UNetbootin,选择 Diskimage,打开我们准备好的 Windows 10 ISO。下面的 Type 当然选择 USB Drive,然后将 Drive 设置成你要制作安装盘的 U 盘(如果不确定的话,可以把主机上所有其它 U 盘和读卡器什么的都拔掉,这样就只有一个选项了)。

然后点击 OK,耐心等待写入完毕就是了。

在写入完毕后,我们打开 启动转换助理,选择 操作 => 下载 Windows 支持软件,并将保存位置设为我们的安装盘的根目录下。接下来我们会需要的。

下载即将结束时会向你请求权限,这是正常的,直接输入密码确认就行了。

如果你尝试过 Boot Camp 安装

如果你没有尝试过 Boot Camp 安装,请跳过这一节!

直接照着 这篇帖子 里面的方法做就行。

以及你需要先把 SIP 暂时关掉。

开始安装

把你的 U 盘、键盘和鼠标插上你的 USB Hub,并连接 MacBook。

重启你的 MacBook 并按住 Option 键,你会看到有好几个磁盘的选项。按方向键选择 黄色图标的 EFI Boot,然后回车。

然后先按提示一路走下去,然后到了选择磁盘这一步,你会发现没有磁盘可选。这是正常的,我们还需要加载驱动程序。

我们点击 加载驱动程序,再点击 浏览,找到 C:\WindowsSupport\$WinPEDriver$\AppleSSD64,确定。然后点击下一步。

稍后,我们就可以看到我们的磁盘分区了。我们按照正常的方法创建好分区,然后继续一路向前就是了。

安装驱动

当我们进入安装好的 Windows 10 以后,找到你安装 U 盘下的 WindowsSupport\BootCamp 文件夹,运行里面的 setup.exe,安装驱动程序,然后重新启动就是了。

然后就大功告成了,你的内置键盘、触摸板等一系列硬件都可以使用了。

(在我设备上的)已知问题

  • Windows 睡眠时间过长以后,你需要经过完整的开机过程才能还原。
  • 每次返回 macOS,你恐怕都需要按住 Option 键手工选择 macOS 分区。在设置里改 启动磁盘 不管用。
  • 蓝牙工作异常
Horo's avatar

如何可能正确的以大部分人可能会接受的方式提出电脑相关的问题

汝问咱为啥标题起得这么长,那是因为咱不敢保证所有的人都乐于接受这种提问方法啊……

以及似乎能衍生到其它领域?那 …

via these people and places