Recent Posts

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の胡說八道

依云's avatar

HiDPI 配置记录

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

首先,我是用 X11 窗口系统的,不同屏幕分别设置肯定没戏。所以只好让笔记本电脑的屏幕迁就一下我的4K主屏啦,把笔记本屏幕缩放一下。算一下 scale 值:192 / 120 = 1.6。不是整数,会糊,可总比放大两倍的巨大界面要好。

xrandr --output eDP-1 --scale 1.6 --auto --output DP-2 --auto --pos 3072x0 --primary --fb 6912x2160

这里要注意的是,要指定--pos(或者--panning),不然会重叠;要指定--fb,不然鼠标可能会有部分区域去不了。

然后开始设置。本来我是尝试了一下 KDE 的,但因为我将在下一篇文章中写的原因而放弃,回到了 Awesome。不过也不是全无收获。我把 KDE 的配置方案拿过来用了。你想问怎么拿的?我 btrfs 的文件系统,做好快照再 rsync -n 对比一下它动了哪些文件就有了。

首先是 X11 的资源。在~/.Xresources里写上Xft.dpi: 192,然后xrdb -merge ~/.Xresources一下就好了。顺便再xrandr --dpi 192一下,听说有些程序会读这个。

然后是 GTK。GTK 2 就放弃吧,没办法。文字会按设置的 Xft.dpi 放大,图标啥的不会。GTk 3,要设置两个环境变量:

export GDK_SCALE=2 GDK_DPI_SCALE=0.5

前一个是把界面放大,后一个是把文字缩回去,因为文字已经按 Xft.dpi 放大过,不能再放大一次了。

再然后是 Qt。Qt4 早卸载干净了不用管。Qt5 嘛,也不用管。它自己会处理好。有个按不同屏幕缩放的环境变量QT_SCREEN_SCALE_FACTORS,效果跟 Windows 10 差不多的。但是我为了照顾其它程序已经把屏幕给 scale 过了,就不需要设置这个了。你要设置个QT_AUTO_SCREEN_SCALE_FACTOR=0也行,但这个是默认行为。

最后是个别的程序。

Telegram 直接在设置里关掉「默认界面缩放比例」并且设置缩放比例为 300% 就好了。我也不知道为什么,Telegram 默认的字总是很小。之前 120dpi 的时候我要 200% 缩放,现在 192dpi 需要 300% 缩放了。

YouTube,就是那个网站啦。它其实没什么显示上的问题,只是死活不会给我自动选择 1080p 以上的分辨率。经过仔细二分测试之后发现,把火狐的配置文件夹下的storage/default/https+++www.youtube.com目录删掉之后就好了。没发现删掉这个会有其它影响。

mpv 要修改配置文件,加上no-hidpi-window-scale参数,不然会把视频自动放大,4K视频一打开会只能看到四分之一的画面。加上这个参数,默认窗口大小时,一个视频里的像素会对应一个显示器上的像素,不大不小刚刚好。mpv 文档上说这是 OS X 系统上的默认行为,可我这是 Linux 桌面啊,你把别的平台上的习惯搬过来是几个意思?另外我加了个demuxer-readahead-secs = 20选项。我的大文件都在机械硬盘上,4K 码率又比较高,不多预读一点容易卡。

我的 qemu 之前使用的是-display gtk,也坏掉了。窗口那么大,虚拟机只用左下角那里四分之一的空间。spicy 也有问题,会告诉虚拟机只有 1080p。解决方法是 unset GDK_SCALE GDK_DPI_SCALE。它们在放大了自己的界面的同时,把显示的虚拟机的内容也给放大了,所以干脆叫它们别动。也没什么别的影响。

哦还有 Zoom。设置个QT_AUTO_SCREEN_SCALE_FACTOR=1似乎就好了?我试了一下QT_SCREEN_SCALE_FACTORS,会导致很怪异的行为。

以上解决了显示大小的问题,但我发现还有个问题:我的鼠标光标时大时小的……从 KDE 那边弄来几个设置之后就好了,而且主题也更加一致了呢。

首先是设置 xcursor 环境变量:

export XCURSOR_THEME=Vanilla-DMZ XCURSOR_SIZE=36

听说对应的 X 资源大家都不理睬,那我也就不设好了。

然后是 GTK 2 的~/.gtkrc-2.0文件里写上:

gtk-cursor-theme-name = "Vanilla-DMZ"
gtk-cursor-theme-size = 36

再接下来是 GTK 3 的~/.config/gtk-3.0/settings.ini

[Settings]
gtk-cursor-theme-name = Vanilla-DMZ
gtk-cursor-theme-size = 36

然后又没了。天知道为什么 Qt 那边啥都不干就好好的,GTK 却这么麻烦。

啊,你问这些环境变量在哪里设?我给写~/.xprofile里了。不过这还不够。有些 GUI 程序会由用户的 systemd启动(比如我的 Telegram 是由 systemd 启动的,为了在内存用得太多的时候自动重启),有些 GUI 程序会由 D-Bus 激活(比如 gnome-terminal)。这些是和登录会话分开的,所以要手动导入一下。以下是我的 .xprofile 中导入图形界面相关环境变量的部分:

_envs=(
  GDK_SCALE GDK_DPI_SCALE
  XCURSOR_THEME XCURSOR_SIZE
  XMODIFIERS QT_IM_MODULE GTK_IM_MODULE
  LIBVA_DRIVER_NAME GST_VAAPI_ALL_DRIVERS
)
dbus-update-activation-environment "${_envs[@]}"
systemctl --user import-environment "${_envs[@]}"

至于登录界面怎么办,我是在 lightdm 的 display-setup-script 里,跑了跑 xrandr,设置了一下 Xft.dpi 资源。环境变量啥的没动,反正用不上。当然你也可以去改~lightdm/.pam_environment来设环境变量,反正现在 Arch Linux 还是读它的。别的 dm 同理。

依云's avatar

让 QEMU 使用 SPICE 协议

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

缘起

我就是买了个4K显示器,咋这么多事呢……(有两篇文章还在路上)

第一个问题是,我的显卡 vGPU 最高只支持 1920x1200 的分辨率。行吧,我缩放成了吧?嘿嘿,-display gtk 的缩放不会保持比例,我只好算了算最大保持比例的大小,然后窗口切成浮动,再调用命令调整到指定的大小:

sleep 1 && xdotool getactivewindow windowsize 3280 2122

然后还要居中放置一下。多麻烦!

第二个问题是,我想在虚拟机里试试 i3,但是我的按键总是会被外边捕获。Super 键基本上是 Awesome 在用,而 Alt 键会撞上这个 GTK 窗口菜单栏的快捷键。

配置

经过多番尝试和摸索之后,确定了如下的参数:

  -display egl-headless,gl=on,rendernode=/dev/dri/renderD128
  -spice unix,addr=/run/user/1000/qemu/ArchKDE/spice.sock,disable-ticketing
  -device virtio-serial-pci
  -device virtserialport,chardev=spicechannel0,name=com.redhat.spice.0
  -chardev spicevmc,id=spicechannel0,name=vdagent

当然要gl=on啦,不然我怎么玩特效,我还不如回到 vbox 去呢(啊不,我的 vbox 不喜欢 btrfs,经常出错然后只读挂载,所以已经被删掉了)。要指定rendernode,不然它会 fallback 到 llvmpipe,然后还段错误崩掉……这也是我不-display spice-app的原因。

后边三行是从这个 QEMU + Spice with Copy & Paste 抄来的。搜索问题时不小心遇见,然后解决了这个我一直没有处理的问题。SPICE 不但能共享剪贴板,而且还支持 PRIMARY 选择区呢~虚拟机里要安装 spice-vdagent 并启动相应的服务。

然后是客户端的选择。一个很神奇的地方是,virt-viewer 看上去轻量,实际上只是选项少而已。它不光拖进来个 gtk-vnc 依赖,还把 libvirt 都给我带上了……然后 GNOME 的 vinagre,我不知道为啥,它就是连不上我的 spice+unix 地址。哦对了,virt-viewer 直接敲命令调用也是连不上,只能用 xdg-open 才能正常打开。

virt-viewer 有个依赖叫 spice-gtk。我试着 pacman -Ql 了一下,还真找到个 spicy 工具。比 virt-viewer 轻量多了,选项也更为丰富,比如可以选项不 grab 键盘。

一点额外的东西

在群里听说了 virtio-fs 共享方案,听说比 virtio + 9p 更高效。然后我用它成功取代了之前用的 NFS 方案(反正我的 vbox 虚拟机已经被删掉啦)。NFS 的服务也可以卸载啦(开放一堆端口到公网,看着有点怕怕的,虽然是 IPv6 地址不太会被扫到,但知道我的地址的咋办呢)。

virtio-fs 相比 virtio + 9p 的另一个优点是,和 NFS 一样,virtiofsd 是以 root 权限运行的,所以可以写入我的 pacman 缓存。qemu 那个 9p 似乎没有办法。至于启动嘛,用 systemd abstract socket 触发一下就好了。

另外,我使用 GVT-g 和 virtio 输出视频信号时,均遇到了声音在视频画面变化时声音卡顿的情况。一个绕过的办法是,通过设置 PULSE_SERVER 环境变量以及加载 module-native-protocol-tcp 模块,将音频信号直接通过网络发送到宿主机上,一点也不卡!

RecursiveG's avatar

IPsec 配置备忘 Part8 - 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

我的测试环境是一台 iOS 12.4.9 的 iPad。由于在测试的时候发现 iOS 的坑实在太多,以及不同版本的 iOS 的行为都不太一样,如果你碰到了我没碰到的坑我只能祝你好运(<ゝω・)☆

坑坑坑

由于本 Part 是基于 Part6 的,所以我们先来列举一下会需要我们做调整的 iOS 的坑(大部分在 strongSwan 的文档里已经提到过了):

  1. iOS 的 local_id 和 remote_id 全部都是 FQDN 类型,意味着我们需要按照 Part7 的说明给证书加上dns_name的 SAN。
  2. iOS 在导入客户端证书的时候只允许 CN/SAN 二选一,否则不能导入。所以 iOS 客户端证书不能有 CN。
  3. iOS 不允许 p12 证书使用空密码。
  4. iOS 12 还不支持 ed25519,所以我们需要改用其他算法。
  5. iOS 的 mobileconfig 全是坑。
  6. iOS 需要在配置描述文件显式指定 CA 的 CN 才会发送 CERTREQ。
  7. 你需要在服务端配置文件的 pool 里指定一个 DNS,否则 iOS 连上后无法上网。

基本流程是:生成密钥和证书;生成 iOS 的mobileconfig配置描述文件;想办法把这个文件安装到 iOS 设备上;最后尝试连接。由于 iOS 的配置文件比 Android 的复杂许多,所以我写了个 Python 脚本来负责生成。

依云's avatar

Python 小版本升级是怎么 break 已有项目的

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

近日,Arch Linux 终于开始升级到 Python 3.9 了。很多人认为 Python 小版本升级容易搞坏兼容性,导致项目无法在新的版本上运行。事实是这样的吗?我正好借着 Arch Linux 升级 3.9 的机会,分析一下打包过程中失败的项目到底是出了什么事。

需要说明的是,我仅大致地分析了打包的报错信息,不排除分析出错,或者有额外的问题没有被看见的情况。另外我是在打包过程中随机(arbitrarily)取样,并且排除了我不能确定问题所在的案例。

以下项目测试失败是和 Python 3.9 相关的。排序是按照项目开发者的无辜程度排序的。也就是说,排序越靠前的,我越是认为项目开发者是无辜的;而像「硬编码 Python 3.9 为未发布的版本」这种完全不 future-proof 的做法,现在坏掉了真是自找的。

其中,使用的公开特性变化导致问题的有 3 个,调用私有属性或者方法、依赖非正式的文本信息的有 11 个,使用已废弃的特性的有 8 个,使用已被修复的 bug 的有 2 个,使用未来注定会出问题的信息的有 3 个。总共 27 个。

  • freecad: PyTypeObject.tp_print 没了
  • python-llfuse: PyTypeObject.tp_print 没了
  • linux-tools: PyMODINIT_FUNC 的变化导致了警告,然后被转为错误
  • python-blist: _PyObject_GC_IS_TRACKED不再在第三方库中可用(被公开 API 取代)
  • python-pyflakes: Python 语法解析报告的列位置似乎不太对,应该是受新的语法解析器的影响
  • python-pylint: Python 语法解析报告的列位置似乎不太对,应该是受新的语法解析器的影响
  • python-typing_inspect: 使用私有名称 typing._GenericAlias,结果新版本变成了 typing._SpecialGenericAlias
  • python-sphinx-autodoc-typehints: 看上去是类型标注相关的内部更改移除了 typing.Dict.__parameters__ 属性造成的
  • python-fastnumbers: 看上去是内部函数 _Py_dg_stdnan 不再被默认包含导致的问题
  • python-libcst: 类型标注相关的内部更改移除了 typing.Dict.__args__ 属性造成的
  • monkeytype: typing.Dict 的类型从 type 变成了 typing._SpecialGenericAlias
  • scrapy: 由于 typing.Optional[str] 的字符串表示由 typing.Union[str, NoneType] 变成了 typing.Optional[str] 导致 mitmproxy 运行出错,进而使得 scrapy 的测试失败
  • python-billiard: 调用的私有方法 _posixsubprocess.fork_exec 参数发生了变化
  • python-pytest-benchmark: argparse 的帮助信息格式有优化
  • python-opentracing: 自 3.7 起废弃的 asyncio.Task.current_task 被移除
  • python-engineio: 自 3.7 起废弃的 asyncio.Task.all_tasks 被移除
  • impacket: 自 3.2 起废弃的 array.array.tostring() 被移除
  • python-pybtex: 自 3.2 起废弃的 xml.etree.ElementTree.Element.getchildren 被移除
  • python-jsonpickle: 自 3.1 起废弃的 base64.decodestring 被移除
  • python-ioflo: 自 3.1 起废弃的 json.loads() 参数 encoding 被移除
  • routersploit: 自 Python 3 起废弃的 threading.Thread.isAlive 终于被移除了
  • python-socketpool: 自 Python 3 起废弃的 threading.Thread.isAlive 终于被移除了
  • python-furl: Python 3.9 修正了一处 URL 解析 bug
  • python-stem: Python 3.9 移除了错误的 unittest.mock.__version__
  • python-natsort: Python 的 Unicode 支持更新到了 13.0.0 版本,CHORASMIAN NUMBER ONE 字符被判定为数字,但是测试代码不认识,认为程序出错
  • python-pony: 对新版本的 Python 报不支持的错误
  • python-dephell-pythons: 硬编码 Python 3.9 为未发布的版本,但现在 3.9 已经发布了

而以下项目的测试失败与 Python 3.9 没有直接关系,共 26 个。其中与 Python 生态有关的有 18 个,与其它项目有关的有 4 个,依赖外部信息的有 3 个,包括一个特别搞笑的依赖夏令时是否生效的。

  • python-eventlet: 调用的 dnspython 私有方法已不存在;DNS 解析超时
  • python-markdown2: 语法高亮的结果有少许变化,不符合预期。推测是 pygments 新版本的变化
  • python-flake8-typing-imports: 似乎是 flake8 能够检测到更多的问题了
  • python-babel: 使用了已废弃的特性,测试被 pytest 拒绝
  • python-pygal: pytest 6.1.0 移除了 Metafunc 的 funcargnames 属性
  • python-flask-gravatar: 使用了已废弃的特性,测试被 pytest 拒绝
  • python-pytest-relaxed: 使用了已废弃的特性,测试被 pytest 拒绝
  • python-pytest-randomly 使用了已废弃的特性,测试被 pytest 拒绝
  • python-deprecated: 测试所预期的警告文本信息已经发生变化
  • python-dbus-signature-pyparsing: 执行时间超过了测试设定的 200ms 时限
  • python-tinycss2: flake8 风格检查未通过
  • python-pytest-runner: black 风格检查未通过
  • python-portend: black 风格检查未通过
  • python-aiohttp: @coroutine 的 DeprecationWarning 被视作错误
  • python-poetry: poetry-core 的一项数据由 dict 改为 OrderedDict,使得输出顺序与测试预期的不一致
  • python-isort: 将使用旧版本 isort 的外部项目的 import 排序视为正确,然后它还真出错了
  • python-cachecontrol: Python 2.7 相关
  • python-zc.lockfile: 测试代码把 Python 3 代码喂给了 Python 2.7。可能是该库已经不支持 2.7 了
  • python-occ-core: 依赖 OpenCASCADE 的版本更新,不被支持
  • protobuf: C 整型比较因表示范围问题而恒为假,警告转错误。是因为新版本的 gcc 比较聪明么?
  • gnome-passwordsafe: 构建系统发现有依赖缺失
  • io: C 代码引用了不存在的系统头文件
  • ceph: C++ 相关问题
  • python-distlib: 调用远程 XML-RPC 太多被限制导致预期的数据与实际错位
  • python-requests-toolbelt: 测试所需要的 HTTP 资源 404 了
  • postgresql: 夏令时结束,导致实际时区与预期对不上。「所以冬天就不要滚包啦,冬天要冬眠!」

所以在这些升级 Python 3.9 的项目中,不兼容 Python 3.9 仅仅只占一半,其中又有一半多属于「总有一天会坏掉」的类型(一大半属于「不听话」,使用没有明确文档、预期为私有的特性,少数尝试当预言家但是失败了)。最后剩下的,再一大半是使用了至少两个版本前已经说了要废弃的特性,只有三个莫名地发现自己真的被 Python 坑了,还都是 C API 部分的。

所以我对我自己的脚本顺利升级到 Python 3.9 非常有信心呢。可能有些老代码使用了已经废弃的特性,所以我也设置了环境变量 PYTHONWARNINGS=default,ignore::ResourceWarning 以便及时得到提示。

哦对了,Arch Linux 中受 Python 3.9 升级影响需要更新的软件包共有2077个,绝大部分我都没见着失败的。目前从开始升级到现在已经过去六天,还剩最后40个失败了的包。

'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
Jixun's avatar

快捷方式脚本

重装系统后如果没有备份桌面,那么快捷方式就会不见了。

同时,Windows 的检索对开始菜单目录下的快捷方式应该有加速,有时候会搜索不到桌面。

检索快捷方式

做了个简单的脚本快速添加快捷方式到开始菜单里。

Set objShell = Wscript.CreateObject("Wscript.Shell") Set objFSO = CreateObject("Scripting.FileSystemObject") Set objFile = objFSO.GetFile(Wscript.ScriptFullName) strFolder = objFSO.GetParentFolderName(objFile) strDesktop = objShell.SpecialFolders("Desktop") strStartMenu = objShell.SpecialFolders("Programs") strStartMenuGames = strStartMenu & "\Games" Sub Mkdir(dir) If Not objFSO.FolderExists(dir) Then objFSO.CreateFolder dir End If End Sub Function StrFallback(a, b) If a <> "" Then StrFallback = a Else StrFallback = b End If End Function Sub CreateShortcutWithIcon(root, dir, exe, name, desc, icon) strProgramFolder = strFolder & "\" & dir strProgramPath = strProgramFolder & "\" & exe Mkdir root Set lnk = objShell.CreateShortcut(root & "\" & name & ".lnk") lnk.IconLocation = StrFallback(icon, strProgramPath) lnk.Description = StrFallback(desc, name) lnk.TargetPath = strProgramPath lnk.WorkingDirectory = strProgramFolder lnk.Save Set lnk = Nothing End Sub Sub CreateShortcut(root, dir, exe, name, desc) CreateShortcutWithIcon root, dir, exe, name, desc, "" End Sub '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''''''''''''''''''''''''''''' 快捷方式代码放在下面 ''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' 建立 Steam 快捷方式到桌面 + 开始菜单 CreateShortcut strDesktop, "Steam", "steam.exe", "Steam", "Steam 启动器" CreateShortcut strStartMenuGames, "Steam", "steam.exe", "Steam", "Steam 启动器" ' 建立 osu! 快捷方式 CreateShortcut strDesktop, "osu!", "osu!.exe", "osu!", "osu! 是一个节奏游戏" CreateShortcut strStartMenuGames, "osu!", "osu!.exe", "osu!", "osu! 是一个节奏游戏" ' 建立其他快捷方式 CreateShortcut "目标目录", "子目录名", "可执行文件", "快捷方式名", "描述" CreateShortcutWithIcon "目标目录", "子目录名", "可执行文件", "快捷方式名", "描述", "图标路径"

比较适合经常重装的情况。

快捷方式脚本最先出现在Jixun 项目集

'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 立得……)。如果各位有想看的配置场景欢迎留言告诉我,会考虑先写。

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 也是存在的。我也许会在未来的某一期讲。

依云's avatar

让 Arch Linux 系统和最新的镜像同步,从最快的镜像下载

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

Arch Linux 就是要追新!要追新自然要选择一个更新及时的软件仓库镜像啦,比如国内的 TUNA、USTC 同步都很及时。但是呢,这俩难兄难弟最近一段时间有些吃不消了,导致下载包的时候很慢,甚至超时失败,使用体验真糟糕。如果直接用上游镜像,比如 pkgbuild.com,漂洋过海的,也挺慢的。

而国内另一些镜像,比如网易腾讯云阿里云华为云,他们要么有 CDN,要么线路很好,下载速度飞快。但是呢,他们基本上每天才同步一次,阿里云还时不时连续数天都没能同步成功,这让喜欢追新的 Arch Linux 用户多不舒服呀。当群里的小伙伴们都用上了最新版本的软件,体会到了让人心痒痒的新特性和 bug 时,你 -Syu 却是「今日无事可做」,真是扫兴呢。

和最新的镜像同步,从最快的镜像下载,真的不可兼得吗?

非也。只需要稍微配置一下,用上我的 pacsync 脚本,就可以啦~

配置方式是,为 /etc/pacman.d 下的镜像列表文件创建一个.sync后缀的同名文件,里边指定用于同步的镜像,而不带.sync后缀的文件里按优先级列出多个镜像。pacman 在下载文件时,会按顺序依次尝试列出的镜像,如果遇到更新不及时 404 的时候,就会尝试另一个。这样,可以仅在下载快的镜像里还没有需要的包文件时,才转而从比较慢的镜像下载。

而需要同步 pacman 数据库的时候,使用pacsync脚本取代pacman -Sy。脚本会使用 bind mount 用.sync文件取代不.sync的版本,就能同步到最新的数据库了。原来的pacman -Syu命令要拆开来用,先pacsyncpacman -Su了。

脚本里使用了单独的挂载空间并且将挂载改为了私有,所以并不会影响到外边。

依云's avatar

tar 归档的权限问题

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

一次系统升级之后,我的许多 Python 程序突然开始报错:

[...]
  File "/usr/lib/python3.8/site-packages/pkg_resources/__init__.py", line 2762, in _get_metadata
    for line in self.get_metadata_lines(name):
  File "/usr/lib/python3.8/site-packages/pkg_resources/__init__.py", line 1415, in get_metadata_lines
    return yield_lines(self.get_metadata(name))
  File "/usr/lib/python3.8/site-packages/pkg_resources/__init__.py", line 1405, in get_metadata
    value = self._get(path)
  File "/usr/lib/python3.8/site-packages/pkg_resources/__init__.py", line 1609, in _get
    with open(path, 'rb') as stream:
PermissionError: [Errno 13] Permission denied: '/usr/lib/python3.8/site-packages/Telethon-1.17.4-py3.8.egg-info/PKG-INFO'

WTF 滚坏了!立即回滚!

回滚完之后,我开始调查这个事件——因为 [archlinuxcn] 的这个包是我管的呀。而且我记得之前也遇到过一次类似的情况,当时没有深究。

检查一下软件包里的文件的权限:

>>> tar tvf python-telethon-1.17.4-1-any.pkg.tar.zst | grep PKG-INFO
-rw------- root/root      3659 2020-10-24 10:05 usr/lib/python3.8/site-packages/Telethon-1.17.4-py3.8.egg-info/PKG-INFO
>>> tar tvf python-telethon-1.17.4-1-any.pkg.tar.zst | grep -- ----
-rw------- root/root      3659 2020-10-24 10:05 usr/lib/python3.8/site-packages/Telethon-1.17.4-py3.8.egg-info/PKG-INFO
-rw------- root/root     12078 2020-10-24 10:05 usr/lib/python3.8/site-packages/Telethon-1.17.4-py3.8.egg-info/SOURCES.txt
-rw------- root/root         1 2020-10-24 10:05 usr/lib/python3.8/site-packages/Telethon-1.17.4-py3.8.egg-info/dependency_links.txt
-rw------- root/root        27 2020-10-24 10:05 usr/lib/python3.8/site-packages/Telethon-1.17.4-py3.8.egg-info/requires.txt
-rw------- root/root        15 2020-10-24 10:05 usr/lib/python3.8/site-packages/Telethon-1.17.4-py3.8.egg-info/top_level.txt

好奇怪,Telethon 这些包信息文件怎么只让 root 读了呢?

从 PyPI 上下载 Telethon 的原始 tar 归档回来看看,发现最近几个版本里,文件权限全部只有自己可以读(-rw-------),而所有者是 u0_a167/10167。开发者突然在 Android 系统上打包了呢……安装的时候,部分文件的权限被保留了下来(Arch Linux 打包时强烈反对使用 root 权限执行,因此我用 devtools 打包,解包部分自然是普通用户操作的,所有者无法被保留)。

然后我又看了一下之前的版本,哦豁,所有者成开发者的 id 了,但是有三个版本的 pyc 文件,还有好几个 pyc 文件都是 -rwxrwxrwx。大概系统上的低权限用户可以去改改,然后看谁跑 Telegram 机器人就拿谁的权限?

经过跟开发者的讨论,最终干掉了 pyc 文件,也不在 Android 上打包了。777 权限问题还待解决。不过我更在意的是,为什么会发生这种状况呢?setuptools 干嘛不修一修呢?别的工具创建的用于发布的 tar 归档会不会有类似的问题呢?

结果找了找,发现 setuptools 前年就有人报告这个问题,但是并没有解决。行吧,我打包时统一修正一下权限好了……

下一个 GitHub 生成的 tar 归档看看?咦,-rw-rw-r-- root/root,是处理过了么?啊对,git archive 生成的包是怎么样的?去试了试,原来一样的啊。看来 git 想到了这个问题并且处理了,只是 002 的 umask 有点意外。

Arch Linux 为了普通用户打出文件为 root 所有的 tar 归档使用了 fakeroot,那么 git 是怎么实现的呢?翻了翻代码,git 是自己生成 tar 文件的,写死了所有者是 root/root,但是权限位还是有专门的 umask,默认是 002。可以配置,比如git config --global tar.umask user一下,就会取当前 umask 作为 tar 归档里文件的 umask 了。

至于传统的 GNU autotools 构建系统创建的 tar 归档,我也创建了一个看了一下,并没有特殊处理,跟手动跑 tar 一样。

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

编写 Minecraft 玩家用小康文本编辑器的努力

(不支持移动版浏览器)

这个编辑器在 这里,大家现在就可以使用了。

虽然说这玩意确实还没做到令我满意的程度,但是我把它写出来了,并达到了勉强可用的程度。

不过开发这玩意,我算是明白 HTML 的富文本编辑器(虽说我这是「小康文本编辑器」,因为屏蔽掉了所有 Minecraft 不支持的样式)有多难开发了。

顺便开发 Web 富文本编辑器的前端工程师们,你们都是好样的!

为什么要造轮子?

Minecraft 原生就支持那么几种样式和颜色,所以一开始记忆样式代码也不是太困难的事情。但是在 Minecraft 1.16,我们有了 RGB 文本支持;而 EssentialX(一种被各大服务器广泛使用的辅助性插件)也积极跟进支持,追加了玩家使用 RGB 颜色的样式代码;但要在脑海里演算 RGB 颜色数值发展的具体变化,感觉还是有点困难,况且我还希望在游戏中实现彩色渐变文本等酷炫的特效。

那么,头脑一热的我决定,干脆自己写个编辑器好了,顺便练练手。

contenteditable

这玩意 其实是个相当历史悠久的东西,IE 5.5 就支持了,而且设计上就是用来开发富文本编辑器的。

在前期开发阶段,我感觉要把编辑区的内容转换为 EssentialX 文本格式应该不是太困难的事情。我的做法是这样的:

  1. 读取 DOM 结构
  2. 获取各 HTML 元素计算过后的 CSS 样式
  3. 内部维护一个样式树(抽象的数据结构),记载每一段文本的样式。例如下面这段文本:

凤凰卷是一种奇怪的点心。

它的 HTML 代码是:

<b>凤凰卷</b>是一种<i>奇怪的</i>点心。

通过计算得出的样式树:

char color bold italic underline strickthrough
凤凰卷 #000000 true false false false
是一种 #000000 false false false false
奇怪的 #000000 false true false false
点心。 #000000 false false false false

然后,我依据这个数据结构,就可以非常轻松的计算出对应的 EssX 文本代码:

&l凤凰卷&r是一种&o奇怪的&r点心。

事情到这里,还是很简单的,毕竟富文本编辑器的操作,本质上不就是操作 HTML 结构嘛(虽然是这样)。

拉胯的 execCommand

这玩意 其实设计上是与 HTML contenteditable 配合使用的,目的就是用来在页面编辑中给选择的内容设置不同的样式。

于是我兴高采烈的用上了,然后发现一些问题:

  • MDN 显示,这玩意过时了。
  • 不同浏览器生成的 HTML 代码不一致,添加的标签五花八门,甚至连早已淘汰的 <font> 标签都出来了。不过还好对于我的解析方案不是太大的问题……
  • 不同浏览器的行为存在差异。例如给文本同时添加下划线和删除线,Chrome 浏览器肯定会把你选择的这段文本旁边的文本的下划线 / 删除线样式搞乱,但 Firefox 浏览器就不存在这个问题。(顺便最后的不完美之处还是跟下划线和删除线有关)

其实如果说 execCommand 这玩意,市面上倒是还有一大票编辑器还在用,而且大概浏览器厂商也不会那么轻易的干掉古董的 API(说的就是你,document.all)。不过考虑到下划线和删除线的问题,我还是决定:换掉它,避免未来更麻烦的事情发生。

用现代的 API 来解决吧!

我重新整理了一下思路,发现我需要的样式操作工作流其实是这样的:

  1. 将用户选择的文本片断剪下来
  2. 分析剪下来的片段的样式,并生成样式树
  3. 直接对样式树进行操作
  4. 从样式树生成相应的 HTML
  5. 将生成的 HTML 追加到文本被剪切的地方

我选择直接操作样式树的原因是因为我只关心最终呈现的效果,这样就可以保证 HTML 元素的低嵌套性(指一个 <span> 标签中包含了所有应有的样式,而不是一层套一层的标签),提升处理效率和鲁棒性。

那么,首先在进行一个样式操作以前,需要把选区剪切下来:

/**
 * 剪切用户选区
 * @returns 剪切下来的用户选区的文本数据结构
 */
cutSelection(): StringItem[] {
    // 获取用户选择的文本范围
    const selection = document.getSelection() as Selection;
    // 如果用户选择了至少一段文本,就取第一段被选中的文本(目前只有 FireFox 浏览器支持一次性选择多个选区?)
    if (selection.rangeCount > 0) {
        const range = selection.getRangeAt(0);
        // 把选区剪切为 HTML 片段
        const extracted = range.extractContents();
        // 进行解析,返回解析得到的样式树
        return this.parseFromFragment(extracted, parent || undefined);
    }
    return [];
}

然后拿到样式树以后,再进行步骤 3-5 就可以了。

但是……接下来的不可靠因素出现在剪下来的 HTML 片段(DocumentFragment)。当用户选择一段文本,有这么几种特别需要注意的情况:

  1. 用户只选中了一个元素里的文本,则整个片断里只有一个文本节点(Node)。
<b>Phoenix Roll</b> is <i>awesome</i>
   | ----+--- |
         |
         +-------------------- [0] [Text Node] Phoenix Roll
  1. 用户选中了嵌套在多层元素中的文本,则:
<u><b>Phoenix Roll</b> is <i>awesome</i></u>
          | ----+------ |
                |
                +-------------------- [0] [Element Node] <b>nix Roll</b>
                                      [1] [Text Node]     is

没错,外面一层的 <u>(下划线)标签就被完全无视了。虽说这样的操作其实合情合理,毕竟浏览器哪里知道你想要的根元素是哪个啊。

下划线和删除线

我一开始的考虑是:让顶层的 CSS 样式直接覆盖父级元素的 CSS 样式,这样不仅处理容易,而且展示效果也会是正确的。但是,下划线和删除线样式的处理问题又向我泼了一盆冷水。

CSS 的下划线和删除线的样式继承偏偏和别的不!一!样!

简而言之,CSS 的 text-decoration 实际渲染样式是从父级元素向下叠加,就像这样:

<s>
    <!-- 追加了删除线样式 -->
    <u>
        <!-- 追加了下划线线样式 -->
        <span style="text-decoration: none">
            <!--
            期望效果:这段文字什么样式都没有
            实际效果:这段文字有下划线和删除线样式
            -->
            为什么我的下划线和删除线没有被消除?
        </span>
    </u>
</s>

那么,如果要正确的获取到一段文本的下划线和删除线样式,就只有向下递归搜索了:

/**
 * 检查某个元素是否会渲染出下划线或删除线样式
 * @param el 要开始搜索的节点
 * @param root 根节点(停止搜索的地方)
 * @param name 搜索的关键词
 * @returns 是否会渲染
 */
static searchLineStyle(el: HTMLElement, root: HTMLElement, name: string): boolean {
    // 如果被搜索的节点没有有效的根节点,停止搜索
    if (el === null) {
        return false;
    }
    // 获取该元素实际计算出的样式。直接通过 `el.style` 未必能够获取到实际计算出的样式。
    const styles = window.getComputedStyle(el);
    // 如果找到了搜索的关键词,停止搜索,返回搜索成功
    if (styles.textDecorationLine.includes(name)) {
        return true;
    }
    // 如果要开始搜索的节点已经是根节点,停止搜索
    if (el.isEqualNode(root)) {
        return false;
    }
    // 递归,继续搜索上一层元素
    return TextEditor.searchLineStyle(el.parentNode as HTMLElement, root, name);
}

至于编辑框里的文本,我写了一个函数,在编辑框失焦以后进行自动「标准化操作」:

  1. 获取编辑框里的 HTML
  2. 解析样式树
  3. 清空编辑框,用从样式树渲染得到的 HTML 替换原始内容

渲染完成的 HTML 为扁平的,意味着不会出现任何嵌套元素。为了避免出现「用户只选中了一个元素里的文本」带来的麻烦,我想了个办法,强迫浏览器每次剪切出的文档片段首层只有元素:把每一个字单独放在一个 <span> 里。以第一个例子的文本为例,最后渲染出的 HTML 是这样的:

<span style="color: rgb(255, 255, 255); text-decoration-color: rgb(255, 255, 255); font-weight: 700;">凤</span>
<span style="color: rgb(255, 255, 255); text-decoration-color: rgb(255, 255, 255); font-weight: 700;">凰</span>
<span style="color: rgb(255, 255, 255); text-decoration-color: rgb(255, 255, 255); font-weight: 700;">卷</span>
<span style="color: rgb(255, 255, 255); text-decoration-color: rgb(255, 255, 255);">是</span>
<span style="color: rgb(255, 255, 255); text-decoration-color: rgb(255, 255, 255);">一</span>
<span style="color: rgb(255, 255, 255); text-decoration-color: rgb(255, 255, 255);">种</span>
<span style="color: rgb(255, 255, 255); text-decoration-color: rgb(255, 255, 255); font-style: italic;">奇</span>
<span style="color: rgb(255, 255, 255); text-decoration-color: rgb(255, 255, 255); font-style: italic;">怪</span>
<span style="color: rgb(255, 255, 255); text-decoration-color: rgb(255, 255, 255); font-style: italic;">的</span>
<span style="color: rgb(255, 255, 255); text-decoration-color: rgb(255, 255, 255);">点</span>
<span style="color: rgb(255, 255, 255); text-decoration-color: rgb(255, 255, 255);">心</span>
<span style="color: rgb(255, 255, 255); text-decoration-color: rgb(255, 255, 255);">。</span>

(实际上各个 <span> 之间并不包含空格或换行,因为行内元素之间的空格/换行在浏览器中会被渲染为一个空格。)

那如果用户只选择了一个字怎么办?对于这种情况,我会读取和操作它的父级元素的样式。

不过,这种情况仅适用于对编辑框内已有文本进行操作的情况。如果用户一直输入文本,没有让编辑框失去焦点,然后选中了一段特定的文本并试图添加/删除样式,编辑器就崩坏了。

对于这种情况,我又补充了一些比较难看的 hack,但是目前并没有在本质上解决这问题。所以这就是为什么我提醒大家输入完文本以后先点一下编辑器外面了(

更新:现在,每当你应用一个样式以后,编辑器就会自动失焦并优化 HTML 结构,所以这种不可靠情况应该是暂且这么解决了。

结论

富文本编辑器是一种很让用户和开发者难过的东西,即使我降低标准,屏蔽除 Minecraft 支持的所有特殊样式,我依然没有把它做到令我完美的程度;至少目前而言,这是让我感到很遗憾的事情了。

这告诉我们:

  • 作为合格的 Minecraft 玩家,熟练背诵样式代码和一大堆常用颜色还是很重要的
  • 还是不要随便碰富文本编辑器坑了

就酱。

'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 更新)

为什么?

最近我想玩 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

如何可能正确的以大部分人可能会接受的方式提出电脑相关的问题

汝问咱为啥标题起得这么长,那是因为咱不敢保证所有的人都乐于接受这种提问方法啊……

以及似乎能衍生到其它领域?那就靠汝自己斟酌了。

本文参考了下面几篇文章的观点,某些文章可能正在经常的被提起。

  • 提问的智慧,原文作者 Eric S. Raymond,以开放源代码运动(不是自由软件运动,这个的领导者是 Richard Stallman)的提出者和主要领导者为人所知的黑客。本指南将教你如何正确的提问以获得你满意的答案。
  • 如何有效的报告 Bug,以程序员的视角阐述如何提交一份足够准确的 Bug 报告
  • X-Y 问题,一种常见的令人疑惑的提问方式,至于为啥令人疑惑嘛……
  • 真的,再这样提问就没人理你了,以提问的智慧的方法提出不一定是电脑相关的问题的方法,大概吧。

提问真的有那么多讲究的地方嘛?

大多数时候如此,因为有一个大前提:

“我们(在很大程度上)是自愿的,从繁忙的生活中抽出时间来解答疑惑,而且时常被提问淹没。所以我们无情的滤掉一些话题,特别是拋弃那些看起来像失败者的家伙,以便更高效的利用时间来回答赢家(winner)的问题。”

大多数人其实都是出于各种志愿目的回答来自不知道何处的提问的,除非……(“我本来想这样拒绝他的,但是他给的钱实在是太多了……”)

所以 …

Jixun's avatar

血污:夜之仪式 – 7 项修改器

测试于 GOG 的 Patch 1.10 (2020.05.07) 版本,Steam 版本可能不支援。在 GOG 购买

《血污:夜之仪式(Bloodstained: Ritual of the Night)》的封面图

修改器项目

CE 表内容

修改功能都做成了开关类型,在左侧的方框里勾上即可启用,取消勾选则还原。

  • HP 相关
    • 一拳超人:双方承受一次伤害后即死(剧情锁血除外)。
    • 无敌:顾名思义,免疫伤害。
  • 蓝条不掉:使用技能的时候,蓝条(MP)不会减少。
  • 商店白嫖:在商店购买的时候不消耗金币。
  • 道具无消耗:使用道具时不消耗道具。
  • 无限跳:未降落时可以一直跳。速降会失效(跳+↓)。
        获得二段跳能力后可以下降的时候也跳。
        部分特殊游戏模式下无效。
  • 调试信息:调试用的一些信息。并没有什么实际用途。
关于一拳超人修改项目(有剧透)

如果需要打真实结局(True Ending)的话,那么在打吉贝鲁(Gebel)的时候需要关闭这一项目。


下载

关于 Cheat Engine 修改器表

※ 你需要安装 Cheat Engine 来开启修改器表文件(.ct)。
  Cheat Engine 是一个开源的游戏作弊软件,请不要将其用于多人对战游戏。


演示动画

击杀路上的小怪 我起了,一枪秒了,有什么好说的(剧透注意)
初见直接秒杀吉贝鲁Gebel,喜提 BE 一枚。

血污:夜之仪式 – 7 项修改器最先出现在Jixun 项目集

's avatar

为什么大家都在安利这一样东西?

大概无数次我在各大群组里(看见别人)求某种东西的推荐,然后群友们就异口同声的说:「XXX(指同一件东西)不香吗?」

但是这样的安利反而让我感觉不安,因为:

  • 一种东西肯定有它自己的优缺点,但是在那些群友的口中,给人一种 XXX 非常完美的错觉。
    真的,跑分不能说明一切。
  • 安利这种东西的群友中,大概率有相当一部分是它的 fanboy,然后如果你提出不太一样的安利,大概会跟你争个面红耳赤,甚至引起严重的不愉快。
    好吧,我大概是已经屈服于这种「政治正确」了。
  • 有的群友可能只是云用户,在瞎起哄而已。

所以为什么通常情况下,我越来越不想在群聊中为这种事情浪费时间了。我宁可自己问问 Google 娘。

's avatar

Dream Diary - 7,8

#2019

她站在跑道上,望着晚霞点缀着的海面。

我远远地望着她,揣摩着。她到底在看些什么,又在想些什么呢。是把海面看作是浩渺的宇宙,粼粼的波光当作是将抵的舰队?抑或是遥望海的另一端的本土,思念着许久不见的家人……和恋人呢?

再次遇到她,是在来到这艘航母之后的事了。当然我没有大模大样地问她在来这之前是否有恋人,以免打草惊蛇。不过就我的推断,开朗积极如她,赢得一段感情应当是不在话下。

一阵晚风袭来,我不禁打了个寒颤。她不冷么。不过即便如此,她依旧一动不动地站在那里,但不知为何,看起来更加遥远了。

这次,我没有跟她说上话。

2018年,未知外星文明入侵。

2020年,人类灭绝。

#2010

星期六的下午。

老实说,我不是那么讨厌学习,但是我也不是那么喜欢课外班。考试本应该是比较受到同等教育的学生的学习成果的行为,课外班、补习班的存在打破了这一平衡,也打破了学生们投入到素质教育的时间的上限。通过放假时间上课来获取更加优秀的成绩,我认为这是一种恶性竞争。

好事是这种恶性竞争几年后就会被明令禁止。我不禁嫉妒起未来的小弟弟小妹妹们,他们可以傻乎乎地在这烈日之下自由地奔跑嬉戏、中暑晕倒。我摇了摇头,摆脱开这一想法。

10 年后的日子像鬼魂一样,曾时不时在我眼前出现。那段时间,我感觉自己像失去了灵魂的躯壳一样,浑浑噩噩,终日不知所措。对未来一无所知的人们反而成了我羡慕的对象。那种感觉过了一个月才渐渐消退。不如说,我学会了转移焦点。取而代之的是及时行乐的想法,与其忧虑注定到来的末日,还不如珍惜当下,多享受一番。

按照这个逻辑,我现在应该是在室内一边吹着空调,一边打着游戏的。我之所以冒着烈日来参加这个课外班,一个原因是家里没有游戏可以打,另一个原因则是这里有她在。

她——连雪是我的小学同学。她平易近人,虽然有点别扭,容貌——按照小学生的标准——算是不错的,而且成绩向来优秀。在除了成绩,就几乎没有什么好比的小学生眼里,她自然而然就成为了憧憬的对象,还是个小屁孩的我当然也包括在内。我的成绩?现在的话,算是不错啦。

闲话休提。可能是觉得难以接近的原因吧,虽然是同学,小时候的我却没怎么和她有过交集。对此我有那么一丁点,那么一丁点后悔:跟她的关系要是再好一点,就好了。不过对于过去的自己而言只可远观的她,对于现在的我来说,是不是就是容易接近的对象了呢?抱着这样的希望,我想着至少圆一下过去的遗憾,就这样来到了课外班所在的大楼。

这是一栋写字楼,接待处的大姐姐看到我脖子上挂着的名牌,便没有说什么。教室在6楼——我走进电梯,按下按钮。当门将要关闭的时候,我看到另外一个挂着名牌的身影正向电梯这里跑来。是她。我的心跳快了一拍,连忙按下开门按钮。她跑了进来,看到了我,便转向了电梯门,没有说话——。我从面板处退了一步,留出空间。巧也不巧,一个男人在电梯门再次关上之前,也跟了进来。男人按了5楼。

我瞥了她一眼,她像是在沉思,没有注意到我。5楼到了,男人走了出去,她突然也跟着走了出去。我叫住了她。“教室在6楼!”并按住开门键。她张望了一圈,听到我出声喊她,又走了回来。电梯门关上了。“走神了。”她小声说了一句。然后就没有再说话了,像是一副不高兴的样子,可能是因为出丑的缘故吧。


下课后。看着一个人收拾书包的她,我不知从哪里涌上了勇气。我追上了她,问道,“一起回去吗?”

毕竟有一段是顺路,我心里在给自己找借口。

她瞅了我一眼。“随便。”漫不经心地回答道。

我们走在大楼和行道树的阴影之间。热气让我呼吸困难,知了在汽车的呼啸声中肆意聒噪。我莫名地想吃冰淇淋。香草味的大杯装。

“好热啊。”我像是在对自己说。她没有回应,像不觉得热似的。

一个拐弯之后,是一个长长的下坡。路面被太阳晒得发热,路两边稀疏地种着树, 在人行道上洒下零零落落的树荫。路上人影稀疏, 偶有汽车经过。我们一边聊着关于课外班的话题一边下坡。

下了坡,穿过一个小公园。公园里没有人。小公园没有滑梯和秋千,不过有一个沙坑。一座城堡矗立在那里。我下意识地走到沙城堡前。我突然有一种奇怪的感觉:这个沙堡将要融化,像初春的雪一样,变回沙子,落进池里。魔法的时间就要结束了。

连雪走在前面, 我跟在后面。快到她家门口的时候,她停下脚步,转过身来。

“今天过得很愉快。”她说道,脸上露出笑容。不像是平常的她的笑容。

“我也——”

钝器打击的声音。

我的意识就此中断。

17windy's avatar

[8月16日更新P2]17Windy的七日杀A19原创MOD-[近战包]+[远程包] 稳定版

注意:不要光看数值面板,很多武器都有很多数据显示不正确或者没有显示,看小书图标的文本说明!!!

偃月刀用捅的我也觉得很难受,不过七日杀官方就这么几个双手动作,其他的都是砍到1/3就停了,所以用捅的还能稍微好看点,多理解。

更新细节日志:

0816P2 远程包增加了特殊射钉枪:英特纳雄耐尔,特点是手持的时候制作品质+1,单次射击爆发10发铁钉,可通过工作台制造或者高级任务奖励小几率得到;增加了普通版MP7、M9A1的工作台制造配方。

0816 近战包部分属性优化,较为重要的有:太阳舞者不再造成长时间单体火焰伤害,而是有小几率造成群体短时间较高火焰伤害;铁狐现在的火焰伤害强化了;两把智力系近战武器调低了特效触发几率,增加了基础伤害。

0816 远程包部分属性优化,较为重要的有:安迪密恩现在不再造成单体电击伤害,而是有几率造成小范围群体电击;风之力提升了伤害和弹速。

0816 部分汉化文本修改,本次更新仅有xml修改。

0814 修复了拳套武器位置错误的问题(此处实名diss七日杀开发组)

0814 平衡和调整了部分进展/远程武器,让不同武器的差异性变大

0814 完善了部分武器的性能文本说明

0808 近战包新增肉斩骨断(力量+2)、绿色奇迹(对僵尸特攻)、青龙偃月(高截肢)、重生之刃(高潜行倍率)四把近战武器,重制了最后的武士和黑降两把武器的造型

0806 11:00 修复风之力箭矢位置问题@yichen手动狗头

0806 远程包新增 MP7、纯白仓萌、风之力三把远程武器

0806 近战包刀刃类部分武器属性buff

0801 远程包新增一把.44手枪、一把无限弹药的智力系步枪

0801 近战包新增长矛纳迦法、双手锤塔、单手剑永恒魔埚

0729 远程包新增两把霰弹枪:长射程的羞辱(游戏内显示射程不对,实际15)、基地保卫战决战兵器台风排笛(大幅度降低移动速度和体力、增强防御力)

0729 远程包修复几把特殊弹药武器的伤害值过低问题

0729 远程包武器属性调整

0726 近战包数据微调,远程包更新完成

0725 近战包更新完成

's avatar

明天再和朋友相见

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


读着视觉小说[1],是三位高中生一起在社团活动后的傍晚互相道别的场景。其中一人向另外两人开心地说道:“那么明天再和两位相见喔!”然后跑跳着离开了。

刚刚还在吵吵闹闹的场景,在一人离开之后一下子就安静了下来。看着屏幕上笼罩着夜色的背景,正在带入着主角思考的黄鼠,一瞬间感到了一丝孤独。尽管刚刚还在很开心,但不可避免地,一天马上就要结束了,大家都需要各自分道回家了。有趣的活动到现在已经停止,而朋友们也会是在接下来的一段时间里见不到的了。

但黄鼠在下一刻就意识到这是不需要过度感伤的,因为我们还有明天,我们在明天、十几个小时之后就会马上再见了。刚刚也是这样说的,“明天再和两位相见”,不是吗?这不是长时间的道别,所以黄鼠的孤独感转变成了期待——好期待明天的到来呀。只要熬过今晚的几个小时,再睡一觉,在明天就又可以很快和朋友相见,产生更多有趣的经历了。

不过很遗憾的是,这一切都只是在小说里发生的,黄鼠的上述的感受也只是针对那个虚构的故事的。而在现实中,除去有期待少有的特别活动(像是旅行计划)的到来外,似乎已经忘记自己上一次这样期待第二天的日常的到来是什么时候的事情了。

黄鼠印象中的校园日常,几乎就是充满了缺乏活力的轮回。每天早上起来,急急忙忙度过早晨,就开始了不一定很无聊,但大都很累人的课。结束了之后,回到家才可以放松一会,但也不能放松很长时间,因为马上父母就要回来监督自己完成作业了。每一天的自己,整天几乎全部的期待,都放在了放学回家后到父母回家前的那段“自由时间”里,似乎每天都是为那一小段时间而活。在这段时间结束后,下一次能够留给自己的时间就只有完成作业后(或放弃了完成作业后)躺在床上的时间了。而再往后,就又得挨过一整天的学校才能再次享用这份安逸了。

黄鼠不是在学校中没有能够愉快玩耍的朋友,但与朋友的交往,却很少能够像这次在小说中感到的那样,抵消上学的劳累,令黄鼠充满对明天的期待。

现实中的黄鼠,劳累于上学而期待在家的时间,而这段视觉小说中的小小对话,却把两者完全反转过来,开始期待与在学校的朋友们相见,而对在家的时间反而感到孤独了。

不过这只是视觉小说,黄鼠不是主角。而站在读者的角度的话,黄鼠只能对这样的日常表示羡慕了。能够有对每天怀有这样愉快的期待,真好呀。

黄鼠回不到像高中那样的校园生活了,因为在现实中只能向前看。在未来,即使能够找到工作而不是饿死或啃老,所面对的也大概只能是比校园更加乏味且劳累的社畜生活——实习的经历让黄鼠意识到了这一点。每天回家后几乎就像被抽干了体力一样,除了生活必要的事情(像是做饭),唯一想做的事情就是躺在床上耍废,看一些没有营养的 YouTube 视频,刷一些更缺少营养的社交媒体。游戏——甚至是相对低投入的手机游戏——都很少有心思去玩。写兴趣项目和学习更多知识的动力什么的,就更加被鸽子叼走了。在这样的日常中,每天值得期待的东西,就比学生日常更加稀少了。

黄鼠就经常这样想,做社畜的日常好辛苦呀好累呀好可怕呀。所以在读视觉小说时产生了“对明天日常的期待”的心情时,真是被自己惊讶到了呢。原来自己也可以对日常感到开心和期待。但可惜只是针对在小说中存在的虚构日常。

黄鼠看到这么一小段对话,就写了这么一长篇文章,诚实说,也是令自己觉得蛮惊讶的。不过在写完之后,黄鼠并没有什么深的感悟。要说整片文章有一个什么中心结论的话,那就是——二次元真好呀。 🐁


  1. 尽管这并不重要,但如果在好奇的话,黄鼠在读的视觉小说是《魔女的夜宴》。但请不要把这当作是黄鼠的推荐。故事的主要内容并没有和黄鼠在这篇文章中的感悟有很大联系。

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

violet's avatar

Leetcode - Remove Duplicates from Sorted List II

https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/

Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.

Return the linked list sorted as well.

Example 1:

Input: 1->2->3->3->4->4->5
Output: 1->2->5

Example 2:

Input: 1->1->1->2->3
Output: 2->3

 

violet's avatar

Leetcode - Plus One Linked List

https://leetcode.com/problems/plus-one-linked-list/

Given a non-negative integer represented as non-empty a singly linked list of digits, plus one to the integer.

You may assume the integer do not contain any leading zero, except the number 0 itself.

The digits are stored such that the most significant digit is at the head of the list.

Example :

Input: [1,2,3]
Output: [1,2,4]

 

violet's avatar

Go Routine Practice - tcp server&client

 

violet's avatar

Go Channel Practice V - 祖安萝莉

idea 来自 https://www.zhihu.com/question/402635037/answer/1302122540

逻辑没有照抄,只是做 channel 使用方法练习。

 

violet's avatar

Leetcode - Task Scheduler

https://leetcode.com/problems/task-scheduler/

You are given a char array representing tasks CPU need to do. It contains capital letters A to Z where each letter represents a different task. Tasks could be done without the original order of the array. Each task is done in one unit of time. For each unit of time, the CPU could complete either one task or just be idle.

However, there is a non-negative integer n that represents the cooldown period between two same tasks (the same letter in the array), that is that there must be at least n units of time between any two same tasks.

You need to return the least number of units of times that the CPU will take to finish all the given tasks.

 

Example 1:

Input: tasks = ["A","A","A","B","B","B"], n = 2
Output: 8
Explanation: 
A -> B -> idle -> A -> B -> idle -> A -> B
There is at least 2 units of time between any two same tasks.

Example 2:

Input: tasks = ["A","A","A","B","B","B"], n = 0
Output: 6
Explanation: On this case any permutation of size 6 would work since n = 0.
["A","A","A","B","B","B"]
["A","B","A","B","A","B"]
["B","B","B","A","A","A"]
...
And so on.

Example 3:

Input: tasks = ["A","A","A","A","A","A","B","C","D","E","F","G"], n = 2
Output: 16
Explanation: 
One possible solution is
A -> B -> C -> A -> D -> E -> A -> F -> G -> A -> idle -> idle -> A -> idle -> idle -> A

 

Constraints:

  • The number of tasks is in the range [1, 10000].
  • The integer n is in the range [0, 100].

 

violet's avatar

C memory layout

High Addresses ---> .----------------------.
                    |      Environment     |
                    |----------------------|
                    |                      |   Functions and variable are declared
                    |         STACK        |   on the stack.
base pointer ->     | - - - - - - - - - - -|
                    |           |          |
                    |           v          |
                    :                      :
                    .                      .   The stack grows down into unused space
                    .         Empty        .   while the heap grows up. 
                    .                      .
                    .                      .   (other memory maps do occur here, such 
                    .                      .    as dynamic libraries, and different memory
                    :                      :    allocate)
                    |           ^          |
                    |           |          |
 brk point ->       | - - - - - - - - - - -|   Dynamic memory is declared on the heap
                    |          HEAP        |
                    |                      |
                    |----------------------|
                    |          BSS         |   Uninitialized data (BSS)
                    |----------------------|   
                    |          Data        |   Initialized data (DS)
                    |----------------------|
                    |          Text        |   Binary code
Low Addresses ----> '----------------------'
Fenking's avatar

杂谈

在今天提交完最后一门课计组的report之后,我似乎意识到这是我自从大学以来第一个看上去可以无所事事的暑假。其实大概也不能,但是交完report,与学校暂时无瓜葛之后,涌上心头的第一感觉确实疲惫,困乏,无聊,无奈。这是今年在日本第二个什么都干不了的假期。距离上一次写博客时隔两年了。我也说不清为什么不写博客,似乎人在日本,就慢慢身心都远离了我所熟悉的事物,慢慢就变得蹒跚了起来。

作为杂谈,简单聊聊最近几年在干什么吧。
上一次博文是在2018年暑假,那就从2018暑假左右开始谈起。
2018年4月,高考失败后去日本再战。
2018年暑假,在国内复习与准备各种大学面试笔试。
2018年9月-2019年3月:我的住址从东京墨田区两国搬到东京墨田区向岛,再到千叶船桥市东船桥。
第二次留考仿佛高考的复写,考的稀烂,一塌糊涂,我靠着前期合格的立命馆大学一路冲刺其他学校,可惜全败。最后在4月开学前做了一趟全国环游,拜访了不少同学,但同时大概也是我最后一次和同学近距离相处。
2019年4月-2019年8月,在立命馆的第一个学期,仿佛被丢进大山里的城市人,手无寸铁,好不适应。为了提前解决这种问题,去考摩托驾照。
2019年9月提前回到日本,想着要早一秒拿到驾照。最后10月拿到了,这一年的浪人计划(重考)也开始了。10月开始的后半学期我没报太多课,空出来很多时间去继续战留考,战校内考。这次的留考拿到了凑合的成绩,后期的校内考充斥了整个假期,只得在元旦匆匆回国安稳一周。虽然在国内也是每天泡图书馆。现在我怎么也想不到,如果元旦不回国,我甚至会被困在日本一年以上。
2020寒假。一直埋在家里复习。碍于疫情,1月开始就在日本自我隔离,除了2月底出门在本周岛东西横断三次连续4天疯狂校内考以及零碎不连着的其他校内考,以及三月中旬骑摩托环琵琶湖一圈以外。没离开过南草津一步。
网课大二如期而至。每周12篇report冲破了最后的心理防线,半年以上和两个以下的人现实性往来,本质上被国内几乎所有过去的人遗忘,逐渐变成了连说话都会觉得奇怪的家伙。今天貌似又一次放假了。按理说今年不能再浪学校,却是要准备大三编入转学考试的,9月的托业还在等待我,但我貌似已经没有精力去做。未来去哪里读研?如何快速回国?貌似都是想不明白的问题。

放假即破灭。
没想到所谓放假的第一天,就发现老本行被掀锅,过去所想价值瞬间不存在了。
恍恍惚惚撞到一个介绍国内东方社群/同人圈的b站专栏,内容之详细,以至于和我多年慢慢积累的大量早期国内东方资料基本重合类似,甚至追加了渔场之前漂亮同人堂的内容–这部分对我而言一直是可有可无,本身算不上东方圈的开始的。但它积攒的却是鱼总Fish的思念,以及更早一批人的本心–其实也对我不是特别重要的部分,因为从渔场跟随到漂亮,最终会扯到kid–这之后还会牵扯更多同人团体,而我只对东方感兴趣。
文章本身几乎无可挑剔,国内东方社群历史本身了解的途径就很窄,一旦找到了就只有那一条路–大部分人可能都是从同一个地方出发,最后达到同一个目标,仿佛可以穿越回过去的历史,一笔一划写的清楚,容不下其他言语。虽然其中有些部分是怎么找到的,我也一直抱有迷惑,但文章本身其实是无所谓的。令人灰心的,是他的个人网站。
和很多之前认识的同龄人类似,这也是个年龄相仿的神童,一个早早就在互联网上可以留下自己一笔的人物,以至于他们的丰富,导致他们对丰富的否定。网站上写道,文章的决定是十分坎坷的,但它的过程,确实一气呵成的,平均一周一篇。我不清楚我之外的人对东方同人了解甚多甚少,不知道他们是否有高强的起点,至少我得到很多消息,除了通过那条固定的渠线,还有很多迷津小路,但大概都是被在一周之内完成了。
心态恢复平静,继续看对方的网站上的文章。
东方在对于国内东方社群,或者就是东方同人社群,大概就是爱好者从深受影响而同人创作,进而走进专业化,原创化,最后创造新的project,成为领域的或东或西某一角。不论是从同人音乐走向专业电音领域的haku,还是从同人画手走向制作人,新的project人的海猫氢弹库,更或者早已在各个领域扎根的各路神仙,国内的东方社群虽然早就断代了,在渔场死后,在小镇死后,但是某些时代的终点就是某些时代的起点,宛如一所大学,终将毕业之人最后携手或者不约而同成立新的时代,逝去的中国东方同人史一直在诉说这一轮回,不同于贴吧开始的新东方社群。这些话在多年前就深根蒂固于心,乃至一直是我作为东方同人史爱好者砥砺前行的唯一动力–回到过去,追忆过去,透彻过去,【历史可以被遗忘,但不能被遗失。】【中国东方同人史就是从引导一拨人,从同人走向专业,走向毕业,走向新的project。】没有被展示出来的后句,我甚至不敢在任何地方明示。不过同样的话已经被说过了,现在再高呼出来,也不过是巧妙的蹭罢了。就像看到论文出版而痛悔不已的科学家,自己做过的一切仿佛都是尘埃,自己接下来做的一切仿佛都是追随。我曾在好几年前就对【想法】的保护烦恼许久–世界的残酷容不下共同的荣誉,时间的存在更是让每个随着时间跳动的生命对它致以崇高的敬意,先与后是绝对的,不容打破,不能打破,只能在懊悔中为自己感到羞愧。然而像这样写文章去发泄自己,终究不过是在暗地里为自己的嫉妒发生,往如在病床上看着电视里的范马父子,大喊【这我也做得到呀!】的杰克范马一样。
终究还是早了半年。而这半年是我没有接触它的半年,这半年的结束也一如平常,在现在结束的一瞬间,它就追上了你。
从今往后,我似乎也失去了在这一领域探索的义务,失去了一切的动力。自讨苦吃,接下来的每一步看似在证明,其实在挽救,在诡辩,在狡辩。
暂时确实不知道该怎么做。
看着对方的文章,感觉自己也是这么想的,但为什么你会说出来而我没有找到说出来的机会。但仔细想想自己仿佛又不是这样想的,对自己的本心产生了疑惑,一篇文章竟让我如此动摇。仿佛中国东方同人史的研究,早已成为自己最后的遮羞布,需要完成的却没有完成。
仔细想想所处的环境,说不定环境确实早就了这样的我–缺少交流,缺少实感,往如在新东方上培训课的竞职者,失去了所有爱好的土壤。
仿佛一直在说日本是宅的圣地,也是东方爱好者的圣地,是东方的土壤。我为何对这片土地毫无发觉,毫无触觉呢?盈月纪年和境界生命物语在交付完成到zun先生手上的那一瞬间开始,对我而言zun先生不过是zun而已,在我心中它仿佛不会对我而言所爱着的东方产生任何价值,其实自己爱着的东方也并不一定是zun先生自己创造的价值。时代,人群,年岁,机遇,信息,身份,是多元的遭遇创造了早期的中国东方同人圈(社群),而又是这多元的每一层每一丝的紊乱错综,一步步让它走向自我灭亡。我总会在最后发现我到底想说什么。我不想谈东方爱好者,但我必须谈。那个时代的东方爱好者可能并不存在什么转型,他不论之后去做什么,不做什么,他都永远剥不掉身上【早期东方同人圈一员】这样的标签,这个标签也在无时无刻不影响这个人。也许算一种“因果”,但我希望这层神秘的面纱不会脱落。

我不想当追随者,但也不得不当。
2020.7.23

violet's avatar

Leetcode - Top K Frequent Elements

https://leetcode.com/problems/top-k-frequent-elements/

Given a non-empty array of integers, return the k most frequent elements.

Example 1:

Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]

Example 2:

Input: nums = [1], k = 1
Output: [1]

 

依云's avatar

Linux 的环境变量怎么设

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

最近,Arch Linux 的 pam 包将更新到 1.4.0,然后因为一个字符的变化,不少中文用户都开始避难了:pam_env 将默认不读取用户的环境变量设置。许多中文用户使用~/.pam_environment文件来配置 fcitx 输入法所需要的那三个环境变量。更新之后,这些配置将不再生效,意味着他们可能无法输入中文了,于是大家热烈讨论现在要在哪里配置环境变量比较好。

当然了,在 pam 的配置文件里加上user_readenv=1就可以恢复原先的行为。只是,pam 的开发者这么改当然是有原因的:CVE-2010-4708。简单地说,就是在鉴权模块里设置用户指定的环境变量不安全,怕被提权。

2020年08月20日更新:Arch Linux 打包时添加了以上这个配置

当然啦,桌面用户完全可以去改系统级的环境变量设置,只要你愿意让你个人的配置信息跑到系统配置那边去的话。

正文

用户经常需要设置一些环境变量,比如输入法,比如语言和地区选项,比如自定义的 PATH,等等。然而 Linux 的环境变量又不像 Windows 那样有一个专门设置所谓「系统环境变量」的地方,而是所有环境变量全部由子进程继承父进程获得,这么一路继承下来的。于是,想要给所有想设置上的进程都设置上,就不是一件简单的事情了。

这里关注的是桌面用户,自然首先从图形界面说起。

使用 X11 的桌面环境,通常通过 display manager 来登录,比如 lightdm 和 sddm。这俩都支持 ~/.xprofile。这个文件会在启动过程中被 source,使用的 shell 是由 dm 自己确定的。lightdm 和 sddm 都是用的 /bin/sh(分别位于 /etc/lightdm/Xsession 和 /usr/share/sddm/scripts/Xsession 文件里)。可以看到,除了读取 .xprofile 外,lightdm 也会读取 .profile。sddm 甚至连 bash、zsh、tcsh、fish 的启动配置脚本都给读了。

对于 Wayland,我这儿只有 sddm,类似的,也是各种 shell 的都给你读了。(当然就不读 X11 相关的东西了。)

而对于手动 startx 的用户,~/.xinitrc 里自己写上呗。还有 VNC 啥的,也都可以自己看启动脚本找到方法。

没有图形界面的登录,通常是从 tty 或者 ssh 登录。这两者都是登录到命令行 shell。写在 shell 配置里就可以了。具体到 zsh,我是写到 ~/.zprofile,这样不管是否交互,只要是登录 shell 就执行,不登录的大概已经继承到了。另外有些情况可能写这儿也没有用,比如 cron 调用的时候。非要搞的话其实可以写到 ~/.zshenv,这个基本上所有的 zsh 都会读,只能被系统级设置或者命令行参数禁用掉。而如果是 bash 用户,.bash_profile .bash_login .profile 这仨,会读找到的第一个(sddm 也会按这个顺序找,但是 lightdm 只会找 .profile)。Arch Linux 现在默认会给新用户建立 .bash_profile,我建议 bash 用户把它改名成 .profile。这里有个图 ,大致上说明了 bash 和 zsh 不同情况下会读取的配置文件

systemd 用户实例也有一份环境变量,用于通过 systemd 启动的用户级服务,通过 systemctl --user 的子命令可以查看和更新。D-Bus 也有一份,可以通过 dbus-update-activation-environment 命令来更新。这俩通常不需要用户操心,桌面环境应该会维护好。

如果你用 tmux 的话,那么 tmux 还有一份,用于新创建的窗格。tmux 会在被连接时更新 update-environment 选项指定的环境变量。当然你也可以用 tmux setenv 子命令去更新。这个尤其值得注意,因为 tmux 可能在不同的环境中被连接,导致环境变量混乱(比如 X11 下没有 DISPLAY 变量)。

要注意的一点是,不同的登录过程并不是只会读取自己专属的配置文件,尽管大家都在努力,也并没有完全统一好用的配置文件。所以有些环境变量,你可能想尽量避免重复设置(比如冗长重复的 PATH 项就很讨厌)。好在这些都是 shell 脚本,不光能设置环境变量,也能做条件判断。

要查看当前进程的环境变量,可以用 env 命令。要查看别的进程的,去读它的 /proc/PID/environ 文件,或者开个 htop 然后在进程上按 e 键。要看看某个环境变量在不同进程里是什么情况,可以用我写的小工具 compare-env

Linux 软件生态的特点就是这样,没有谁规定一定要用怎样的方式做一件事情,所以大家的想法总会有些出入,就导致设置个环境变量还有这么一大群配置文件(systemd 还有一份呢,我还没读没试所以没说)。但另一方面,理解它们也是十分容易的:不用猜测,不用撞大运般地耗费时间去尝试,顺着代码摸过去,总能弄明白软件的行事逻辑。即使文档像 pam_env 那样前后矛盾,也有源代码这条路可以精确刻画软件的行为。

violet's avatar

React - 组合 vs 继承

React 有十分强大的组合模式。我们推荐使用组合而非继承来实现组件间的代码重用。

Props 和组合为你提供了清晰而安全地定制组件外观和行为的灵活方式。注意:组件可以接受任意 props,包括基本数据类型,React 元素以及函数。

如果你想要在组件间复用非 UI 的功能,我们建议将其提取为一个单独的 JavaScript 模块,如函数、对象或者类。组件可以直接引入(import)而无需通过 extend 继承它们。

 

violet's avatar

React - 状态提升

在 React 应用中,任何可变数据应当只有一个相对应的唯一“数据源”。通常,state 都是首先添加到需要渲染数据的组件中去。然后,如果其他组件也需要这个 state,那么你可以将它提升至这些组件的最近共同父组件中。你应当依靠自上而下的数据流,而不是尝试在不同组件间同步 state。
虽然提升 state 方式比双向绑定方式需要编写更多的“样板”代码,但带来的好处是,排查和隔离 bug 所需的工作量将会变少。由于“存在”于组件中的任何 state,仅有组件自己能够修改它,因此 bug 的排查范围被大大缩减了。此外,你也可以使用自定义逻辑来拒绝或转换用户的输入。
如果某些数据可以由 props 或 state 推导得出,那么它就不应该存在于 state 中。

 

violet's avatar

React - 表单

在 react 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState() 来更新。

React 并不会使用 selected 属性,而是在根 select 标签上使用 value 属性。这在受控组件中更便捷,因为您只需要在根标签中更新它。

可以将数组传递到 value 属性中,以支持在 select 标签中选择多个选项
<select multiple={true} value={['B', 'C']}>

当需要处理多个 input 元素时,我们可以给每个元素添加 name 属性,并让处理函数根据 event.target.name 的值选择要执行的操作

在受控组件上指定 value 的 prop 会阻止用户更改输入。如果你指定了 value,但输入仍可编辑,则可能是你意外地将value 设置为 undefined 或 null。

有时使用受控组件会很麻烦,因为你需要为数据变化的每种方式都编写事件处理函数,并通过一个 React 组件传递所有的输入 state。当你将之前的代码库转换为 React 或将 React 应用程序与非 React 库集成时,这可能会令人厌烦。在这些情况下,你可能希望使用非受控组件, 这是实现输入表单的另一种方式。如果你想寻找包含验证、追踪访问字段以及处理表单提交的完整解决方案,使用 Formik 是不错的选择。

violet's avatar

React - 列表 & Key

用 key 提取组件

元素的 key 只有放在就近的数组上下文中才有意义。

比方说,如果你提取出一个 ListItem 组件,你应该把 key 保留在数组中的这个 <ListItem /> 元素上,而不是放在 ListItem 组件中的 <li> 元素上。

key 只是在兄弟节点之间必须唯一

key 会传递信息给 React ,但不会传递给你的组件。如果你的组件中需要使用 key 属性的值,请用其他属性名显式传递这个值

function Blog(props) {
  const sidebar = (
    <ul>
      {props.posts.map((post) =>
                       <li key={post.id}>
                         {post.title}
                       </li>
                      )}
      </ul>
  );
  const content = props.posts.map((post) =>
                                 <div key={post.id}>
                                    <h3>{post.title}</h3>
                                    <p>{post.content}</p>
                                    </div>
                                 );
  return (
     <div>
       {sidebar}
       <hr />
       {content}
     </div>
  );
}

const posts = [
  {id: 1, title: 'hello world', content: 'welcome to learning react!'},
  {id: 2, title: 'installation', content: 'you can install react from npm.'}
];
ReactDOM.render(
  <Blog posts={posts} />,
  document.getElementById('root')
);
violet's avatar

React - 条件渲染

class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
    this.state = {isLoggedIn: false};
  }

  handleLoginClick() {
    this.setState({isLoggedIn: true});
  }

  handleLogoutClick() {
    this.setState({isLoggedIn: false});
  }

  render() {
    const isLoggedIn = this.state.isLoggedIn;
    let button;

    if (isLoggedIn) {
      button = <LogoutButton onClick={this.handleLogoutClick} />;
    } else {
      button = <LoginButton onClick={this.handleLoginClick} />;
    }

    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {button}
      </div>
    );
  }
}


function LoginButton(props) {
  return (
    <button onClick={props.onClick}>
      Login
    </button>
  );
}

function LogoutButton(props) {
  return (
    <button onClick={props.onClick}>
      Logout
    </button>
  );
}

function UserGreeting(props) {
  return <h1>Welcome back!</h1>
}

function GuestGreeting(props) {
  return <h1>Please sign up.</h1>
}

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    console.log(isLoggedIn)
    return (
      <UserGreeting />
    );
  }
  return (
    <GuestGreeting />
  );
}

ReactDOM.render(
  <LoginControl />,
  document.getElementById('root')
);

在 js 中,true && expression 返回 expression,而 false && expression 返回 false。

阻止组件渲染
可以让 render 返回 null,不进行任何渲染。

function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }
  return (
    <div className="warning">
      warning!
    </div>
  );
}

class Page extends React.Component {
  constructor(props) {
    super(props);
    this.state = {showWarning: true};
    this.handleToggleClick = this.handleToggleClick.bind(this);
  }
  
  handleToggleClick() {
    this.setState(state => ({
      showWarning: !state.showWarning
    }));
  }
  render() {
    return (
      <div>
        <WarningBanner warn={this.state.showWarning} />
        <button onClick={this.handleToggleClick}>
          {this.state.showWarning ? 'Hide' : 'Show'}
        </button>
      </div>
    );
  }
}

ReactDOM.render(
  <Page />,
  document.getElementById('root')
);
's avatar

Something Incredible Between Them

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.


Mathew feels troubled today. It’s not because of the mock final exam that has just passed. Although indeed he didn’t do well, it doesn’t bother him too much. He believes that studying is easy, relatively speaking. All he have got to do is to read those textbooks, remember these bullet points, do things that have all been successfully done by billions of people. Even he has trouble understanding, he has literally all the resources to help him. As long as he studies seriously, his grades are bound to rise to a respectable level. That’s what he believes, at least.

What troubles him, is the tiny screen glowing in his hand. On the top of the screen is the logo of a popular social media. On a more prominent part of the screen is a name that can drive Mathew’s heart up and down in milliseconds, Remi. The post on screen is not sent by Remi however, it’s another person that occupies a large part of Mathew’s mind, Karter. The post reads: I just witnessed something incredible of Remi.

Someone asks “What’s incredible?” and judging from the response Karter has given, it’s apparently very secretive.

“It’s always been like that.” Mathew mumbles. “Saying some prompt as if wanting to tell us more of a story, but just as the prompt provoked others’ curiosity, they tell us no more.”

Well, that’s what couples do, isn’t that right? They share things on social media not for others to see, but for themselves to have the pleasure of showing off and being showed off. Mathew doesn’t think it’s a badly selfish thing. In fact, he likes it when people announce their love, and enjoys reading romantic stories, both real and fictional. In fact, he craves for it. It doesn’t only make him happy for those in love, but also gives him a space for illusions as if he is part of it. This is usually the case with people that Mathew is unfamiliar with, and especially the case when the couple in question includes the one he admires.

Indeed, “admires” is the most Mathew dares to say about his feeling towards Remi.

Mathew met Remi when he was a first-year high school student. Remi was in the second year. In a school-organised activity, where 3-5 students from both first-year and second-year collaborated to complete a collage on a topic freely chosen. The groups were randomly arranged, although students had a chance to rearrange if they were unhappy about their groups. Mathew, a couple of unimportant people, and Remi were in the same group, they were quite happy about the arrangement, so it stuck. Mathew quickly took a liking on Remi. Remi is interesting, artistic, caring, and knows quite a lot. Remi didn’t seem to think Mathew as a nuisance either, so they exchanged contacts and chatted regularly. The collage didn’t end up being a hit, but it was good enough that both their parents praised them for it.

Later on, Matthew loved hanging out with a bunch of second-year students after each class, including Remi. The first-years and second-years were in the same building, so it wasn’t a rare sight in this high school. To others, they just looked every other students hanging out together, but to Mathew, the times they spend together were incredible. The more Mathew knew about Remi, the greater he thinks about Remi. And Mathew thought, this was going to last forever.

But obviously it couldn’t. A year passed by, Remi had gone up to the third year. The third-years were in a different building, “In order to better assist their studies.” The time Remi could spend with Mathew had drastically decreased, their interaction was then mostly restricted to social media and weekends. It was also around the start of the academic year that Karter started to appear in Remi’s social media posts.

Mathew didn’t care that he didn’t know Karter personally. “It’s just someone Remi thinks is cool.” Mathew thought. He knew, by reputation, that Karter was a prominent member in the school soccer team, but then resigned for some reason. “Whatever, it doesn’t bother me at all.” Mathew told himself.

But then Karter was mentioned more and more by Remi. They posted more and more photos of them together. They also put each other’s username in their social media profile. “Wow, they must be really good friends.” Mathew thought, “Karter must be a genuinely interesting person. I kinda want to know more about.” Mathew wasn’t jealous or anything, at least he knew he shouldn’t be.

One day, Mathew got a 2-ticket bundle at a local movie theatre, it could only be used when 2 people went at the same time. So Mathew invited Remi.

“Is it just us two?”

“Yes, it’s a 2-ticket bundle.”

“I guess…​ but Karter probably wouldn’t be happy about it.”

The rest of the conversation didn’t matter. The last sentence Remi said stuck in Mathew’s head. “Why would Karter be unhappy about Remi and I going to a movie?” Mathew pondered, “What kind of people would be unhappy? Is it…​ what I imagined it is?”

There wasn’t a sure answer, but later observations only confirmed Mathew’s guess. Remi and Karter, are in a relationship. They didn’t announce it when it started, but they are, now.

It is when Mathew made this guess that he also realized how jealous he was over having someone that holds an exclusive lock on Remi. There are now things that Remi must keep Mathew away from. There are now things that Remi cannot do for Mathew.

It was time that Mathew needs to accept the new reality, one that has Remi occupied by someone Mathew wasn’t close with.

This reality has been largely accepted by Mathew today. He knows he can only watch Remi and Karter from a friendly distance. He has also attempted to get close with Karter, but they don’t much in common. Mathew knows that there will always be a large part of Remi he can’t acquire forcibly, so the best course of action, is instead watch for things that Karter and Remi shared about their life publicly, consuming that, relieves his insatiable hunger for more Remi.

But Mathew also knows that he can’t do this forever. In matter of months, Remi and Karter, both as third-years, are graduating. Whether they’re going to the same college is unkown to Mathew. Obviously he could just ask Remi. But he is too scared to ask, as he is with many more questions to Remi. The same goes for many things Mathew wants to say to Karter and Remi, but he will never say them, as they are, at most, irrespective and irresponsible. Mathew thinks it’s best for him to befriend Karter, and be friends with both Remi and Karter for as long as they can keep in contact.

Yet, Mathew is feeling troubled by something incredible between them that he can’t know about. 🐁


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

MikroTik RB4011 访客网络配置备忘

前言


由于之前陆陆续续添置了不少电子设备,以及更换 ISP 的原因,机架上连了5台设备,每台各负责一点点事情,不管是配置还是调试都很麻烦。再加上旧路由器不能很好同时处理千兆 NAT 和 VLAN,于是最近入手了一台 RB4011iGS+5HacQ2HnD-IN,把这一堆乱七八糟的设备统统换掉。主要需求有三点:

  1. 划分2个 VLAN,一个内部网络,一个访客网络。
  2. IPv4 和 IPv6 双栈接入。
  3. 因为路由器直接暴露在 Internet 上了,所以防火墙一定要配好,包括 VLAN 之间的访问也是靠防火墙来控制的。
SgDylan's avatar

DIY 显示器亮度自动调节

DIY 显示器亮度自动调节记录存档。

AlisterTT's avatar

板烧的LOGO

给板烧画了个水印用的LOGO,感觉有内味了,中文字体思源黑,英文字体Helvetica Black,感觉有内味儿了。

AlisterTT's avatar

吾有猫,其名为“板烧”

今年决定养只猫了,找到了一家靠谱的猫舍,店长每天都在勤勤恳恳的做着直播,目前观众还不是很多。

2020年6月5日,猫舍的小母猫铁扇公主生下了四只小猫,一只梵,一只蓝,板烧排行老三,以及排行老四、最可爱的蓝白妹妹。

板烧是四兄妹中最小的一只,但是很努力的在喝奶,这两天打开直播看到他,心里都在默默的说:“板烧,冲鸭!”

因为体型最小,所以也最努力喝奶的板烧

至于他为什么要叫板烧呢,开始想着如果选到了妹妹,就叫“茶茶”,选到了弟弟,就叫“信长”或者“秀吉”,可是朋友都觉得这俩名字太正经,于是探讨了大半天无果…后来小豆子建议选我最喜欢吃的食物,那当然是暴风雪或者麦旋风了,用来起名就欠了点,灵光一闪“板烧”这个名字就出来了,甚至已经做好了设定,等小朋友长大了就叫“大阪烧”(误)…

2020年6月12日晚上的板烧

小猫在妈妈身边要待六十天左右,估计八月份就能接回家了,板烧,一定要健康呀!!

farseerfc's avatar

系統中的大多數文件有多大?

你覺得,你的系統中大多數文件大概有多大?

這是一個很有意思的問題,你可以試着先猜一下。

基於對系統中保存文件的瞭解,可能有這樣的思考過程:

  • 我收藏了好多照片,每個有 2~5MiB 吧。
  • 我下載了好多漫畫,每個 100KiB 左右,這些大概佔了不少比例。
  • 我還收藏了不少動畫電影電視劇,雖然這些文件總數量可能不多?
  • 我下載了 Linux 的源碼,那裏面每個 C 代碼文件都幾千行,每行 100 字寬,平均也得有 30KiB 吧,有幾萬個源碼文件呢,佔比應該挺大的……

問題中「大多數」其實是個挺不精確的稱呼,換個精確點的問法:你覺得你的系統中 文件大小的中位數 大概在什麼範圍內?或者說,文件系統中 文件大小的分佈情況 一般是怎樣的曲線?

這個問題其實還有多種別的問法,比如:一個常見的桌面或者服務器系統中,多大的文件算大文件, 多小的文件算小文件,什麼範圍內的大小算是普通呢?

經歷過基本的科學教育的人 …

依云's avatar

终端色彩总结

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

终端转义序列里有一个 SGR 代码用于表示「粗体或者增加强度」的字体渲染。相当多的终端将其实现作更明亮的颜色而非粗体字,也有很多终端应用程序如此(比如 mutt 中的 brightXXX 颜色使用此代码;新一点的 mutt 支持使用 lightXXX 来表示亮色了)。

然而最近,GNOME 终端决定将这个「或」字去掉,让 SGR 代码 1 表示粗体,亮色使用另外的颜色代码来表示。这无疑导致了我看到的许多软件里出现粗体字。有时候看着还行(比如 systemd、htop 中的),有时候会让人觉得很不舒服(比如 zsh 里打着命令,字体一会儿变粗一会儿变普通粗细)。我就认真去查了一下相关信息,作出相应的配置更改,顺便做个总结笔记好了。

转义序列

「选择图形展现」(Select Graphic Rendition; SGR)序列用于设置字体的渲染方式。其格式为CSI (code ";")* code m。CSI 就是 ESC "["。一个序列里可以给出多个代码,使用分号分隔。如果一个都不给出,当作代码 0 解释。

八色

这是最基础的八种颜色,代码 30-37 设置前景色,40-47 设置背景色。

16色

这就是大多数终端设置里,那个14色的调色板所指定的色彩了。为什么只有14色呢?因为默认的前景色和背景色是单独的设置项。

如序言中所说,相当多的终端将代码 1 解释为亮色,也就是上述八色再加上对应的明亮版本。

自 GNOME 终端此次改革之后,代码 1 只管粗体。要亮色,使用代码 90-97 设置前景色,100-107 设置背景色。除了 GNOME 终端外,也有一些其它终端跟进,比如 alacritty。有些终端保留了将代码 1 解释为亮色的选项,而 GNOME 终端最近去掉了这个选项(但是还有一个将粗体字显示为亮色的选项)。

256色

16色怎么够?于是出现了256色。

ESC[38;5;<n>m用于设置前景色,ESC[48;5;<n>m用于设置背景色。其中,n 是一个数,0-7 同代码 30-37,是那最初八种颜色。8-15 是它们的亮色变种。16-231 是216种彩色,在RGB空间构成了一个6x6x6的立方体。232-255 是24个灰阶色彩。

一些标准中,这中间的分隔符使用冒号。

真彩色

现代显示器普遍使用8位值表示RGB中每一个通道、共计24位了,终端也不能落后呀。于是有些终端也支持了这个被称为「真彩色」的24位色彩了。

代码格式是256色的扩充。ESC[38;2;<r>;<g>;<b>m来设置前景色,ESC[48;2;<r>;<g>;<b>m设置背景色。这里的 r、g、b 当然就是RGB色彩空间的值了,每一项的取值范围是 0-255。

测试脚本

整合了我从各处收集到的展示方式,写了一个脚本,可以直观地感受终端对各种色彩的支持情况:

colors.py

参考资料

SgDylan's avatar

使用 VMAF 对静态图片进行质量评估

使用 VMAF 评估图片质量,测量算法性能。

SgDylan's avatar

DIY 显示器背景灯 Lightpack

最近自己弄了一套显示器背景光,在此稍微记录一下。

Jixun's avatar

移除游戏添加的美式英文键盘

很多 FPS 游戏(如 CS:GO)会在启动的时候添加一个美式英文键盘,但不会在结束游戏的时候卸载这个键盘。

在 Steam 社区找到一个批处理的解决方案,不过需要保存两个额外的 xml 文件在硬盘来调用。

研究了下相关的 API,用汇编做了个简单的小程序。

下载

GitHub | 历史版本

源码使用 BSD 3-Clause 协议授权,可以在 JixunMoe/RemoveUSKeyboardLayout 获取。

启动游戏并移除美式键盘

  • 此处使用的例子是“军团要塞2”。
  • 其他游戏的 Steam APPID 可以从其对应的商店地址找到。

将批处理与编译后的文件放在同一目录:

REM 启动游戏 start steam://rungameid/440 REM 等待游戏启动并添加键盘 timeout /t 5 REM 移除键盘 %~dp0\RemoveUSKeyboardLayout.exe

或,使用 VBScript 脚本启动来隐藏命令行窗口:

Set objShell = CreateObject("Shell.Application") Set objFSO = CreateObject("Scripting.FileSystemObject") Set objFile = objFSO.GetFile(Wscript.ScriptFullName) strFolder = objFSO.GetParentFolderName(objFile) ' 启动游戏 objShell.ShellExecute "steam://rungameid/440" ' 等待游戏启动并添加键盘 WScript.Sleep(5000) ' 移除美式键盘 objShell.ShellExecute strFolder & "\RemoveUSKeyboardLayout.exe"

移除游戏添加的美式英文键盘最先出现在Jixun 项目集

Jixun's avatar

FC 魂斗罗1 汉化

FC 上的《魂斗罗1》是我在 2016 年做的,很多内容已经找不到了唔…

汉化说明

人生第一个汉化的 FC 游戏。因为字数不算太多,就试着汉化了下。

汉化基于有剧情、有动画的日文版本制作。

汉化完后,发现以前汉化 FC 游戏的前辈真不容易啊~

汉化内容参考自英文翻译版、百科、贴吧以及网络上的各种资源,因为我看不懂游戏里的日文…

标题界面调色有点小问题,脸有点黑… 不要在意细节~

以上。

  • 标题画面
  • 剧情画面
  • 过场画面
FC《魂斗罗 1》汉化截图

下载

更新说明

  • v2 – 2016.08.04
    • 修复地图界面的卡顿 & 乱码。
    • 翻译了之前漏翻的隐藏信息。
    • 加强了断句信息的停顿。
  • v1- 2016.08.03 – 初版发布

碎碎念

汉化的时候折腾了好一段时间;因为网络上文章的丢失(很多做 FC 汉化的前辈的部落格都无法正常访问了),很多时候都是自己一个人在瞎折腾。还好最终给我折腾出来了

汉化日记可以在旧博客上找到(含目录),日期大概横穿了从立项到发布的日期哈哈。

对代码部分所做的代码更改则使用 BSD-3-Clause 授权协议,可以在 JixunMoe/ContraNES1TranslationPatch 获取。

过段时间把汉化日记补充道后续页面吧。

FC 魂斗罗1 汉化最先出现在Jixun 项目集

Jixun's avatar

QMC 解密

腾讯旗下的《QQ 音乐》所使用的音乐文件加密格式就是 QMC,本质上就是将整个文件读入后用 XOR 处理。

下载

GitHub | 历史版本

源码使用 MIT 协议授权,可以在 JixunMoe/qmc-decode 获取。

使用说明

使用解码程序对 .qmc 文件进行处理。

打开命令行,执行像上图一样的命令即可。

.\qmc_crypto.win64.exe .\周杰伦-青花瓷.qmcflac .\周杰伦-青花瓷.flac

具体调用方法:qmc_crypto.win64.exe "<qmc文件路径>" "<解密后文件路径>"

更新历史

  • v1.0.1 – 2019.07.16 – 修正 Linux 下无法编译的错误,感谢 @nswa-project 提交的 PR。
  • v1.0 – 2019.05.25 – 初版发布。

碎碎念

解密代码其实是从某个第三方 APK 里面提取的,里面有一个叫com.tencent.qqmusic.business.musicdownload.vipdownload.PayProcessor 的类。

这个类里面有两个函数,分别是 native_decryptnative_encrypt

估计就是从手机版《QQ 音乐》里面提取出来的了吧?

QMC 解密最先出现在Jixun 项目集

Jixun's avatar

100% 橙汁 – 资源解包工具 v1.1

100% 橙汁(100% Orange Juice)是一个类似大富翁的游戏。

支持类型

  • .dat 后缀文件解密
  • 伪装为 ZIP 压缩包,内部包含后缀名为 .dat 的加密文件(如 animation.pak
  • 将合并后的 ogg 拆分成单独的文件(如 bgm.pak
  • 将合并后的 wav 拆分成单独的文件(如 se.pak

使用方法

OrangeDecryptor <输入文件> <输出路径/目录> [模式]

如果不填写模式的话,将尝试自动识别。

下载

季寻储存 | GitHub | 历史版本

源码使用 BSD 3-Clause 协议授权,可以在 JixunMoe/OrangeDecryptor 获取。

更新记录

  • v1.1 – 2018.01.18 – 修正 XP 下的支援
  • v1.0 – 2018.01.?? – 最初版本发布

碎碎念

本来想顺便把源码放 GitHub 的,可惜用 Everything 一搜才发现找不到源码… 看来是某次重装的时候不小心删掉了呀。

在去年的一个系统备份里找到了

参考来源

这里的参考来源全凭记忆了,毕竟这东西写了有两年了。

  1. WAV 文件格式的说明:
    https://wiki.fileformat.com/audio/wav/ (存档)
  2. OGG 文件格式的说明:
    https://xiph.org/ogg/doc/framing.html (存档)

100% 橙汁 – 资源解包工具 v1.1最先出现在Jixun 项目集

Jixun's avatar

蓝光原盘压硬字幕并跳过前 10 秒

找到个未加密的原盘,里面有一堆字幕轨,发现第一轨(0:s:0)是需要的字幕。

字幕的前几秒是一些观影说明,也可以一同去掉(大约 10 秒长度)

蓝光里的音频倒是有一堆,直接用第一个音轨(0:a:0)就行。

目标播放设备不支援 x265 也不支援 10 bit,因此编码器选择的是 x264 以及 Profile 为 main@4.0

跟着网上找的说明,加上一些 B帧、引用帧的设定以及一些调整,最终的压制脚本如下:

#!/bin/sh set -ex INPUT_PATH="bluray:/path/to/disk" OUTPUT_PATH="/tmp/Film.name.YYYY.1080p-ENCODE.mp4" META_TITLE="中文名 - 外文名 (年份)" AUDIO_MAP="0:a:0" nice -n 15 -- \ ffmpeg -stats -i "${INPUT_PATH}" \ -filter_complex "[0:v:0][0:s:0]overlay=0:0:enable='gte(t,10)'" \ -metadata title="${META_TITLE}" \ -movflags +faststart \ -c:v libx264 \ -crf 20 \ -flags +loop \ -deblock 0:0 \ -bf 16 -b_strategy 2 -refs 6 -maxrate 12M \ -profile:v main -level 4.0 \ -preset slow -tune animation \ -c:a libfdk_aac -vbr 5 \ -map "0:v:0" -map "$AUDIO_MAP" \ "$OUTPUT_PATH"

如果是 Windows 环境,可能使用 AviSynth 脚本会比较好一些?调滤镜什么的也方便。

最后压出来的视频大概 2 个小时长,因为 B 帧 设定得比较大,每次快进都是 5 秒一跳;不过考虑到视频是拿来本地收藏用的,还是能够接受。

参考资料

  1. 介绍 ffmpeg 中对应的 x264 选项的文档:
    https://sites.google.com/site/linuxencoding/x264-ffmpeg-mapping
  2. 对 ffmpeg 中使用 -deblockalpha 参数却不能使用的解决方案:
    https://stackoverflow.com/a/23539599
  3. ffmpeg 百科对滤镜的教程:
    https://trac.ffmpeg.org/wiki/FilteringGuide
  4. ffmpeg 的滤镜文档:
    https://ffmpeg.org/ffmpeg-filters.html

蓝光原盘压硬字幕并跳过前 10 秒最先出现在Jixun 项目集

Jixun's avatar

仓库用度盘投稿助手

虽然说当初是为了某个仓库而做的辅助插件,没想到现在因为百度网盘的严打而再次热门起来 _(:3__

脚本安装

首先需要安装一个脚本管理器,推荐使用 暴力猴,然后安装脚本兼容版)。

推荐使用原版,兼容版做了一些转译操作来兼容旧内核浏览器而增加了体积。

源码使用 MIT 协议授权,可以在 JixunMoe/dupan-helper 获取。

脚本说明

安装脚本后,百度网盘的管理页面会多出一些功能:

  1. 自定义分享(提取密码)
  2. 批量重命名
  3. 标准提取码(秒传链接),分享再也不会失效啦 ^1
  • 批量重命名选中的文件
  • 自定义分享密码
  • 导入标准提取码

^1 取决于百度网盘是否针对文件特征码进行屏蔽。

支持的提取码

  • 「游侠」的「肚娘提取码」。 游侠格式的提取码一次只能添加一个,不能与其他格式混搭。
  • 梦姬标准提取码
  • PanDownload 的 bdpan:// 协议链接。

※ PanDownload 的作者于二〇二〇年四月被捕,请小心目前在网上流传的版本。

标准提取码生成器

标准提取码生成器以及相关说明请参见从「百度网盘标准提取码生成器」。

仓库用度盘投稿助手最先出现在Jixun 项目集

Jixun's avatar

百度网盘标准提取码生成器

配合脚本使用效果更佳!仓库用度盘投稿助手

软件非常的简单,打开后把文件拖放进来,然后按下「生成代码」就会生成提取码了。

标准提取码生成器的主界面

软件下载

下载:季寻储存 | 百度网盘:xxxx | GitHub

源码使用 BSD 3-Clause 协议授权,可以在 JixunMoe/mfcDuDownloadCodeGenerator 获取。

旧版本存档

这个是更早之前使用易语言做的了,分别是 v1 实现了游侠的格式,而 v2 则实现了标准提取码的格式。

此处提供的旧版本仅供研究,不推荐日常使用。而且因为是易语言做的,容易被杀毒软件报告为病毒…

下载:季寻储存 | 百度网盘:dddd(解压密码 jixun

VirusTotal 查毒报告

  • v1 – 23/72 个杀毒软件报告为危险。
  • v2 – 20/72 个杀毒软件报告为危险。
  • v3 – 4/72 个杀毒软件报告为危险。

标准提取码格式

一行一个,每一行的数据如下:

<完整 MD5> # <片段 MD5> # <文件长度> # <文件名>

字段的说明如下:

  • 完整 MD5: 文件的整体 MD5 校验数据。
  • 片段 MD5: 文件前 256KiB 的 MD5 校验数据。
  • 文件长度: 文件的字节长度,纯数字。
  • 文件名 : 导入的文件名称。

合并起来就是下面这个样子(提取码仅供测试用途):

855E7B1A30C30612AF4EF48E98ADA278#3DF18E7BF1E05C9E40EA5B6E061FE4D8#295682048#LibreOffice_6.2.4_Win_x64.msi
85F1F1A093F7645985C5B87DB9D0411B#AB3E81997FB8E223EF9FDEA99AC3CBEF#156026792#xampp-windows-x64-7.3.6-1-VC15-installer.exe
828D08946421B5B2215625DEF1C7745E#D3A1FB7C331013ADC3E7BA46CF22F9A2#111087432#MeGUI-2896-32.zip
1C06E48C6A85C2FD6D1C0CF8BD57ABAF#C97B8AF390F4E50B0C13A3C7A6CD9A9C#59287984#Wireshark-win64-3.0.2.exe
C654643F3BCFBC305CA61151ED407DDA#D79939D48BAC90ADE0CA8EE922FD6EF6#785958680#android-studio-ide-192.6241897-windows.exe
CF5D5D149E4A6ECF993B720D4C3D5FE9#8032F875BDA5C2C6EC8DFDF25BCD5B32#170460680#VirtualBox-6.0.14-133895-Win.exe
70FDFA614E781514C37E3A990A2E3821#A414B184565F7B48FD6B192290F7F9FD#50930768#eclipse-inst-win64.exe

百度网盘标准提取码生成器最先出现在Jixun 项目集

Jixun's avatar

利用 Docker 来静态编译 ffmpeg

这篇文章是关于在 Linux 下使用 Docker 编译适用于 x86_64 架构的 ffmpeg 可执行文件,不包括 Windows 相关的内容。也许以后会做也说不定。

常见问题

问:为什么要自己构建?
答:使用非自由non-free授权的编码器(如:fdk-aac)。

问:为什么要用 docker 来构建?
答:不用额外在宿主机配置环境,直接编译就行了。

问:如何确保编译出来的文件能跨平台运行?
答:使用静态构建Static Build,将所有依赖内嵌到可执行文件里。

问:如何加入自己的编译参数或依赖?
答:直接建立一个新的 Dockerfile 并引入这个项目,或建立一个分支然后配置。

注意事项

因为包含了 non-free 的编解码器,因此编译后的文件只能自用而不能分享。

Docker 镜像

你可以访问 JixunMoe/ffmpeg-builder 来获取构建镜像所使用的 Dockerfile,或是直接拉取在 Docker Hub 上自动构建的镜像:

docker pull jixun/ffmpeg-builder

镜像准备好后就可以开始编译了:

OUTDIR="$(pwd)/bin"
mkdir -p "${OUTDIR}"
docker run --rm -v "${OUTDIR}:/build/bin" jixun/ffmpeg-builder

默认编译的版本是镜像编译时的最新版(4.2.3),或者你也可以添加参数来指定想编译的版本(不保证能成功):

docker run --rm -v "${OUTDIR}:/build/bin" jixun/ffmpeg-builder 4.2.3

最后就能在 $OUTDIR 里找到编译好的 ffmpegffprobe 文件了。

查看包含的编解码器

$ ./bin/ffmpeg -codecs | grep fdk
ffmpeg version 4.2.3 Copyright (c) 2000-2020 the FFmpeg developers
built with gcc 7 (Ubuntu 7.5.0-3ubuntu1~18.04)
configuration: --prefix=/usr --pkg-config-flags=--static --extra-cflags='-static -Wl,-Bdynamic,-lgcc_s,-Bstatic' --extra-ldflags=-static --extra-libs='-lpthread -lm' --bindir=/build/bin --enable-static --enable-gpl --enable-gnutls --enable-libass --enable-libfdk-aac --enable-libfreetype --enable-libmp3lame --enable-libopus --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-libbluray --enable-nonfree
libavutil 56. 31.100 / 56. 31.100
libavcodec 58. 54.100 / 58. 54.100
libavformat 58. 29.100 / 58. 29.100
libavdevice 58. 8.100 / 58. 8.100
libavfilter 7. 57.100 / 7. 57.100
libswscale 5. 5.100 / 5. 5.100
libswresample 3. 5.100 / 3. 5.100
libpostproc 55. 5.100 / 55. 5.100
DEA.L. aac AAC (Advanced Audio Coding) (decoders: aac aac_fixed libfdk_aac ) (encoders: aac libfdk_aac )

参考资料

  1. ffmpeg 官方的编译指南:https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu

利用 Docker 来静态编译 ffmpeg最先出现在Jixun 项目集

's avatar

狗粮!唔嗯……想要……还要更多!咳!

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


恋爱真是件美妙的事情呢。尽管要享受它,还必须得付出巨大的代价才行。得承担起两人份的责任,得照顾好对方的心情,得掌握好所有人的看法和态度,还得知道全方位的处理冲突的办法。但很幸运地,对于像黄鼠这样,不想付出代价又想吸收恋爱带来的甜美的人,我们还有替代方案——吃狗粮。

我们可以寻找虚构的故事。除了少数的例外,故事们一定都是被设计成读后会让人开心的。作家们用了全力,只为了将人物写得无比可爱,把交互写得超级幸福。即使有冲突,那也一定是会得到解决的,而在解决之时,他们也一定不会放弃机会,再让读者释放一次快乐的荷尔蒙。

黄鼠可以放心地、全力地喜欢虚构故事中的 CP 们,因为不用担心它们会令我失望——如果这是两个黄鼠不会喜欢的角色的话,那么从故事开始就会知道了。角色们的可爱是被刻意设计如此,因此是完全不用担心会消逝的。

而在现实中,我们也可以不劳而获地享受别人的恋爱带来的幸福感。现实中的情侣会秀恩爱,会撒狗粮——这是人之常情,得到了那样稀有的机会、付出了那样多的努力,黄鼠也一定会忍不住使劲炫耀的。

黄鼠通常来说,都认为自己是一个擅长接受狗粮的人。尽管有少数时候会有些许嫉妒,但那不重要,因为那是和自己无关的事情。面对别人的感情、别人的幸福,自己只要在周围开心的祝福就好了。狗粮发放者本人的的幸福,才是故事的主角。而自己能够免费蹭到这份幸福,是值得感谢的事情。

黄鼠看 YouTube ,在 YouTuber 们的镜头前,几乎每对人都是那样地美丽。他们互相扶持着,一同行进着,一起将美好展示给全世界的观众。在镜头之外也许仍然会有冲突,但那跟黄鼠无关,也无法获知,因此黄鼠不去思考它。

黄鼠看着 Veritasium 的 Derek 讲述自己的人生故事 ,那本身就是一篇很棒的、启发人的视频,而在其中 Derek 感谢到自己的妻子对自己的长期支持的时候,在提及两人相遇的时候,在视频中播放他们在从前求婚时在室外用手机录下的模糊录像的时候,那份狗粮是突然的,但是是美味的。幸福的感觉遍布了黄鼠全身,唯一能组织出来的语言,是“好棒啊,好想祝福”;唯一拥有的想法,就只有祝福他们在这样多年的时间后,依然能够持续这份幸福。

黄鼠看着 AkiJoey 的频道。看着这两位做着相似种类的视频的 YouTuber ,从乎不相干,到公布了跨越大洋的感情,再到现在生活在了一起,除了祝福他们以外,难道还有什么其他的事情可以思考吗?而在如今,两人已经频繁地在视频中互相出镜,互相提及一起做的事情,这样的生活成为了日常,这样的日常是多么令人向往呀。而黄鼠,除了感谢他们一直带来的有趣视频以外,就只有希望这美妙的日常可以继续下去了。

决不能忘记提及的是 Rachel and Jun 的频道。从这样的频道名称看来,还能指望更多的什么呢?几乎每一篇的视频,都是优质的狗粮。美妙的两人,被三只可爱的猫咪包围着。对着样的美妙生活,那是连嫉妒都难以做到的。

放下 YouTube ,黄鼠看了看自己所认识的人们,那也是一个大量的狗粮来源。黄鼠看着大家的幸福,自己也会被幸福感所感染。黄鼠自诩是一个思想开放的人,会接受各种各样关系,会理解他人各种各样的决定,会明白这是与自己无关,自己无权评判的事情。于是黄鼠享受着从他人借来的快乐,开心地祝福着他们。

至少,这是黄鼠认为自己应该做的事情,在所有时候。

但事实上,黄鼠并没有像自己想象中那样强的承受能力,也并没有能够完全保持开放的思想。黄鼠有时会私下评判别人的身份和行为,也会拿着自己个人的衡量标杆,去评判与自己完全无关、自己完全无权干涉的事情。黄鼠无法总是纯粹地享受狗粮而不添加自己的主见。

黄鼠会偷偷地给人打上“难以喜欢上”的标签,尽管这可能仅仅是依据于粗浅的认知。黄鼠会觉得某个人可能太高冷、太凶、说话不好听、做事太绝情。可是人家是独立、有权做自己的人,是不需要黄鼠的欣赏的。事实上,黄鼠的存在有可能令对方厌烦也说不定。

尽管是人家自己的事情,自己完全无权评判的事情,但是可笑地,黄鼠会觉得自己无法接受现实中一些人的配对。就像对虚构作品中自己不喜欢的 CP 一样,想“诶,为什么那两个人会在一起”。可是对虚构作品这样做是没关系的,因为他们是虚构的人,可是在现实中,每个人都是有自己独立的思想,有着自己的事才对。与谁在一起是别人自己思考做出的决定,这样子否定别人的人生决定,是太大的不尊重了。

黄鼠知道这是自己不该拥有的想法,所以想要尽量避免它。因为这样,黄鼠十分害怕获知自己在意的人的恋人。万一那是一个黄鼠“难以喜欢上”的人该怎么办?那样的话,黄鼠就会悄悄地否定它们了。尽管这一切都不是黄鼠有权去评判的事情。

黄鼠是充满控制欲的,不愿意面对不在自己控制中的事情。如果熟悉的人宣布了新开始的感情,却又不愿意让黄鼠了解他的恋人,黄鼠会觉得气愤。尽管黄鼠知道,这是人家自己的决定,人家自己私人的事情,不愿意分享明明是十分正常的。可是不平衡的内心,仍然会无法接受自己熟悉的人正在隐藏其十分重要的一面,并且将大量的经历与时间花费在这个隐藏的地方,黄鼠难以获知的事实。但显然,这样的想法是不能说出来的,只好让黄鼠自己活该地承受。

黄鼠更不愿意接受的,是来自特定的人的狗粮。

那其中包含着黄鼠对对方不了解的气愤。自己明明声称那样喜欢一个人,却不知道人家居然有认识来自其它地方的其他人。不能够完全了解一个人的信息来源,令黄鼠气得不断跺脚:“他们到底怎么认识的啊!为什么黄鼠不知道啊!”

黄鼠没有“为什么不是我”这样的想法,因为黄鼠明白,之所以不是自己,一定是有合理的原因的。黄鼠因此想要了解对方,希望能够使用和平的方式,来让自己内心的控制欲平衡一些。可是对方大概完全不会有想要被黄鼠了解的兴趣,更不用提黄鼠的动机了。

但这样的事情,能有什么经决方案呢?在黄鼠能够改变自己的想法之前,大概每次吃到那颗特定的狗粮后,只能够继续被这些禁忌的想法所围绕了。“为什么这个人能与这个人关系这样好”、“为什么我不能成为其中的一分子”,这些不该被提出,也不该被回答的问题,希望能够停止吧。黄鼠想要能够全心全意地吃狗粮,这是足够的,也是黄鼠唯一有权做的。 🐁


Image by Mat Coulton from Pixabay

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

's avatar

Hackthebox - Scavenger - 10.10.10.155 - Writeup

Hack The Box - Scavenger 解题过程及思路 Writeup
's avatar

Hackthebox - Magic - 10.10.10.185 - Writeup

Hack The Box - Magic 解题过程及思路 Writeup
ホロ's avatar

Chromium OS 和 Crostini 初体验

日常动机不明瞎折腾……

所以 Chromium OS 是啥?

Chromium OS是Google Chrome OS的开放源代码开发版本。 自2009年11月19日开始,Chrome OS以Chromium OS为名陆续发布其开发源代码, 并在遵守着BSD授权条款不断有新版本发布,并试图能够提供绝大多数长时间浏览 万维网的用户一个快速、方便且安全的操作系统。

历史上Chromium OS曾经整体是创建在以Linux核心为主的Ubuntu 4.10版本上,而操作系统的的软件包管理系统则是使用Gentoo Linux的Portage。 但是现在实际上只是单纯利用了Gentoo Linux 的 Portage 而独立编译出来的特制化 GNU/Linux 操作系统,而这个系统本身也与 Gentoo Linux 无关。

Wikipedia: Chromium OS

愿意的话当作一个核心是 Chromium 浏览器的操作系统也行……

于是 Chromium OS 大概像这个样子(嗯?)

AlisterTT's avatar

520的涂鸦

这两天在看寒蝉鸣泣之时,片子太血腥就干脆一边玩手机一边转移注意力,用sketches那个APP乱涂乱画,涂了个狐狸出来。

然后勾线上色,这粗手指头是真够累人的

刚好12点过了,到5月20日了,那就祝自己节日快乐好了,什么时候还能脱单嘛!!

依云's avatar

桥接无线网卡!

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

众所周知,大部分无线网卡是不支持桥接操作的。

但是 VirtualBox 就是能,因为它做了特殊处理:来回改 MAC。

那么,我的 LXCnetnsKVM 啥的也想这么玩,成不?

实际上不仅能成,而且 Debian Wiki 还给出了两个方案。方案一是用 ebtables 来回改 MAC。不过我失败了,可能是 ebtables 不支持改完 MAC 再把包发往另外的网络接口吧。

方案二是内核的一个叫 Proxy ARP 的功能。设置起来超级简单:往/proc/sys/net/ipv4/conf/all/proxy_arp里写1,然后给需要的 IP 地址加一条 /32 路由项就可以了。

这方案相比起 VirtualBox 来是非常手动了,也不支持 DHCP 自动配置的 IP 地址,但好歹能用。至少微信备份能用。(火狐的 Wi-Fi 远程调试已经坏掉了,倒是那个「USB 调试」其实只要 adb 连接上就能用,不一定要走 USB 线。)

ホロ's avatar

Windows Subsystem for Linux + DistroLauncher

利用 DistroLauncher 在 WSL 上运行自己喜欢的 GNU/Linux 发行版, ,例如还是咱喜欢的 Arch 🌝

复习(?):Windows Subsystem for Linux 是个啥玩意?

从 Windows 10 Insider Preview 开始,加入了 Windows Subsystem for Linux (适用于 Linux 的 Windows 子系统) 功能.

Windows Subsystem for Linux(简称WSL)是一个为在Windows 10上能够原生运行 Linux 二 进制可执行文件(ELF 格式)的兼容层。 它是由微软与 Canonical 公司合作开发,目标是使纯正的 …

依云's avatar

Linux 的进程优先级与 nice 值

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

假设有一个程序叫 use-cpu,它运行的时候会一直消耗一个 CPU 核心。试问,如果我开两个终端窗口,分别执行以下两个进程,其 CPU 会如何分配?

$ taskset 2 ./use-cpu
$ taskset 2 nice -n 10 ./use-cpu

两个进程都在1号CPU上运行,意味着它们必定争抢时间片。第二个进程使用 nice 命令设置其 nice 为 10,那么,是不是第二个进程会占用比较少的 CPU 呢?

很合情合理的推理,然而答案是否定的。

呃,也不一定。cat /proc/sys/kernel/sched_autogroup_enabled 看一下,这个开了的话,CPU 调度会多一个层级。默认是开的,所以这两个进程会均分 CPU 时间。

首先说好了呀,这里只讨论普通进程(SCHED_OTHER)的调度。实时进程啥的不考虑。当然啦,CPU 分配只发生在 R(Runnable)状态的进程之间,暂时用不到 CPU 的进程不管。

最上面的层级是 cgroups 了。按照 cgroup 层级,每一层的子组或者进程间按权重分配。对于 cgroups v1,权重文件是 cpu.shares;cgroups v2 则是 cpu.weight。不管用哪个版本的 cgroups,systemd 默认都没有做特别的设置的。对于 v1,大家全在根组里;对于 v2,CPU 控制器都没有启用。如果你去设置 systemd 单元的 CPUWeight 属性(或者旧的 CPUShares 属性),那么 systemd 就会开始用 cgroups 来分配 CPU 了。一个意外的状况是,使用 cgroups v2 时,systemd-run 不会自动启用上层组的 CPU 控制器,以至于如果上层未手动启用的话,设置不起作用。在使用 cgroups v1 时,用 systemd 设置 CPUWeight 或者 CPUShares 也不太好用,因为它并不会自动把进程挪到相应的层级里去……

其次就是这个默认会开的 autogroup。这个特性是为了提升交互式的桌面系统的性能而引入的,会把同一 session 的进程放一个组里。每个 autogroup 作为一个整体进行调度,每个 autogroup 也有个 nice 值,在 /proc/PID/autogroup 里可以看到,也可以 echo 一个想要的 nice 值进去。至于这个 session,不是 systemd 的那个 session,而是传统 UNIX 的那个 session,也是 setsid(2) 的那个 session。我一直以为它没多大作用,没想到在这里用上了。基本上,同一群进程会在同一个 session 里(比如一群火狐进程,或者一群 make 进程),同一个终端里跑的进程也都在一个 session 里(除非你 setsid 了)。

最后才是轮到进程。其实准确地讲是线程。同一个 autogroup 里的时间片如何分配,就看里边这些线程的 nice 值的大小了。所以其实,我系统里的那些高 nice 值的进程,由于 autogroup 的存在而它们又没有去设置 autogroup 的 nice 值,其实调度起来没什么差别的。

参考资料

  • man 7 sched
  • man 7 cgroups
imi415's avatar

STM32H7中的DMA

1. 概述

       STM32H7相比其他系列性能有着不小的提升,同时结构也有了较大的变化。这些变化如果不加注意则会影响DMA等功能的使用。本文通过对STM32H7的Bus Matrix及Cache/MPU两方面尝试分析不同点及对应的解决方案。

2.硬件平台

       本文中使用的硬件是STM32H750开发板,属于STM32H7 Value Line产品线,代码位于QSPI Flash中,通过XIP方式执行。

3. STM32H7的总线结构和访问规则

       STM32H7拥有三个不同的Bus Matrix,分别为D1,D2与D3。

  • D1区域为AXI  Interconnect Matrix,与CPU通过AXI总线相连,高速外设如Flash,QSPI,FMC等通过此AXI Bus连接到CPU,速度最快。
  • D2区域为AHB Multi-layer Bus Matrix,连接了大部分低速外设及另一部分SRAM,通过CPU的AHBP接口连接到CPU,速度其次。
  • D3区域为另一个AHB Bus Matrix,与前两个区域不同的是,它不与CPU直接连接,而是通过D2区域的一个AHB Master连接到D3区域。D3区域速度最慢,同时也连接了一部分低功耗外设,速度最慢。

三个区域的时钟及门控可独立控制,以实现低功耗与高性能间的平衡。

在H7的架构中,部分高速外设通过AXI总线连接到Master,相比只有Flash存储器连接到AXI接口的F7系列,外设访问速度也有了提升。

STM32H7的总线互联架构

从上图我们可以发现以下访问规律:

  • D1区域的Bus Master可以通过D1-to-D2 AHB bus访问D2域的地址范围,也可以通过D2-to-D3 AHB bus访问D3的地址范围。
  • D2区域的Bus Master可以通过D2-to-D3 AHB bus访问D3域的地址范围,也可以通过D2-to-D1 AHB bus反向访问D1域的地址范围。
  • D3区域没有连接到其他区域的Bus Master,因此只能访问D3区域的地址范围。

总结一下就是:

D1与D2中的Bus Master可以互访对方Slave, D3中的Master不能访问D1与D2 Slave

4. STM32H7中的DMA与存储器

STM32H7中有三种不同的DMA,分别为MDMA,DMA(DMA1/DMA2)以及BDMA,其特点如下所示:

  • MDMA可以通过AXI Interconnect的接口访问D1域,同时能通过专用的AHBS接口访问CPU中的I/DTCM存储器,速度最高。
  • DMA1/2位于D2域中,通过AHB接口访问D2域。由于D2域存在着连接到D1域的通路,因此DMA1/2依然可以访问D1域中的存储器及外设。
  • BDMA则位于D3域中,仅可以访问D3SRAM及对应的D3域外设,同时功能上也相对有限。

相似的,STM32H7中的存储器也分为了以下几种:

  • AXI SRAM(D1_RAM),QUADSPI,FMC,Flash:这些存储器连接到AXI Interconnect,可被能访问D1域的Bus Master访问。
  • AHB SRAM1/2 :这些存储器连接到D2域 AHB Bus Matrix,可被能访问D2域的Bus Master访问。
  • AHB SRAM3:这些存储器连接到D3域 AHB Bus Matrix,可被能访问D3域的Bus Master访问。
  • 特殊的,位于CPU内部的I/DTCM(指令/数据紧耦合存储器)在可被CPU访问的同时也可通过专用接口被MDMA访问。

由此,我们可以得出以下几点规则:

MDMA能访问包含TCM在内的所有存储器(几乎和CPU范围类似),DMA1/2不能访问TCM,BDMA仅可访问AHB SRAM3以及D3域外设。
特别需要注意的是,这些规则不仅应用于DMA控制器,同时也适用于其他Bus Master,如DMA2D,LTDC,Ethernet,SDMMC,USB等等拥有内部DMA的外设,使用时同样要保证用户buffer位于可访问区域内。

5. 关于L1 Cache及MPU

Cortex-M7相比于其他核心,增加了单独的L1 I/D Cache,为了保证DMA访问的内存不出现一致性问题,需要通过配置MPU的方式控制指定区域的缓存策略。

Cortex-M7的MPU通过Region的形式定义访问规则,这里通过STM32CubeMX的配置工具提供简单的缓存配置示例。

CubeMX的MPU配置界面

MPU的配置最好按照粒度从粗到细的顺序配置,示例中的默认配置是禁用缓存,允许全部访问,在QSPI Flash区域启用读缓存,并允许指令访问及共享。

6. 代码实现

在默认的Linker Script中,数据代码被放置在了DTCM中,如果想要通过DMA访问这部分数据,我们就只能通过MDMA访问,或者修改LDS使得数据放置在AXI SRAM或者AHB SRAM中。以下的修改可以将用户的buffer放置在D2域SRAM中:

  _SI_D2SRAM = LOADADDR(.d2_sram);
  .d2_sram :
  {
    . = ALIGN(4);
    _DMA_Buffer_Start = .;
    *(.d2_sram_buffer)
    . = ALIGN(4);
    _DMA_Buffer_End = .;
  } >RAM_D2 AT> FLASH /* Note: Not actually init, we need to copy manually before use */

然后我们即可初始化这部分数据:

    uint32_t bytes_to_copy = &_DMA_Buffer_End - &_DMA_Buffer_Start;
    if(bytes_to_copy != 0) {
        memcpy((void *)&_DMA_Buffer_Start, (void *)&_SI_D2SRAM, bytes_to_copy);
    }

之后通过DMA1或DMA2即可正确实现DMA传输。

依云's avatar

Intel GVT-g 初体验

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

准备 GVT-g

把 kvmgt vfio-iommu-type1 vfio-mdev 这仨加到 /etc/mkinitcpio.confMODULES 数组里去。mkinitcpio -P 重新生成一下 initramfs。

添加内核参数 i915.enable_gvt=1。比如是 grub 引导就去改 /etc/default/grub 里的 GRUB_CMDLINE_LINUX 变量,然后 grub-mkconfig ...

去把 /etc/systemd/system.conf 里的 DefaultLimitMEMLOCK 给改了。比如 DefaultLimitMEMLOCK=65536:1073741824

重启。

这个时候应该已经有 /sys/devices/pciXXXX:XX/XXXX:XXXX.X/mdev_supported_types 这个目录了。里边有好几个选项呢。选择一下合适的(查看 description 文件),然后往里边的 create 文件里写一个 UUID 就创建了。

启动 KVM 虚拟机

呃,如果你还没有磁盘镜像就自己 qemu-img 创建一个,然后装机。如果你有别的虚拟机的,也可以用 qemu-img 去转格式。

另外准备一下网络。我早就有个网桥了,所以直接用它了。在 /etc/qemu/bridge.conf 里写一句 allow br0 不然不给用的,毕竟我是普通用户权限而网络接口是要 root 权限操作的,得明确允许一下。

我尽可能地使用了 virtio,据说性能好(VirtualBox 也支持一部分了呢)。如果用已有的虚拟机系统但以前没用过 virtio 的话,记得用 fallback 那个 initramfs 启动,然后进系统之后重新生成一个。

我给分配了四个逻辑 CPU 核,4G 内存。VGA 要关掉,不然两个显卡用起来麻烦。为了避免部分内容显示到别处去(如果关了 VGA 的话就看不到,否则能在默认的那个上看到),要加上 ramfb=on,driver=vfio-pci-nohotplug 选项。

声音当然是要的。添加个 PulseAudio 后端,一张 HDA 声卡。我不懂声卡型号所以找了个顺眼的,能用就好。

合起来是这样子的(那两个省略号,一个是磁盘镜像路径,一个是创建 vGPU 用的 UUID):

#!/bin/bash -e

ulimit -l 1024000

exec qemu-system-x86_64 -enable-kvm \
       -name "ArchKDE" \
       -cpu host -smp 4 \
       -m 4G \
       -drive file=/.../ArchLinuxKDE.qcow2,if=virtio \
       -netdev bridge,id=eth0,br=br0 \
       -device virtio-net,netdev=eth0 \
       -device vfio-pci,sysfsdev=/sys/bus/mdev/devices/...,display=on,x-igd-opregion=on,ramfb=on,driver=vfio-pci-nohotplug \
       -vga none \
       -display gtk,gl=on \
       -audiodev pa,id=pa0,server=/run/user/$UID/pulse/native -device intel-hda -device hda-output,audiodev=pa0 \
       "$@"

如果你使用 GVT-g 显卡的时候整个系统都卡卡卡的话,去看一下宿主的内核日志,是不是有 vfio_pin_page_external: Task qemu-system-x86 (257364) RLIMIT_MEMLOCK (104857600) exceeded 这样的提示,然后去把 RLIMIT_MEMLOCK 给调大,大到它不再报这个错为止。我最后给了1000M才终于不报错地把 KDE 给跑起来了(默认是64K)。

当然如果你没有 GVT-g 支持的话,去掉那行配置,然后 -vga virtio 也能用。

参考链接

imi415's avatar

使用SystemView分析FreeRTOS应用

免费的RTOS Tracealyzer,SEGGER大法好
17windy's avatar

练手/找感觉 自制1080P壁纸收集与下载 汇总

要改掉练完就扔的坏习惯,慢慢积累一下。 /但是不会存源文件,因此都是很难重制。

夏夕 0614 For the Life (Remix) #明日方舟 For the Life #明日方舟 泰拉大地的挽歌 #明日方舟 泰拉大地的挽歌 #明日方舟 梦觉流莺。 去,不要说再见。 聚。 破。 挖矿与吃货。 薄暮之城。 傍晚时分。 傍晚时分。 五月病。 抗僵尸能力低下。
ホロ's avatar

切点洋葱 - 搭建一个洋葱服务

“如果你愿意一层一层剥开我的心……”

所以洋葱服务(Onion Service)是啥?

洋葱服务 (Onion Service ,旧名为“隐身服务/隐藏服务/ Hidden Service”) 是一种只能透过洋葱路由网络访问的网络服务 (例如网站)。

那么有人为啥要使用洋葱服务呢?

  • 洋葱服务在 Tor 网络中传递,因此可以隐藏服务器的真实地址(例如 IP 地址和地理位置等等)。
  • Tor 用户与洋葱服务之间所有的流量都是端到端加密的,所以汝不必担心像没有 HTTPS 这样的问题。
  • 洋葱服务的网址是为自动生成,因此网站的架设者或管理员无需另行购买网络域名。其网址皆是以 .onion 结尾的, 这样的设计可以让洋葱路由系统确保所有网络连接都通往正确的站点,并且其连接数据未被窜改。

访问一个洋葱服务网站时,除了一般 Tor 网络中会经过的节点以外,还会额外通过若干个中继。 (图上的是 DuckDuckGo 提供的洋葱服务 https://3g2upl4pq6kufc4m.onion/

我需要搭建一个洋葱服务么?

如果汝遇到了这些情况,那汝大概会对如何搭建一个洋葱服务引起兴趣(大概吧……):

  • 匿名、不被截获和篡改的传输一个文件。(正好有 OnionShare 可以帮忙这么做)。
  • 在没有公共 IP 地址(甚至没有域名)的情况下提供 Web 服务。
  • 匿名的和另一位匿名者交流。
  • 汝也重视汝的读者的隐私权。 (要是汝不是作者怎么办?)
  • 或者别的? (详见:Tor at the Heart

切洋葱之前当然要做好保护措施啊……

于是亦然(?),要搭建一个洋葱服务的话,首先要有一个能够正常连接的 Tor 。

介于应该没人会一直开着个浏览器(?),所以最好是有个独立的 Tor 在运行(就是那啥所谓的 Expert Bundle 啦……)。

以及现在用 GNU/Linux 提供 Web 服务的家伙应该不少吧,于是汝大概能从汝所使用的 GNU/Linux 发行版的 软件仓库中找到 tor:

准备一个 Web 服务

这个就看人下菜了(?),如果有只用洋葱服务访问的需要的话,可以调整 Web 服务器的配置文件, 让她只接受本地地址的连接。 例如 Nginx 和 Apache 的话,大概可以这么做:

listen localhost:8000;

不放心的话还可以用防火墙啊(x)

生成一个洋葱服务地址

洋葱服务使用的 .onion 地址是随机产生的,地址是在配置洋葱服务时用新生成的公钥计算而成的。 所以叫做“生成”而不是注册,以及虽然有方法可以提前算出来生成特定地址的公钥但是不建议尝试……

用汝最顺手的编辑器和 root 权限(?)打开 Tor 的配置文件(通常是 /etc/tor/torrc ), 然后加上这些:

# 每个不同的洋葱服务都需要一个独立的文件夹来存储其所需要的私钥和主机名,
# 要创建不同的洋葱服务时,需要修改 HiddenServiceDir 所指向的文件夹。
#(注:不要手动创建 HiddenServiceDir 的路径,否则会出现权限的错误而无法启动。
# 在配置完成后启动 Tor 后,程序会自动生成权限合适的对应文件夹。)

HiddenServiceDir /var/lib/tor/path_to_your_service

# HiddenServicePort {汝希望汝的洋葱服务开在哪个端口上} {汝这个端口的洋葱服务交给谁处理}

HiddenServicePort 80 127.0.0.1:8080

保存完毕后重新启动 Tor ,如果一切 OK 的话,可以在汝设置的 HiddenServiceDir 中看到一个 名为 hostname 的文件,里面就是汝新鲜的洋葱服务的域名啦~

同时提供普通网络服务和洋葱服务时?

  • 可以考虑让来自 Tor 的出口 IP 地址的连接自动重定向至洋葱服务地址,例如 这样
  • 也有可能需要调整汝的应用(或者主题什么别的)来适应洋葱服务和 Tor 浏览器。

更进一步?读读看这些文章

当然都只有英文版(汗)

你会鼻酸,你会流泪……

ホロ's avatar

在 Android 上创建 GNU/Linux 容器

那这次再说吧……

再一次提醒没有耐心和同理心的家伙们去用其它即用的工具像是 TermuxArch 和 Linux Deploy ……

所以这回咱们要干什么?

由于咱不可能把所有发行版都装一次,也不可能在各种手机上都测试一遍,于是咱只能拿 咱手边的家伙举个例子,例如咱手上的小米平板4 ……

  • 一部 aarch64 / arm64 设备

现在的手机 CPU 基本上都是 64 位了吧,不知道的话搜索一下手上 CPU 的型号应该就能看个大概。

  • 比较新的 Android 系统,最好有 root 权限和完整 busybox 支持。

如果汝已经动手给手机安装了第三方 ROM,那应该不是什么难事。 某蓝绿海厂等受害者可以尝试 UserLAnd……

  • 一些剩余存储空间 (这不是废话么)
  • 安装好终端模拟器和合适的键盘。

或者 Termux 也可以,在里面装上 tsu 以后可以让 Termux 里的 Bash 以 …

ホロ's avatar

在 Android 上使用 GNU/Linux 工具

虽然……

虽然汝可能从哪里听说过 Android 是基于 Linux 内核的啦,不过大多数时候汝大概没办法直接把汝爱用的 GNU/Linux 发行版上的 工具直接拿过来用,为啥咧?

  • 手机和电脑不是一种 CPU(PC 常见的就是 x86_64 , 手机上比较常见的是 arm64(有时也称作 aarch64)),因此 两边的二进制文件并不能直接拿来换着用。
  • 虽然 Android 用了 Linux 内核,但是和普通的 GNU/Linux 发行版还是有很大的区别的。例如以 bionic 取代glibc (C 函数库)、以 Skia 取代 Cairo (用于向量图形绘图)、再以 OpenCORE 取代 FFmpeg(常用于音视频的录影和转换)。 于是不少依赖它们的软件不好运行。
  • 以及随着越来越多的 GNU/Linux 发行版开始用 Systemd 作为初始化程序,很多程序或多或少就和 Systemd 有了些关联(或者依赖)。 不巧的是……

所以 Android 应用们不好用了么?

STAGE 0 - Android 上的终端(模拟器)

如果汝有用过一些需要在电脑上运行一个辅助程序的 Android 应用(像是 AppOps 这样的),汝其实已经离 Shell 很近了。

在手机和电脑连接以后,可以运行 adb shell 命令获得一个 shell:

(PC) $ adb shell
walleye:/ $

接下来就可以 cd ls 乱出了…… (啥?) 因为别的汝也干不了啊……

如果汝的手机有 root 权限的话,在 Shell 里运行 su 试试?第一次的话汝的手机上的 root 权限管理程序应该会提示汝授予权限什么的。

要想在手机上试试的话,也有差不多的终端模拟器程序可以选择。 例如这个?

STAGE 1 - 在 Android 上使用(部份) GNU/Linux 程序

只有个 shell 哪里够……

正好也有一群人这么想,于是它们把终端模拟器和一些常用的 GNU/Linux 应用程序组合起来,创造出了 Termux

(这个在电脑上显示 Android 设备画面的程序是 scrcpy 啦~)

这里面提到的 pkg 其实就是有点小包装的 apt 啦,熟悉 Debian / Ubuntu 的话应该不会陌生。

下面的 root / Unstable / x11 是额外的仓库,需要使用要求 root 权限或者图形界面的软件在里面。

  • Play 商店上也有几个 Termux 使用的插件,可以实现自定义字体、浮动窗口、快速运行脚本、访问手机内存设备 等功能。有几个是收费的,不过有别的地方可以免费下载(小声)
  • 键盘上面的特殊按键可以通过编辑 ~/.termux/termux.properties 文件中的 extra-keys 属性来修改, 特殊键的定义在这里。
  • 偷懒的话也可以直接安装一个有这些特殊键的输入法,例如 Hacker's Keyboard
  • 当然外接键盘也是可以的。

以及大概有人踩过了不少的坑的样子……

STAGE 2 - 在 Android 上运行(部份) GNU/Linux 容器

啊 pkg/apt 好不习惯……

怀念汝习惯的 GNU/Linux 发行版的原汁原味的包管理器和其它工具?可以考虑运行一个容器来解馋(?)

Linux® 容器是与系统其他部分隔离开的一系列进程。运行这些进程所需的所有文件都由另一个镜像提供, 这意味着从开发到测试再到生产的整个过程中,Linux 容器都具有可移植性和一致性。

RedHat : 什么是 Linux 容器?

实现这种操作的关键要素就是 chroot ,它针对正在运作的软件行程和它的子进程,改变它外显的根目录。 在使用 chroot 之后,进程就会认为设置的目录是根目录,就可以进行各种操作啦,例如隔离访问或者修复系统什么的。

当然这操作是要 root 权限的,至于后来有人写出用户空间中的 proot ,就是另一个故事啦……

  • 手机有 root 权限的话,可以用 chroot 安装一个 GNU/Linux 容器。也有像是 Linux Deploy 这样的应用可以简化这一过程。
  • 没有 root 权限的话,借助前面提起的 proot 也能实现差不多的操作。也有像是 UserLAndTermuxArch 这样的工具帮忙简化这一过程。

以及大概也有人踩过了不少的坑的样子……

那如果咱就是想从零(?)开始呢?

那下次再说吧……

OX's avatar

斐訊R1智障音箱通過adb調試介面安裝apk實現AirPlay和DLNA功能

因為揀垃圾是一件很快樂的事情,一年前(2019年)我特意從中國大陸的網站上購買了很多斐訊遺產,其中就包括斐訊R1音箱,通過重重困難飄洋過海轉運到了日本。

剛剛拿到手的R1音箱是沒有拆封的,不同時期生產的R1音箱,內置的韌體(ROM)版本是不一樣的,舊版本的韌體音質校準不是特別理想,需要通過DNS劫持、push工廠配置文件等等的方法升級到最新版本,網絡上有很多教程,有需要的人可以Google一下,應該馬上就可以找到。

廢話不多説,下面是正題:

如何通過adb調試介面安裝App?

首先要找到斐訊R1音箱的IP位址。

有很多方法,比如查看路由器的DHCP分配位址表:

Host Name是「Phicomm_R1」開頭的就是斐訊R1音箱

知道斐訊R1的IP位址之後,用adb連接它!

OX-Macbook:~ ox$ adb connect 192.168.0.40
connected to 192.168.0.40:5555

然後用adb push命令把需要安裝的apk推送到音箱上:

adb push [apk文件所在的本地路徑] /data/local/tmp/

// 比如這樣:
// adb push /Users/ox/Desktop/airplay.apk /data/local/tmp/

然後通過調用pm工具安裝剛才push的apk安裝包:

adb shell /system/bin/pm install -t /data/local/tmp/[文件名]
額外提醒

如果你不知道轉義字符是什麼東西,那你的文件名最好不要有奇怪的字符,比如空格和括號之類的。

安裝AirPlay接收端

「樂播投屏TV版」和「AirPin」還有「Media Center」我都在用。

AirPin 是收費的App,但是也有免費的版本(AirPin Lite),在R1上用的話已經足夠了。

樂播投屏TV版 是免費的App,但是會上傳MAC地址之類的隱私內容,有時候還會擅自更新,新版本的樂播投屏TV版每次新設備連接都需要點擊允許,沒有屏幕的R1音箱就只能通過scrcpy之類的工具連接到R1之後手動點擊允許,非常麻煩,介意的話可以安裝舊版本的同時在路由器上屏蔽樂播投屏的服務器(*.hpplay.cn)。

Media Center 是免費的App,不過似乎穩定性不是特別好,但是非常輕量。

安裝DLNA接受端

上面提到的三個Apps都支援DLNA功能,自己選一個用吧。

使用scrcpy操作R1音箱的UI介面

雖然用adb調試介面可以完成大多數操作,但是比如像更改AirPlay的顯示名稱之類的操作,還是需要GUI操作,因為R1沒有屏幕,所以需要用到一些可以遠端操作Android GUI介面的工具,比如scrcpy。

scrcpy的GitHub倉庫地址:https://github.com/Genymobile/scrcpy

Windows版本在這裏可以找到。

Linux和macOS可以通過包管理器很方便地安裝,具體參考這裏

使用方法極其簡單:以macOS為例,先用adb connect命令連接到R1音箱之後,再執行scrcpy就可以了。

比如像這樣:

OX-MacBook:~ ox$ adb connect 192.168.0.40
connected to 192.168.0.40:5555
OX-Macbook:~ ox$ scrcpy
使用scrapy連接斐訊R1音箱 更改Media Center的設備顯示名稱 打開Media Center的AirPlay功能和設定R1音箱啟動後自動打開AirPlay伺服器

三款App的下載地址

樂播投屏TV版舊版本:Download

AirPin Lite:Download

Media Center:Download

這篇文章 斐訊R1智障音箱通過adb調試介面安裝apk實現AirPlay和DLNA功能 最早出現於 OXの胡說八道

ホロ's avatar

两次理想主义的尝试

几月不见甚是想念…… 会这么想的肯定是没看 咱的 Matters 啦…… (虽然那边也沉寂了好一阵子), 以及「集合啦!动物森友会」真好玩……

所以“两次理想主义的尝试”中的其中一次是什么?

在赞助了 Utopiosphere「本格异想录」 的会员计划之后,咱打算推出咱自己的会员计划了。

诶???

为啥开始寻求赞助啦?

因为穷.png

不像公众号、文章平台等可以"免费"存放内容(虽然汝和汝的读者可能会因为免费付出 其它的代价,例如自由和广告什么的……),独立博客是需要博主自己付出一定的成本来 维持运转的(例如域名和存放内容的地方)。

虽然咱前几个月终于悟出了 Likecoin 的赞赏键其实就是一个 iframe, 然后把它“移植” 到了这里,不过这几个月咱也没在这边写什么的样子,于是也形同虚设了(hmmmm)

最后还有咱自己的一点个人(?)原因,希望能得到一些声音(嗯?),咱当然也是有 回报可以拿出来的啦……

赞助者可以获得的回报有?

咱不知道还有啥词汇可以描述这群人了……

在写完这篇文章的时候,咱能够想到的大概有这些:

  • 优先阅读咱的拙作(诶?以及对于会员计划来说这好像很平常啊)

其实咱有好几次都是有好几个想法不知道先写那一篇,然后就咕咕咕了……这样大概 能让咱知道大家更想看到哪一篇,以及鞭策咱不要咕咕咕(x)

  • 某些方面的咨询服务(诶??)

只要是咱能够帮的上忙的地方,咱会努力。以及既然收了钱就会接纳(几乎全部)咱觉得 (有些)蠢的问题……

至于其它的嘛,让咱再想想……

赞助的方式?

还是草案(首先要有人愿意赞助……)
  • 「异想星空」 那边用了爱发电,看着就像有本地化的 Patreon ……
  • 在有了一些数字货币(就是 Likecoin 啦……)以后,也有意愿接收数字货币赞助 (但是有人愿意出嘛)
  • 以及可能会有优惠?

那另一次又是什么?

啊没错,咱又双想把 某个咱之前挖的大坑 的铲子捡起来了。

那么这个想法是怎么想起来的呢?

忘了……依稀还记得有一天吐槽过中文的 GNU/Linux 教程几乎都是默认用户只会用 GNU/Linux 来架设服务的那种。以及觉着 鸟哥的Linux私房菜 虽然写的很不错,但是是用的 CentOS 当作的教学范本……

于是就有想法写一部和 GNU/Linux 日常使用相关的手册的想法就这么产生了。

咱的目标是什么呢?

简单来说,咱有计划完成一部 GNU/Linux 桌面应用相关的手册,那具体有哪些方面呢?

  • 了解和 GNU/Linux 相关的一些概念
  • 自己动手安装 GNU/Linux 发行版
  • 使用 GNU/Linux 完成某些操作 (不只是运行服务)

具体的细节可以去看 咱之前的计划

自由的理想

作为 并不纯的 自由软件爱好者,咱也十分理想的想这么做:

  • 使用一个 完全自由的 GNU/Linux 发行版 作为范本,然而中途一度退而求其次的换掉了……
  • 以及尽可能的只用自由软件进行教学(?),虽然有些地方肯定不可能……
  • 以及想提醒大家稍稍关注一下隐私和安全意识(希望如此……)

但是……


大家快来投币(?)催咱不要咕咕咕啊……

想要了解两个之一(或全部)的更多细节的话,欢迎来咱的 Telegram 群交流更多细节:

链接在这里 ,如果链接失效的话 那就 @咱 请求链接好了。

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

https://afdian.net/@KenOokamiHoro
-----BEGIN PGP SIGNATURE-----

iHUEARYIAB0WIQQRcWZ9dT8okL6OyLwb09jRlMdzdQUCXpwxZgAKCRAb09jRlMdz
dVFQAQDjUk6b9H8MJaOV7+cX8ssyyBBdh3SsM1I/Sp2LK1S3fAD9HRR9ZzEv0CJR
OvdcglAV5zI9Lj1pRjGQvOti7VFaPwk=
=ygU/
-----END PGP SIGNATURE-----
Chawye Hsu's avatar

十款好评如潮的独立游戏与十张一定要听的原声带

在起笔写这篇文章之时,我看了下我的 Steam 帐号最近的一次启动游戏距离现在又过去了一段 6 个月的时间。我果然并不是一个极其热衷于玩游戏的「游戏热爱者」—— 即使在网易公司熏陶了几年下来,我也并没有过上像同事朋友那样在朋友圈刷屏的“动森”生活。手游就更加谈不上来…… 但就像每日三餐那样,我还有一个每天必定要汲取(至少 1.5 个小时)的精神食粮 —— 音乐,能够让我时常记着我那个玩了几百小时新手级别的《以撒的结合:重生》,还有几十个成就没有解锁,以及一堆还在愿望单里的好游戏。原来我这个早早过气的云村达人不止听电子、流行,还对游戏原声有强烈的嗜好,就像对 Future Funk、合成器浪潮那样。于是,听那些没时间、没队友玩的游戏的 OST,便成了我在通勤或者闲时“感受游戏”的方式。于是,又写音乐相关的内容了。
's avatar

天亮啦!动物森友会

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


一次在游戏中的合照,除最左村民外,从左至又依次是:芙兰,黄鼠,奎妮,萌狼, Cocoa

“动物之森?那样无聊的游戏,我还是不要浪费更多时间和金钱了吧”,第一次看到许多人为即将推出的新游戏《集合啦!动物森友会》兴奋时,黄鼠这样想到。

但这风潮似乎远比想象中更大,越来越多的玩家开始考虑是否要入手这部游戏,而其中的一些,已经开始他们的无人岛生活了。一位同样看到这场风潮,正在捉拿不定的朋友询问黄鼠会不会购买,不过黄鼠同样给出了否定的回答。

而黄鼠觉得这部游戏会无聊,也不仅是凭借粗浅从预告片看到的感觉呢。在蛮久之前,黄鼠曾使用 NDS 模拟器玩过一点《欢迎来到动物之森》,就觉得好无聊,没有玩很久就放弃了。所以这次在同样的系列发布新作的时候,黄鼠也继续认为新作会同样地无聊。

但是越来越多的人开始跳上前往无人岛的飞机了。在发售之后的一天下午,忍不住黄鼠一咬牙,决定也要冲动消费了!临时地赶在最近的百货商店关门之前,从货架上拎走了一盒《集合啦!动物森友会》。

在那之后,黄鼠的行为就变得和王镜泽一样了。

整一天的时间,几乎有做的唯一事情,就是在玩动物之森。本身就因为学校停课、整天呆在家里而变得混乱的作息,被动物之森加速成为几乎完全的黑白颠倒了。每天的睡觉时间成为了凌晨 7:00 ,起床时间成为了下午 16:30 (±3 小时)。在睡觉之前,黄鼠会望一眼窗外的天空,感叹道:“呀,天亮了呢。”


动物之森让黄鼠的作息更快坏掉、让黄鼠无法及时学习、让黄鼠整理房间的计划更加延后——这些游戏带来的坏影响,是实实在在的,不过在这里,黄鼠想要讨论的不是这些话题。

黄鼠想要讨论的,是关于人的话题。

无需质疑,动物之森使得许多平常几乎不会有交集的朋友得到了非常丰富的交流机会。平时完全没有理由说上一句话,在交流关于游戏的时候却有了许多的内容。即使只是简单的日常业务性对话,像是询问大头菜价格和交换水果,在这样的来往间,创造的羁绊大概也是存在的。

黄鼠得以了解许多可爱的人——动物之森是一个能够通过设计和搭配表达个性的游戏,每个人都拥有着的漂亮的室外景观和室内装饰,还有各种各样的可爱衣服可以收集。这是难得的体验。

可是在享受着玩家之间互相游玩的乐趣之后,黄鼠总是无法停止想到游戏所带来的排他性。在 Switch 持有者之间、在动物之森持有者之间,这部游戏让大家联系地更紧密,可是更多的没有游戏或没有主机的人,却被悄悄地排除在外了。

本身就不是联系很紧密的人群,现在被进一步分割成为了“动森玩家”和“非动森玩家”。而在意动森玩家的非动森玩家,在几乎所有人都在讨论一个自己不懂的事物的时候,大概会有很大的被排挤的感受吧。这样的感受也是黄鼠在许多人都在讨论技术话题的时候,不停地感受到的。对于本身就已经充满焦虑的人而言,这是最不想要的东西之一了。

黄鼠在意着非动森玩家的成员,但作为一个需要 Switch 主机才可以玩到的游戏,想要同时玩到实在是太大的投入了。黄鼠曾构思了一个可以让网络上的人远程玩 Switch 的计划,利用微控制器模拟手柄键入远程玩家的输入,同时利用采集卡或摄像头将画面实时传输给对方。那大概是一个可行的计划,但一定会很复杂吧,而且网络延迟也许会使游戏体验差到无法接受。似乎没有更多人有兴趣的计划,黄鼠也没有动力开始做了。

黄鼠在玩着动物之森。在接近着其他玩家的同时,却不知觉地也在同时疏远更多人呢。这样一个难得的交流的理由,却无法在更多在意的人身上使用。这样的事实,令人担心呢。 🐁


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

RecursiveG's avatar

WinRAR 恢复记录添加及使用教程

本文中的所有图片及文字均使用 CC0 发布,可任意转载使用。

本文属于疫情期间的摸鱼之作,旨在推广 RAR 压缩格式的正确压缩方法,让资源分享更轻松一些。

获取 WinRAR

先说一下为什么用 WinRAR 而不用 7zip, 因为 7zip 没有恢复记录。在百度网盘等平台分享文件时,文件可能发生损坏,没有恢复记录的话只能尝试重新下载浪费时间,而有恢复记录的话有大概率可以成功修复,正确解压。

国内特供版的 WinRAR 可以免费使用,但是有广告。如果不想要广告,你可以从以下链接下载官方无广告简体中文版

https://www.win-rar.com/fileadmin/winrar-versions/sc/sc20200409/rrlb/winrar-x64-590sc.exe

注意,如果你没有rarreg.key文件进行注册的话依然是有广告的。至于具体的注册方法请自行搜寻。

添加恢复记录

恢复记录需要在创建压缩文件时添加,你需要先勾选添加恢复记录复选框。

然后检查恢复记录的百分比设置。

对于大于 100MB 的大型文件文件来说,默认的 3% 足够使用。如果你的文件非常小,比如只有 几MB 或者 十几MB 你可以考虑增加到 5%。增大这项设置会同时增大文件体积,因此不建议设置得过大,尤其是对于几个 GB 的文件来说。如果你在压缩时忘记添加恢复记录或者是想要修改恢复记录的大小,也可以在事后进行操作:

损坏压缩文件的修复

如果你在解压时遇到“校验和错误”,那么你下载到的压缩文件就是损坏了:

你可以使用“工具”菜单尝试修复它。修复操作会生成一个新的,修复好的压缩包,你需要选择这个新文件的保存位置:

稍等片刻就会生成一个修复后的文件:

你也有可能在修复过程中遇到错误,但只要修复后的文件可以正确解压不报错,就没有问题。
但是只有添加了恢复记录的文件可以使用修复操作,因此所有人在压缩时都添加恢复记录是非常重要的。
如果修复后的文件依然不能正确解压,要么是损坏的部分过多无法修复,要么是资源发布者没有添加恢复记录。
在这种情况下就只能重新下载试试了。

给压缩文件加密

给压缩文件加密是防止文件被和谐的重要方法之一。

分卷压缩

如果你要分享一个非常巨大的压缩包,比如说十几个GB,直接作为一个文件分享一般不是一个好主意,因为下载者有可能下载到中途失败,不得不从头再来。将大压缩包切分成多个较小的文件可以有效减少这种情况的发生。

Linux 用户?

  • 很不幸地,创建或是修复带恢复记录的压缩包都需要rar而不是unrar
  • 如果遇到压缩包包含了文件名过长的文件,可以尝试创建一个 NTFS 格式的磁盘文件,用回环挂载,然后把文件解压进去。
AlisterTT's avatar

我们村的小伙贾洛斯

这两天在玩动物森友会,里面可以邀请很多小动物来岛上居住,其中有一只棕色的绵羊,穿的衣服颜色好像是刚果还是玻利维亚的国旗。

骚话特别多,家里的家具也特别多,特别阔绰,所以我称之为非洲王子。

岛上限制只能居住10个村民,我是一直打算把最后一个居民位留给amiibo的彭花(Rosie)的,结果彭花还没来,居民位已经满了,没办法只能赶走一个人。

正常流程是需要欺负居民,或者好感度非常高的时候对方才会搬走,这都是我不愿意看到的,刚好amiibo的特殊原因可以强制让居民迁走,就选择了才来没几天的杜美。

amiibo的强制交涉 杜美在收拾家具,第二天会离开

本来看到一个没怎么说话的村民要搬走,也没什么感觉,直到在村广场碰见了贾洛斯。他说,杜美要搬走了,希望以后还会相见,所以此时也不会说再见,而是想说一声谢谢。

心里十分不是滋味,尽管是个游戏而已,但还是莫名的愧疚和一点小难过,同时这个骚话不断的花花公子在我心中的形象也大大的改变了。之后一下午他都在裁缝铺门口给花浇水。

无意中做了一次恶霸,同时也发现了我们村的好小伙。

SgDylan's avatar

批量重命名从 Pixiv 下载的图片文件

farseerfc's avatar

SSD 就是大U盤?聊聊閃存類存儲的轉換層

上篇 「柱面-磁頭-扇區尋址的一些舊事」 整理了一下我對磁盤類存儲設備(包括軟盤、硬盤,不包括光盤、磁帶)的一些理解, 算是爲以後討論文件系統作鋪墊;這篇整理一下我對閃存類存儲設備的理解。

這裏想要討論的閃存類存儲是指 SSD 、SD卡、U盤、手機內置閃存等基於 NAND 又有閃存轉換層的存儲設備(下文簡稱閃存盤),但不包括裸 NAND 設備、3D Xpoint (Intel Optane)等相近物理結構但是沒有類似的閃存轉換層的存儲設備。 閃存類存儲設備這幾年發展迅猛,SD卡和U盤早就替代軟盤成爲數據交換的主流, SSD 大有替代硬盤的趨勢。 因爲發展迅速,所以其底層技術變革很快,不同於磁盤類存儲技術有很多公開資料可以獲取, 閃存類存儲的技術細節通常是廠商們的祕密,互聯網上能找到很多外圍資料, 但是關於其如何運作的細節卻很少提到。所以我想先整理一篇筆記,記下我蒐集到的資料,加上我自己的理解。 本文大部分信息來源是 Optimizing Linux with cheap flash drivesA Summary on …

RecursiveG's avatar

CMake 项目生成脚本

C++ 比较尴尬的一点就是缺少比较“傻瓜”的工具库,不得不依靠第三方来补充。想快速开始写个小的 Demo 的时候光找库就花去不少时间。于是糊了一个脚本去自动生成这些基础的东西。放在这里方便自己以后参考。

用到的库列表:

  • {fmt}:
farseerfc's avatar

柱面-磁頭-扇區尋址的一些舊事

在 SSD 這種新興存儲設備普及之前,很長一段時間硬盤是個人計算機的主要存儲設備。 更往前的磁帶機不常見於個人計算機,軟盤的地位很快被硬盤取代,到 SSD 出現爲止像 MiniDiscDVD-RAM 等存儲設備也從未能挑戰過硬盤的地位。硬盤作爲主要存儲設備,自然也影響了文件系統的設計。

這篇筆記稍微聊一聊硬盤這種存儲設備的尋址方式對早期文件系統設計的一些影響,特別是 柱面-磁頭-扇區尋址(Cylinder-head-sector addressing, 簡稱CHS尋址)的起源和發展。 大部分內容來自維基百科 Cylinder-head-sector 詞條 這裏只是記錄筆記。現今的硬盤已經不再採用 CHS 尋址,其影響卻還能在一些文件系統設計中看到影子。

柱面、磁頭、扇區以及相關術語

磁盤示意圖(來自維基百科 Cylinder-head-sector 詞條
chs-illustrate-trans.svg

如右圖所示,一塊硬盤(Hard Disk Drive, HDD)是一個圓柱體轉軸上套着一些磁碟片(platter), 然後有一條磁頭臂(actuator arm)插入磁碟片間的位置 …

imi415's avatar

Archlinux上Buildroot的基础使用

如何使用Buildroot为自己量身定制Rootfs
farseerfc's avatar

Btrfs vs ZFS 實現 snapshot 的差異

zfs 這個東西倒是名不符實。叫 z storage stack 明顯更符合。 叫 fs 但不做 fs 自然確實會和 btrfs 有很大出入。
我反而以前還好奇為什麼 btrfs 不弄 zvol , 直到我意識到這東西真是一個 fs ,名符奇實。
—— 某不愿透露姓名的 Ext2FSD 開發者

Btrfs 和 ZFS 都是開源的寫時拷貝(Copy on Write, CoW)文件系統,都提供了相似的子卷管理和 快照(snapshot)的功能。網上有不少文章都評價 ZFS 實現 CoW FS 的創新之處,進而想說「 Btrfs 只是 Linux/GPL 陣營對 ZFS …

SgDylan's avatar

在 Photoshop 中使用赛璐璐动画风格

赛璐璐动画因其制作工艺有着独特的画面质感,以下是咱为了模拟这一风格的一点探索。

's avatar

猫咪!猫咪为什么这么可爱!

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


猫咪真是太棒了!圆圆的身体和脑袋,尖尖的、竖立着的耳朵,灵活机动的尾巴,宝石般闪亮发光、还含有长条瞳孔的眼睛,柔软却含有锋利爪子的脚掌。它们好奇的行为总是无法被人类理解,却仍然给我们带来了无尽的快乐荷尔蒙(如果没有闯祸的话)。它们抓着毛茸茸的草,追赶着毛茸茸的线团,最后翻滚在地上也变成一团形状不固定的毛茸茸。如果我更有经验也更有文笔的话大概能够写出更多,不过我想不必多说,猫咪超级可爱,应该是许多人都会认同的事情了。可是为什么,为什么它们会这么可爱呢?

准确地说,为什么许多人类会觉得猫咪非常可爱呢?

这是我在刚意识到猫咪的可爱的时候(大概是高中)还没有想过的问题,那时我面对可爱的反应最多还只是低头与闭上眼睛微笑,但这样的感情逐渐地,从起初的“呀,蛮可爱的”,变成了“喔,很可爱呢”,变成了在网上疯狂地阅览含有猫咪地图片和视频,然后又变成了抱着一块屏幕遮住脸发出毫无意义的呐喊这样的行为,最后到达了我现在的样子(无可救药了)。换句话说,就是“深陷泥潭,无法自拔”。后来,在一次日常地对猫咪的可爱做出感叹的时候,我才像每一个发厨的人类一样,做出了这样的感叹:猫咪!猫咪好可爱呀呀呀啊啊啊!猫咪为什么这么可爱!

在发厨完毕后,我才发觉,这可不是随便的发厨中的呐喊呀,这可是一个非常正经的问题,猫咪这么可爱,一定是有原因的,所以这个原因是什么呢?我从此在心中记上了这个问题,虽然还没有开始去主动寻找答案,但还是长期得带着这个问题,在生活中等待着答案。

然后懒惰又拖延的我就把这件事忘记,封存在记忆的地窖中了。

在一个平常地耍废看 YouTube 的夜晚,我遇到了这样一个视频,它是出自 Vsauce 频道的《Why Are Things Cute?》。 Vsauce 是我非常喜欢的讲述知识的频道,于是我便点开来观赏了。视频中说,我们之所以会觉得东西可爱,是因为它们具有人类婴儿的特征,像是好奇心、较小的身体,大大的眼睛,圆圆的脸蛋。因为只要看到婴儿就觉得可爱,于是便想要抱抱蹭蹭,想要保护与关怀,那是有助于婴儿的生存的,也就是有利于人类生命的延续的,所以人类便得以进化出了“觉得可爱”的能力。

可是这个视频没有说服我,因为按照这样说的话,我们都应该觉得人类的婴儿是世界上最可爱的东西才对,可是这对于我来说显然是不对的,婴儿那么吵又烦的东西,怎么可能有猫咪可爱!难道是我的神经有些异常,大多数人都是认为婴儿最可爱才对?可是认为猫咪或者其它宠物比人类婴儿可爱的人显然也不占少数,有这样多的人,那应该不能够用“个别的异常”来解释才对。所以问题还是没有完全解决,为什么猫咪这么可爱,比人类婴儿还要可爱呢?

那是在我近期阅读到的书《绑架本能的世界:影响所有决定的“超常刺激”理论》(英文维基百科: Supernormal Stimuli)才找到了答案的问题。那是由 YouTube 频道啾啾鞋在视频《悄悄潛入你我生活中的「超常刺激」你注意到了嗎? 》知乎链接)中讲述并推荐的一本书。

书中所说的“超常刺激”,是指的刺激了原始本能的人造模仿物,但是却比那个本能本该应对的自然中的事物更鲜明和夸张,所以反而更加具有吸引力。书中的开头举例了欧洲杜鹃,一种把蛋下在别的种类的鸟的巢穴中的鸟,小鸟寄生于那个巢穴的宿主,让它们来孵化和喂养。杜鹃的蛋一般都会比宿主鸟的蛋更大、更亮,小鸟的喙也更宽、更红。出于本能地,对宿主鸟来说,又大又亮的蛋和又宽又红的喙都是更加好的,因此宿主鸟不但没有认出那个寄生鸟,却反而给予它比自己真正的孩子更多的关怀。这种杜鹃地鸟蛋和小鸟,就是对于宿主的“超常刺激”。

作者是一名演化心理学家,那是一门把人类以与动物的同种方式来观察的学科。也就是说,既然动物会被假的鸟蛋所欺骗且更偏爱,那么人类也会做同样的事情,只是人类的超常刺激并不从外种来,而是人类的现代社会自己创造的。

书中讲到了性,因为 A 片中演绎的场景比现实更加刺激,所以人类非常喜欢看;书中讲到了外貌,因为万里挑一的模特与偶像比现实中能够见到的人更好看,所以人类会去更多地追求他们;书中讲到了小说,因为虚构的故事比现实更精彩,所以人类会沉迷与其中;书中讲到了垃圾食品,因为盐与卡路里在原始社会非常稀少,所以人类会本能地想要大量吃下;书中讲到了知识,因为了解得更多会让自己更容易在原始丛林中存货下来,所以人类会本能地无尽地对事物好奇(对,超常刺激不一定都是坏事)。

当然,书中也讲到了可爱。在阅读讲述可爱的章节的时候,我终于明白了。

之前提到的 Vsauce 的视频说得没错,可爱是为了让动物能够爱护自己的后代而产生的东西。我们面对可爱的东西产生的反应,那是本该对人类婴儿产生的。我们会认为是可爱的特征,也是本应该在人类婴儿或者幼年人类身上找到的。列举一些可爱的特征的话,大概是这样的:

  • 小身体
  • 大脑袋
  • 大眼睛
  • 小鼻子
  • 圆脸
  • 胖乎乎的四肢
  • 笨拙的协调性
  • 爱玩
  • 亲热
  • 好奇心
  • 无助的感觉
  • 想要被呵护

都是人类后代会拥有的特征,对吧?可是尽管这些特征都是从“人类后代”的模子里面出来的,世界上却存在一些东西,比人类后代更加显著地具有这些特征,那些比人类后代更加可爱的东西中之一就是——猫咪。猫咪有着圆圆的脑袋,亮晶晶的大眼睛,毛茸茸软乎乎,跳来跳去充满活力,带着满满的好奇心探索四周……列举出来的话许多特征都被满足了,而j几乎每一项都比在人类婴儿中能找到的特征更夸张,换句话说,更可爱。

也就是说,猫咪,是对我们人类的“可爱”反应的超常刺激呢。

当然啦,也许不是每个人都认为猫咪是最可爱的,那么狗狗呢?那个被人类驯化以来就在不断地被人类以对人类有益的特征筛选培育的物种,在很少需要放羊的现代,可爱就是最重要的特征了。狗狗的可爱,可以说是被“研制”出来的。如果不是特别喜欢宠物的话,那么皮卡丘呢?卡比呢?还有各种各样奇形怪状的吉祥物呢?还有请问您今天要来点兔子吗?那些由“可爱工程师”(也就是艺术家)们一笔一笔创造出来的可爱,怎么可能会不使大部分人类痴迷呢?要让真正的人类婴儿与它们相比较的话,也就太不公平了。

简而言之:猫咪为什么这么可爱?因为它具有我们的后代会拥有的特征,却更加显著和夸张。


看到这里,你有未觉得,把“可爱”描述成“本能”,站在用这样理性的方式去剖析,会不会使人觉得可爱很是件低下的事情,而一个理性的人是应该抛弃的呢?我不这样认为,人类是逃不掉被本能支配的,所以被“可爱”这样的本能支配完全不是坏事,倒不如说,我们来一起拥抱它吧~

对了,还有一件令人开心的事,那在生物学上被称作“幼态延续”,它是指一种生物在成年后仍然持有幼年特称的状况。野生的狼在幼年时与狗一样汪汪叫,而成年后就变成了嗷呜;在被驯化成为狗之后,便一直学不会嗷呜,成年之后也继续汪汪叫,这是幼态延续的成果。猩猩在成年后,鼻子部分的脸会更加突出,而幼年猩猩的脸要短很多;人类拥有现在这样的脸,也是猩猩幼态延续的结果。同样,人类所拥有的其他动物无与伦比的好奇心,也是幼态延续的结果。换句话说,人类就是幼齿的猩猩。幼齿使我们更具竞争力,更容易生存,生活越来越好。我们喜欢幼齿,以致于我们在寻找伴侣的时候,都会更加喜欢幼齿的人类。对,合法正太和萝莉最棒了!而且因为这样的择偶趋势,人类的幼态延续会继续下去,所以进化的趋势就是,人类会变得越来越可爱!

唔,因为是在凌晨快要到 4 点钟的时候完成这篇文章的,所以请原谅我在整篇文章中只加入了一张模糊的猫咪照片呢……

最后,猫咪可爱!喵! 🐁


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

farseerfc's avatar

ZFS 分層架構設計

2020年2月9日更新過

ZFS 在設計之初源自於 Sun 內部多次重寫 UFS 的嘗試,背負了重構 Solaris 諸多內核子系統的重任,從而不同於 Linux 的文件系統只負責文件系統的功能而把其餘功能(比如內存髒頁管理, IO調度)交給內核更底層的子系統, ZFS 的整體設計更層次化並更獨立,很多部分可能和 Linux/FreeBSD 內核已有的子系統有功能重疊。

似乎很多關於 ZFS 的視頻演講和幻燈片有講到子系統架構,但是找了半天也沒找到網上關於這個的說明文檔。 於是寫下這篇筆記試圖從 ZFS 的早期開發歷程開始,記錄一下 ZFS 分層架構中各個子系統之間的分工。 也有幾段 OpenZFS Summit 視頻佐以記錄那段歷史。

早期架構

早期 ZFS 在開發時大體可以分爲上下三層,分別是 ZPL, DMU 和 SPA ,這三層分別由三組人負責。

最初在 Sun 內部帶領 ZFS …

OX's avatar

斐訊 R1 音箱關閉開機提示音

斐訊倒閉了,R1音箱早就不能正常用了。
前段時間有大神出了一個刷機的方案,但是要拆機自己焊接端口,比較麻煩,我只需要能播AirPlay就可以了,所以就沒有動力去拆機。
但是每次開機的那個提示音很吵很煩,有時候莫名其妙還會喚醒智障小訊,一直在想能不能把斐訊全家桶幹掉。
但是一直沒有出不拆機就能root的方案。
終於。今天晚上無聊,自己摸索出解決方案,開機再也沒有煩人的提示音,叫它也不會再應答,符合我自己的使用場景,現在把方法分享出來,其實核心內容很簡單,就是通過adb調用pm命令把斐訊全家桶hide掉就可以了。

下面是具體方法

先用斐訊AI的App讓R1連上Wi-Fi,然後找到R1的IP地址,然後

adb connect [R1 IP地址]

然後運行下面的命令

adb shell /system/bin/pm hide com.phicomm.speaker.productiontest
adb shell /system/bin/pm hide com.phicomm.speaker.bugreport
adb shell /system/bin/pm hide com.phicomm.speaker.otaservice
adb shell /system/bin/pm hide com.phicomm.speaker.player
adb shell /system/bin/pm hide com.phicomm.speaker.device

需要留意的是,com.phicomm.speaker.launcher 不可以hide掉,不然頂部的音量調節功能會失效。另外,為了讓開機的音效消失,需要把com.phicomm.speaker.device禁用,但是這樣按三下頂部按鈕開啟藍牙的功能就會失效

雖然隨時都可以通過執行adb shell /system/bin/pm unhide com.phicomm.speaker.device命令恢復藍牙的功能,但是每次這個app啟動,都會有很震耳的音效,每次執行命令之前都要注意R1的音量大小。

然後重新啟動就可以了:

adb shell reboot

想復原的話,只需要將命令的hide改為unhide,就可以了,如果部分功能還是沒有恢復,可能需要重啟。比如像這樣:

adb shell /system/bin/pm unhide com.phicomm.speaker.productiontest
adb shell /system/bin/pm unhide com.phicomm.speaker.bugreport
adb shell /system/bin/pm unhide com.phicomm.speaker.otaservice
adb shell /system/bin/pm unhide com.phicomm.speaker.player
adb shell /system/bin/pm unhide com.phicomm.speaker.device
// 重啟的命令:
adb shell reboot

題外話

如果想乾脆一點,可以用/system/bin/pm uninstall --user 0 命令把上面的全家桶徹底刪掉,但是這個操作不可恢復,特別是com.phicomm.speaker.otaservice 如果徹底幹掉的話,想刷機就只能拆開,手工焊接上調試端口刷機了。

這篇文章 斐訊 R1 音箱關閉開機提示音 最早出現於 OXの胡說八道

依云's avatar

自制大上 Paperlike HD「驱动」

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

大上 Paperlike HD 使用有一段时间了,然而有一点我对其非常不满:它需要以 root 权限运行一个图形界面的程序。具体麻烦的地方是:

  • 图形界面的程序不方便使用 systemd 管理,那个窗口我得找个地方安放,并且在登出图形界面或者 Xorg 出问题时会随之关闭
  • 即使持续运行此程序,当几秒内不使用键盘或者鼠标的时候屏幕就会休眠。这导致我无法将此屏幕用于关注程序日志或者聊天工具的新消息。
  • 它持续不断地执行多个线程的任务(读取键盘事件、读取鼠标事件、通过 ioctl 与设备通讯),耗费了不少 CPU
  • 在屏幕尚未连接时,它的运行会导致内核不断输出日志「drm_dp_i2c_do_msg: 2 callbacks suppressed」

我曾多次想自己实现一个符合自己使用习惯的方案。

首先当然是 strace 上去啦。这会得到许多类似这样的消息:

ioctl(9</dev/i2c-1<char 89:1>>, _IOC(_IOC_NONE, 0x7, 0x7, 0), 0x7f47d8805b70) = 1
nanosleep({tv_sec=0, tv_nsec=100000000}, NULL) = 0
ioctl(9</dev/i2c-1<char 89:1>>, _IOC(_IOC_NONE, 0x7, 0x7, 0), 0x7f47d8805be0) = 1
nanosleep({tv_sec=0, tv_nsec=200000000},  <unfinished ...>

可以看到它在对 /dev/i2c-1 这个文件进行操作,但是具体内容是个指针,strace 看不到。

我尝试过使用大名鼎鼎的 IDA 的免费版本来分析其具体行为。但我对 IDA 并不熟悉,并且 IDA 只支持 Intel 语法的汇编,而我见的 AT&T 语法的比较多,Intel 的很多表示法我不太能看懂。

后来根据 ioctl 的请求参数找到这个文档,里边有这些 i2c 消息的结构体定义。于是想着先把 ioctl 的数据弄出来看看。一开始尝试用 gdb 去看那个地址的数据,但想到数据是变动的,再加上 gdb 查看太累了,就想起了通过 LD_PRELOAD 去 hook ioctl。

所以又要写 C 了?并没有呢!C 写起来那么不舒服,还是用 Rust 吧~然后搜了一下,还真有现成的用于写 LD_PRELOAD 库的 crate,比如我用的 redhook。不用自己去 dlopen,不用在各处写很多错误处理代码,很容易就写好了。代码链接

拿到了 ioctl 里用的消息,我不用理会它具体是什么意思,也没办法去猜测,自然是把它按大上提供的程序那个样子给发过去了。于是又一个 Rust 程序出来了。

一开始写的时候不小心往 unsafe 代码块里传了个悬空的指针,导致程序不工作,调试了好久,甚至我都把完整的整个流程给复刻了一遍。这要是用 C 写文本解析的逻辑可头疼了,不过 Rust 写起来就跟 Python 差不多的了~

至于那个 bug,是 Rust 语句中的临时对象(此例中是包含一个对象的数组)会在语句结束之后就释放导致的。有点坑,但也没什么好的办法。

程序运行起来之后就会保持 Paperlike HD 显示器可用,不会报错让装驱动,也不会过几秒就休眠了。我大幅降低了消息发送的频率(由差不多每秒三次改成了三秒才一次),再加上不需要读取键鼠输入,所以 CPU 占用也会大幅减少。另外内核也不会再打印「drm_dp_i2c_do_msg: 2 callbacks suppressed」的消息了,大概是因为消息频率降低了?重新连接显示器之后,和大上原版程序一样有概率出现显示器亮蓝灯、屏幕不工作的情况。拔插一下电源可解。

当然啦,如果有人要用这个程序的话,记得先确认一下你的 i2c 设备文件路径(去 lsof 大上原版程序就行)。另外,使用此程序后果自负,由此造成的任何设备损坏或者其它损失,我都不负责任的哦~

17windy's avatar

去海边:信使 游戏更新日志

V0.63 0124 版本更新日志

增加:
1,新增剧情关卡,大家春节快乐!

修复:
1,部分怪物AI修复

优化和调整:
1,目前可以获得的基础芯片可以堆叠了
2,角色平衡性微调

V0.625 0117 版本更新日志

修复:
1,修复了第二关狼BOSS可能会瞬间造成大量伤害的问题
2,修复了某个图标错误

优化和调整:
1,采用了新的关卡进度提示UI
2,普通怪物的血条显示修改为会自动隐藏

增加:
1,所有角色增加了不同的自回血能力

V0.62 0116 版本更新日志

优化和调整:
1,狼现在更倾向于灵活的中距离攻击与穿插,拥有灵活但不是特别精确的中距离普攻,拥有快速恢复的短距离冲刺
2,重制了狼的冲刺技能视觉效果
3,凤的技能伤害微调
4,谬的护盾技能恢复更快
5,降低了现有关卡的难度

增加:
1,帮助按钮现在可用
2,增加场景标题和相关过渡

V0.61 0115 版本更新日志

修复:
1,修复狼的二技能偶尔失效
2,修复界面按钮偶尔失效
3,修复背包按钮导致游戏持续暂停状态
4,修复背包按钮偶尔导致角色无法跳跃
5,修复关卡2的植被结构
6,修复关卡1的场景孔洞和出墙操作
7,修复关卡2三尾BOSS的攻击持续时间
8,修复关卡2结束攻略后的持续箭头

优化和调整:
1,优化部分UI设计
2,优化部分怪物AI
3,调整玩家角色狼的普攻范围
4,调整玩家角色凤的部分数据
5,整体调整玩家角色的生存数据

增加:
1,关卡1增加部分指引
2,现有怪物增加攻击前摇和攻击特效
3,部分新剧情资源预载

RecursiveG's avatar

简易内核开发环境

近期尝试了一下写 Linux 内核代码,于是把折腾过程记录一下,方便以后参考。本文默认使用 x86_64 架构以及 Linux 作为宿主系统。

使用 QEMU 运行 Linux 内核

在开始写代码之前,我们需要先准备好模拟器用于运行 Linux。我这里用了QEMU,你也可以用 VirtualBox 之类的虚拟机。一般来说,我们需要一个内核可执行文件(内核本体)和一个 initramfs 镜像(提供用户态程序)。当内核被加载后,它会自动载入 initramfs 镜像,并执行其中的/init程序。由于这一节的重点是 QEMU 配置,所以我直接使用宿主机的内核和 initramfs。以我的 Archlinux 系统为例,内核文件是/boot/vmlinuz-linux,initramfs 文件是/boot/initramfs-linux.img。使用以下命令启动 QEMU,按Ctrl-A x退出。

1
2
3
4
5
6
7
qemu-system-x86_64 \
-kernel /boot/vmlinuz-linux \
-initrd /boot/initramfs-linux.img \
-nographic -append "console=ttyS0" \
-m 512 \
--enable-kvm \
-cpu host
  • -kernel 指定内核可执行文件。
  • -initrd 指定 initramfs disk 镜像文件。
  • -nographic -append "console=ttyS0" 禁用视频输出并使用串口作为终端。
  • -m 512 设定内存。
  • --enable-kvm 使用KVM。
  • -cpu host 使用宿主机的 CPU 特性。

你应该能看到一些系统启动的信息以及无法挂载根分区的报错,这是正常现象,因为我们没有提供任何磁盘文件。你应该可以进入一个紧急修复 Shell, 执行一些简单的如 ls cd 之类的命令。

's avatar

新的家庭服务器:MicroServer Gen10

我的上一代家庭服务器是一台技嘉的 GB-BXBT-2807。其实作为家庭服务器来说,它是个还行的选择,但是内部只能安装一块 2.5 寸 9.5mm 以下的 SATA 硬盘,而且只有一个 USB 3.0 和两个 USB 2.0 接口。

我家的上传速率其实还是可以的,而随着我开始尝到私有云的甜头,我陆续增加了三块硬盘。然而因为它只有一个 USB 3.0 接口,所以最后我的家庭服务器变成了这个样子。

看来,我需要一台真正的多盘位 NAS 服务器了。我一度考虑过以下方案:

  • 搞个蜗牛星际。但是在 KK 家摸到真机以后,我对它的做工倍感失望。
  • 买个迎广 MS04,自己从头攒一台 NAS 出来。但是这样的话,总支出大概不会跟买一台 Gen10 差太远,而且保修这个问题会变得比较复杂。

最终,我还是决定购买 HPE ProLiant MicroServer Gen10。

可以说,这款主机对我来说,几乎是完美的:

  • 4 盘位(虽然并不是热插拔)
  • 低功耗(x3216 的 TDP 只有 15w)
  • 主机本身是正常的 x86 PC,可以很方便的安装各种主流 Linux 发行版
  • 做工良好,可靠性强
  • 两个 PCI-E 插槽(分别为 x8 和 x1),未来升级万兆会很方便
  • 接口丰富:四个 USB 3.0、两个 USB 2.0、两个千兆以太网口、两个全尺寸 DP 和一个 VGA
  • 预装 8GB DDR4 ECC 内存
  • ……

就这样,我以 2.8k CNY 的价格在美亚拿下了这玩意。其实我一开始考虑从德亚买的,只要 2.5k(当时),但是并不能直邮到中国。为了省事,我就直接在美亚买了。

安装

近两周以后,它抵达了我家。到手的第一件事,当然是拆开检查一下了。箱子中并没有太多的东西(主机、美标品字电源线和一堆小册子),不过对于它的目标用户来说大概够了吧。

顺便那条品字电源线用的是带接地的美标插头,这使得它并不能在新国标的插线板上使用。所以如果你家没有多余的品字电源线,别忘了单独买一条!

PSU 是台达的 flex 电源,宽电压,最大输出 200W;输出有 24pin x1、大 4P x1 和小 4P(软驱电源插头)x1。

接下来就要安装硬盘了。这玩意并没有独立的硬盘仓,所以你需要这样安装硬盘:

  1. 从硬盘仓顶部拧下来 4 颗螺丝
  2. 把这 4 颗螺丝拧到硬盘两侧最左面和最右面的孔位上
  3. 把硬盘正面朝右,稍微用力的推进硬盘仓。移除硬盘也是超级容易的(见硬盘仓左下角贴纸):

然后就开始安装系统 SSD 了。这玩意并没有 M.2 NVMe 插槽,但是在主板上提供了一个额外的 SATA 接口,所以我买了一块普通的 SATA SSD。

然而,Gen10 的 PSU 并没有多余的电源线,你能利用的只有那个小 4P 插头。所以你需要买这样的转接线:

我那个 Gamemax 机箱正好附送了一根这样的转接线,所以我就直接拿来用了。

至于 SSD 的固定……Gen10 上侧的那几个空位是给你固定笔记本光驱用的,所以你的 SSD 大概就只能这样放着。当然你可以再买个笔记本光驱位转硬盘位之类的东西,不过 NAS 这种东西本身也不需要经常挪动,再说 SSD 里面并没有活动的部件,所以我就无所谓了。

系统

我选用的是 Ubuntu 18.04 LTS。因为:

  • Ubuntu 是我熟悉的发行版系列
  • 我拥有充分的控制能力

安装过程没什么坑,一切都在预料之中。随后,我通过 apt 安装了各种我需要的软件(nginx、Aria2、Transmission 等),写好 /etc/fstab 表,就大功告成了。

目前,我的硬盘使用情况如下:

硬盘 安装位置 用途
东芝 240G SSD(TR200) 顶部 系统盘
东芝 2T 监控盘(DT01ABA200V) 硬盘仓 1 一般文件存储
西数 4T 蓝盘(WD40EZRZ) 硬盘仓 2 BT/PT 下载

同时,我还有一块 2T 的东芝移动硬盘用于冷备份;我会定期将它连接到 Gen10 上,运行我的脚本来进行 rsync。

嗯,我觉得目前就足够了。等将来有需求的话,再考虑加硬盘吧。

系统运行

我之前的确考虑过 CPU 的问题,毕竟这玩意是焊在主板上的。但我的需求不高(就是存取文件和下载啥的,顺便开个 web 服务器),即使是看动画的话,解码都在客户端完成,所以也就 Gen10 了。

实测我的 CPU 负载一般可以控制在 1.0 以下;如果我真的需要算力,大概我就直接拿主力机器搞事了。


farseerfc's avatar

和萌狼交換問題

很抱歉萌狼很早就提過交換問題的事,被我一直咕咕了許久。 拖延症晚期有藥麼

我的提問和萌狼的回答

可以去萌狼的博客上看呀

Q1:除了博客的「关于」页面以外,还愿意再向咱介绍一下自己嘛?

介紹自己啊。 寫了刪刪了寫,不知道該介紹點啥 就說點自己的興趣?

喜歡自由開源軟件,喜歡 Arch Linux 。喜歡這些倒不是出於 RMS 和 FSF 那樣道義上的原因, 我覺得商業軟件公司要賺錢吃飯也是無可厚非的。

喜歡自由軟件是因爲,當我需要知道它到底怎麼工作的時候,有可能去挖代碼,必要的話能去改代碼。 當然我一個人肯定不能讀所有在用的軟件,但是我知道我有讀和修改代碼的權利的話, 那麼我認識的朋友們也同樣有這樣的權利,我不認識的廣大社區有千千萬萬的人也同樣有這樣的權利, 從而我相信當我遇到問題的時候不至於卡在某些人某些公司某些集體的決策上而無法解決。

基於這個理由,我對開源社區也同樣有公開全部細節的期待。我喜歡 Arch Linux 因爲即便它的內部決策只是一小波人,但是導致決策的討論以及決策的執行方式全是公開的,可以在網上翻閱, 可以追根溯源,這讓我有種安心感。就像我不喜歡 Manjaro 的一點是它有太多細節是翻閱不到的, 雖然它也是開源社區,但是打包細節翻閱不到,包列表翻閱不到,決策的制定和執行的過程也翻閱不到 …

Roy Binux's avatar

家居自动化

从 Google Assistant, Amazon Alexa, Apple Homekit 到米家,智能家居自动化已经不是什么新鲜的概念了。对于我来说,入坑的契机也非常简单:我不想下床关灯。然后随着想要自动化的场景增加,智能设备(可编程设备)就越来越多。这篇文章就根据自

via these people and places