Arch Linux 小折腾记

久闻 Arch Linux (下文简称 Arch )大名,在虚拟机上多次完成过了整个系统的安装与图形界面的配置,也试过了 KDE 和 GNOME 这两个大名鼎鼎的图形环境,深切体会到了 Arch Linux 的四大原则:

  • Simplicity
  • Modernity
  • Pragmatism
  • User Centrality

Pacman 是最好的包管理器


我分别在自己的台机上和一台 ThinkPad S1 Yoga 2014 上安装 Arch. 具体过程跟着官方 Installation Guide 走就行了,Wiki 中的注意事项也是比较全面了,本文写几个小注意点。

Btrfs

不知道 Btrfs 的我建议你马上查 Wikipedia.

Arch 的安装 ISO 环境中是自带了 Btrfs 的工具包和支持的,但是在 base 软件包中不包含这些,所以你需要手动安装 btrfs-progs 这个包,然后在 /etc/mkinitcpio.conf (注意是在 arch-chroot 这一步之后)中的 HOOK 一行中添加 btrfs, 之后跑一遍 mkinitcpio -p linux, 看到输出中有 btrfs 即可。

关于 btrfs 的配置问题,参见官方 Wiki, 也可以参考 egara/arch-btrfs-installation.

Boot Loader

在 Boot Loader 的选择中,我个人还是比较倾向于直接使用 systemd 集成的 systemd-boot, 懒得再装个 GRUB.

虽然 systemd-boot 局限性非常大,比如它只能加载 EFI 可执行文件比如 bootmgfw.efi, vmlinuz-linux.

如果选择了 systemd-boot 作为 Boot Loader, 那么就需要在 arch-chroot 后手动运行一次 bootctl --path=$ESP install 来把引导程序安装进 EFI 分区中并向 UEFI 界面注册这个引导器,之后你在启动时按 F12 就可以看到一个 Linux Boot Loader.

但是如果只是将 Boot Loader 安装到了 EFI 分区还不足以让它引导我们进 Arch, 仍然需要在 /boot/loader/entries/ 这个目录下建立新的 conf 文件,里面的内容如下

1
title Arch Linux
2
linux /vmlinuz-linux
3
initrd /initramfs-linux.img
4
options root=(PARTUUID|PARTLABEL)=xxxxxxxxxxxxxxxxxxxxxxxx rw

如果使用的是 Intel 的 CPU 并且有安装 intel-ucode 包,那么在第3行之前再加一行 initrd /intel-ucode.img 启用它。

建立完了引导所需的系统 config, 需要在 /boot/loader/loader.conf 中的 default 一行中指定刚才建立的 config 文件名,然后使用 Linux Boot Loader 引导器就会默认进入 Arch Linux.

双系统与时钟

感谢 UEFI 标准,现在我们可以非常方便地组建双系统 (Windows + Linux) 环境。

如果使用的 Boot Loader 是 systemd-boot, 那么它会自动检测 Windows 的存在,并且在选择菜单自动提供一个 Windows 的选项,这个选项的配置名为 auto-windows, 选择它会运行 /boot/Microsoft/Boot/bootmgfw.efi 然后就是 Windows 的流程了。

双系统有一个很大的问题,就是时钟。Windows 默认往 BIOS 写入本地时间,而不是 Linux 标准的 UTC, 这就会导致你从 Windows 切换过去后时间会+8, 也就是按你的时区调整然后又写回到 BIOS 中。从 Linux 切换过去,Windows 认为是本地时间,于是显示给你的实际上是 UTC. 所以为了解决这个问题,在安装 Arch 时,使用 hwclock --hctosys -l (将硬件时间作为本地时间读入系统), 而不是 Guide 上所用的 hwclock --systohc(将系统时间写入 BIOS 并且是 UTC).

之后启动到 Windows, 注册表定位到 HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation 添加一个 DWORD, 名为 RealTimeIsUniversal 值为 1, 即可实现 Windows 往硬件中写入的时间是以 UTC 为标准而不是本地时间。

systemctl enable

由于 Arch Linux 的哲学,大部分软件包在安装之后也并不会自动启用,需要你手动 systemctl enable|start xxxx. 尤其要留意的是,还在 ISO 环境下安装系统的时候就要把 dhcpcd 这个服务给 enable 了,解决你进系统之后发现连不上网络想半天不知道问题出在哪里的问题。当然这是针对有线网卡,而大部分无线网卡,我推荐直接使用 Network Manager 搞定。当然使用无线网卡的首次联网你还是需要如下步骤:

1
ip link set dev interface up
2
iw interface scan
3
wpa_supplicant -B -i interface -c <(wpa_passphrase SSID Password)

还有一点需要注意的是,Arch 的 Shadowsocks-libev 默认读取的配置目录在 /etc/shadowsocks/, 与 Python 版相同的目录而不是传统的 /etc/shadowsocks-libev/ 下,启用它的命令为 systemctl enable shadowsocks-libev@配置文件名.service .

Intel 有线网卡的坑

当你机器上使用的网卡的是 Intel Ethernet Connection I21x 的时候,你要小心了,在安装 Arch 之前,在 Windows 中安装 Intel 的官方驱动,然后在网卡的硬件配置面板中将所有的网络唤醒选项给关闭,这可以有效防止你进入 Arch 环境之后获取不到任何的网络信息导致连不上网。

>> endl;

泄露的 iBoot 源代码中都有些什么

近日,一份疑似 iOS 9.3.x 的 iBoot 及其他部分 BootLoader 的源代码被匿名人士 push 上了 Github, 粗略地查看了一下里面的文件之后,大家都惊讶地发现这份源代码的爆点实在是太多了。

项目的 README 中是这么写的:iBoot_BootROM_iBSS_iBSS_iLLB_Source_Code

其中 iBSS 是 iBoot Single Stage 的缩写,而 LLB 是 Low Level Bootloader 的缩写。

我们先来看一下 iOS Devices 的启动流程:

在 Apple 定制的一系列 A 系列 SoC 中有一块存储区域专门存放了一部分最初的启动代码,也就是俗称的 BootROM, 这部分被 Apple 称之为 SecureROM, 它是在电源键被按下,设备上电之后最初加载的代码。SecureROM 检查下一级 BootLoader, 也就是 LLB, 如果签名没有问题,那么就加载并初始化 LLB, 此时设备的 Apple Logo 就出现了。然后 LLB 检查并初始化 iBoot, 同样是通过 Apple Root CA Public 证书验证签名,通过就会把设备带给 iBoot, 而 iBoot 会映射 Device Tree, 然后验证内核签名并加载,最终初始化内核并运行,这时候可以说 iOS 系统已经启动了。

通过简述的启动流程,我们可以看到,BootROM, LLB, iBoot 这三个无论哪一个都是在整个启动流程中充当关键角色的。所以这次源代码的泄露,非常劲爆。

在基于证书链的安全体系下,私钥的泄露可以说是直接把安全性掉到0去了,而这份代码中,在位于 /lib/pki 和其中的 tests 目录下,可以看到有一份 Fake CA 和一些私钥,还有一份中间证书和私钥,如果后续版本也是沿用这些东西的话,整个启动验证链的加密体系,就真的可以说安全性为0了。

因为这份代码是 9.3 时代的,也就是在 iPhone 7 那代发布前的版本,所以我们能看到有许多 T8010 相关的文件(T8010 是 Apple 对于 A10 芯片平台的代号)。而有趣的是,在 /target 目录下出现了 iphone8 这个文件夹,难不成 Apple 内部在 2016 年就开始对 iPhone 8 进行内部测试了?但是点进去看,目录下的文件清晰的指向了另一款产品——iPhone 6s. 往上推,iPhone 7 文件夹对应着 iPhone 6, iPhone 6 文件夹对应着 iPhone 5s, 如果按照这个内部排序,iPhone Ⅹ 这个 Ⅹ的由来,可能更好解释一点。而 iPhone 8, 则更像后来上马的 iPhone 7 Reversion.

除了主引导程序的代码外,泄露的代码中还包含了许多驱动,在 /drivers 目录下,可以清晰地认出 iOS 平台所使用的一些硬件,其中甚至包括了 Thunderbolt 驱动。

内容还有很多,笔者水平有限,也解读不出更多的东西了。

>> endl;

折腾记-0

为了把 RaidFinder 给实现出来,我决定直接自己手动实现一个 Filtered Stream API 的调用,来检查到底是需要什么 Track 关键词才能达到目的。

这里真的要吐槽一下新的 Twitter Developer 页面,以前大量的 API Reference 页面都已经404了,包括一些非常重要有用的 API 文档都能 404, 再看看那个“切换到夜间模式再切换回来之后主题色丢失”的前端 bug 修了几个月才修完,可以说 Twitter 真的药丸。

构造 OAuth 验证

查阅了文档得知,Stream API 需要进行在请求的 HTTP Header 中包含完整的用户验证,也就是走完整的 OAuth 验证流程,由于手上已经拥有了完整的用户和应用的 Key : Secret 对,所以直接进行构造。

一个完整的验证字段中必须包括如下内容:

  1. Consumer Key

  2. Nonce

  3. Signature

  4. Signature Method

    Twitter 只支持 HAMC-SHA1 的签名方法

  5. Timestamp

  6. Access Token

  7. OAuth Version

而 Signature 字段又是根据其他6个字段以及 HTTP 请求的 URL 和参数(包括 POST 方法的 Request Body)来产生的,格式如下:

请求方法&请求URL&其他6个字段&请求参数

HMAC-SHA1 签名的产生还需要一个 Key, 这个 Key 是由用户的 Consumer Secret 和 Access Token Secret 来构建的。

抓包

写了半个下午的 OAuth, 写完运行之后还是返回一个 401 给我,仔细检查代码也没有发现哪里出错了。没有办法之下,我想到了抓原版的请求包来看它到底用了什么关键词。于是立即安装 sbt 和 JDK. 其实 Windows 上的 sbt 也就是提供一个 jar 包和 sbt.bat 这个运行脚本来设定 sbt 所需要的运行环境而已。

安装完了,sbt run 先跑一记看看,然后让我没想到的是,在性能比 VPS 强了几倍的情况下,这玩意儿还是跑的稀慢,也可能是 Windows 的问题,总之,构建初始运行环境就花了大概一个半小时,不容易等到开始编译 scala 资源了,开始疯狂报错了。

首先是一个 Python 脚本报错导致后续脚本无法继续,查询项目文档后得知 Windows 上需要 Python 2.X, 而我安装的是 3.6, 没想到在这里会第一次碰到 Python 的版本问题,没办法,下 2.7 改 Path, 好通过了,然后继续报错。

之后报错都是因为 Java 运行环境的限制,主要问题出在内存的设定上,Google 之,然后在 Java 控制面板中添加全局参数,sbt run 之后开任务管理器看到参数起效了,遂继续运行下去,然而还是会报内存不够的错误,不解,好在每次都能按部就班的往下跑一点,几次重启之后也搞定了。把 twitter4j.properties 放到根目录下,sbt run 之后发现貌似请求没走代理,Twitter 请求撞墙超时。这时想到用 Proxifier 将 java.exe 的请求重定向到本地代理去,重定向之后就跑起来了,程序启动的一瞬间有两个 Search API 的请求和一个 Stream API 的请求,然后全是访问 pic.twitter.com 的请求,下图片的。

既然 Proxifier 能够重定向流量,那么我把 java.exe 的请求重定向到 Fiddler 的端口去不就能看到包内容了。但是切过去却发现,所有请求都不通了。期初以为是 Fiddler 没走代理,根据别人的经验添加了转发规则之后仍然出错,百思不得其解中,突然看到程序的出错信息不再是访问 Twitter 超时了,而是 SSL 证书出错。

怎么会呢?我明明把 Fiddler 的证书添加到系统中去了。Google 之,发现 Windows 上的 JRE 自己实现了一套证书环境,我去你大爷的垃圾 Oracle, 放着系统自己的轮子不用非要用自己那套垃圾轮子给人麻烦,前面的网络请求也是自己造的轮子直接跳过系统代理。

没办法,寄人篱下。于是 Google 到添加 SSL 证书的办法,添加完之后发现还需要自定义的命令行让 JRE 读证书,同样使用 Java 控制面板添加参数,然而这次发现参数并没有起效。

切记 keytool 这玩意儿要用管理员身份来跑,添加完之后 keytool 会生成一个 keystore 文件,建议将它移动在自己 Home 文件夹中并重命名为 .keystore

既然 $JAVA_OPTS 这个环境变量看上去对 sbt 没用,那我改 $SBT_OPTS, 利用 Everything 这玩意儿强大的搜索功能找到了存在于 sbt 安装目录\config 下面的 sbtopts 文件,好就是你了,添加自定义命令行,sbt run, 然并卵,一点作用都没起。一头雾水中我打开 sbt.bat 这个 Windows 版 sbt 的实际起效文件,发现了这行:

1
set FN=%SBT_HOME%\..\conf\sbtconfig.txt

我去你妈的,也是个不喜欢用一套轮子的。

把原本写进 sbtopts 文件的自定义命令行改写到 sbtconfig.txt 中,Java 命令行的前缀 -J 并不用添加,最后如下:

1
-DproxySet=true 
2
-DproxyHost=127.0.0.1
3
-DproxyPort=8888   'Fiddler 的代理端口
4
-Djavax.net.ssl.trustStore=<path\to\FiddlerKeystore> '刚刚生成的 keystore 文件的位置,如果移动到了 $Home 下面并重命名为 .keystore 的话这行就不用加
5
-Djavax.net.ssl.trustStorePassword=<Keystore Password> '刚刚 keytool 让你敲的密码

sbt run

终于,我在 Fiddler 中看到了 java.exe 的请求,并且正确地解密了出来。我花了半天时间探寻的内容终于呈现在我眼前:

count=0&track=%E5%8F%82%E5%8A%A0%E8%80%85%E5%8B%9F%E9%9B%86%EF%BC%81%2C%3A%E5%8F%82%E6%88%A6ID%2CI%20need%20backup%21%2C%3ABattle%20ID&stall_warnings=true

URL Decode 之后就是:

count=0&track=参加者募集!,:参戦ID,I need backup!,:Battle ID&stall_warnings=true

我看到这个之后差点吐血,原来他妈就是简单的用, 这玩意儿来分隔开 Track 关键词就能实现日语推的实时 filter???

还要继续实验。

外网访问

前文有讲,家里网络“重做”之后我就把主路由的 DMZ 主机挂在二级路由上,二级路由的 DMZ 挂在自己机器上,这样外网的请求就直接能到自己机器上。

然而从外部使用 DDNS 域名+端口号的方式不能直接访问到 RaidFinder. 哦好像是要配上一个 HTTP Server, 那简单,跑一个 http.server 80 不就行了。

是行了,能访问到所有的静态资源,但是看着 Console 中不断提示的 ws/raids?keepAlive=true 404, 我突然想起来前不久看到的 WebSockets 简介中提到的,要建立一个 WebSockets 连接是需要从 HTTP 请求“转发升级”过去的。于是想到用 NGINX, 下载,这玩意儿才 1MB+ 的大小,真他妈绿色环保。

把自己服务器上的 nginx.conf 拖出来抄配置,终于理解了之前搜到的配置的用处:

1
proxy_pass http://127.0.0.1:$port;
2
proxy_http_version 1.1;
3
proxy_set_header Upgrade $http_upgrade;
4
proxy_set_header Connection "upgrade";

配置中最后两句就是为 WebSockets 而服务的,是一个 HTTP 请求转为 WebSockets 连接的关键点。

那么一切设定好,开始跑,问题又来了:外网无法访问,内网 80 转发正常。

>> endl;

最后这篇折腾记的终点就在这里了,不知道为何,访问就是无限转圈,但是起初寻找关键词的目的还是完成了。

RaidFinder 开发记——1

上篇文章给自己写了一个开发计划,这两天已经开始动手了,结果刚开头就非常不顺,来写篇文章吐槽一下。

从原版的描述和一些代码中,我发现原作者使用了 Twitter4j 这个看起来在 Java 平台非常强大的库来进行 Twitter Stream 的获取。而在 NPM 上不难找到类似的 Twitter 库,也不难使用,填好两组 Key & Secret 之后简单的调用 API 就可以输出源源不断的 Tweets 来。

Twitter 官方提供的 Stream API 中自带了对自定义关键词的 Filter, 那么我们就来调用它。然后就碰到了目前为止第一个也是最主要最棘手的问题。

最主要的问题

问题就是:Twitter Stream Track 的关键词设置不支持 CJK 字符,而 GBF 的玩家则大部分使用日语,他们的救援推的关键词都是"参加者募集!"

于是我在 Twitter Deck 中新建了一栏,使用"参加者募集!" OR "I need backup!"的搜索条件进行搜索并观察官方用的是什么办法支持 CJK 字符的。结果大失所望,官方的搜索也只是用 Search API 而不是 Stream API, 然后定时获取一次假装出 Stream 的感觉来“糊弄”用户。那么我想,目前找到的库对于 CJK 都没有支持的情况下应该作者是用了一些手段来支持 CJK 字符的。

那么也只有继续读源码了。


经过大概一小时的思考,我决定暂时先将实现平台放到 .NET 上,目前 .NET Core 在跨平台上面已经比较稳定了,用 C# 写也更顺手一些。先拿这套把实现思路和一些算法给摸清楚,以后再重新用 Node.js 来实现。

计划:用 Node.js 重写 GBF-RaidFinder

最近产生了一个“大胆”的想法,就是用 Node.js 来重写 walfie/gbf-raidfinder 这个被许多骑空士使用着的项目。

为什么想要重写?

因为原项目是用 Scala 写的,运行在 JVM 上,虽然 JVM 跨平台的能力比较强,但它相对比较“臃肿”,而且构建、更新起来比较慢。可以是可以用作者提供的 Docker 镜像直接部署,但是之前因为 Docker 不兼容于 4.9 以上的内核,而我又比较依赖于 bbr 这玩意儿所以就没用 Docker 而是直接跑在系统的 JVM 上。

那么为什么想用 Node.js 重写,Node.js 相比较于 JVM, 保证了一定的跨平台能力的同时更为轻量化,版本迭代的代价也更低一些。最主要的是,我想通过这次重写来学习 Node.js 和 Javascript, 因为这个项目是 C/S 架构的,也能学习一定的全栈能力。

重写方案

在重新简要查看了原作者的实现之后,我得出了“这不是我短时间就能重写出来”的结论,原因如下:

  • 原作者使用了 WebSockets 这项技术来实现列表的实时更新
  • 原作者使用的许多库不知道在 npm 有没有类似的替代品
  • 原作者写的 Boss 列表自更新是一大难点
  • 我在 JS 和 Node.js 上都只是一个初学者

那么就一步一步地来,先写出一个 Twitter 的搜索模块,再学 WebSockets 然后把实时更新给实现了,然后把自更新实现了,最后把几个部分整合到一起,差不多重写就完成了。我给这个坑留半年到一年的时间,希望明年的现在我已经填完这个坑了。

>>endl;

一场因为使用 Git Submodule 引发的血案

前略
今天继续对 Blog 进行一些更新,上午先是将目前暂挂于 Github Page 的本博客链接上了自定义域名,但是这样一来就不能强制启用 HTTPS 让我略感不爽,有空解决之。
中午的时候突然冒出来的念头:把 Blog 的主题用 Git Submodule 来进行管理,原因也是用这种形式管理非常适合 Hexo 的结构,遂动手。

我的 _config.yml 中是将 public_dir 挂在 Hexo 目录之外,所以不用动它。而原本就在的 themes/hexo-theme-typescript 已经是一个 Git Repo 了,先将它之中的改动 push 上去,然后删了它。

将原本 themes 文件夹中的内容清空后,我同时删除了该文件夹,这也是之后二十分钟让我不知道错在何处的原因。

删去 themes 文件夹之后我们来添加 submodule, 命令很简单,一句 git submodule add就可以搞定,然后会自动帮你 clone 下来并且在根目录下生成 .gitmodules 保存 submodule 信息。

搞定之后尝试跑跑看有没有问题,hexo g 之后发现警告信息:”No Layout: index.html”. 我心想,不对啊,文件没缺啊,你怎么就找不到 Index 的 Layout 信息了呢?首先想到的是,Git 的 Submodule 是不是用了某种 link, 以至于 hexo 读不到这个文件夹的内容,于是用 ls 查看之,ls 告诉我 theme 和 hexo-theme-typescript 都是实打实的文件夹而不是软链接,百思不得其解,Google 之,发现这个警告代表的文件百分之百是由于文件缺失。然而我的文件都在啊,没缺啊,就认为是 submodule 的问题,参考了别人的 hexo 用 submodule 方式管理的文章之后,我突然想到,会不会是原本文件目录是 “themes” 而我建 submodule 时候用的是 “theme”, 缺了个 ‘s’ 导致的文件缺失呢?于是我新建了一个文件夹跑了一下 hexo init 看看文件目录结构,果不其然,用的确实是 “themes”, 重新把 submodule 建好,用对文件夹名字,运行 hexo s, 打开本地页面,熟悉的主页终于回来了。

>>endl;

GBF2Weibo 开发记

上周末和这周头上都一直在写那个 GBF 自动发 PO 到微博的工具(github),到目前为止也就实现了一半,后半部分自动发 PO 的功能因为新浪的限制,已经没办法做到以前 FaWave 那种形式的发送微博了。我的想法是绕路,通过在 weibo.com, 也就是网页版微博中插脚本,实现将文本插入到发送框,同时图片也插入进去,然后模拟点击发送按钮。上周日下午研究了一小时的微博首页,文本插入到发送框和模拟点击发送是能够做到的,但是就是不知道如何插入图片。在这里我又产生了一种绕路想法,就是模拟 Ctrl + C/V 的键盘操作来进行复制粘贴工作,然后,坑了。

写这玩意儿的过程中,因为需要自己获取当前的 RaidCode, 也就是那个八位参战码。GBF 页面加载完存在一个 “stage” object, 其中 .pJsnData.twitter.battle_id 就是我需要的码。那么就需要将这个码传递出来,而 Chrome 对于 Extension 是有非常严格的限制的,Extension 的 Content Script 和 Extension 本体是处于不同的沙盒之内的,所以就不能直接用 var raidCode = stage.pJsnData.twitter.battle_id 这种形式,而是要通过 Chrome 的 Message Passing API 来传递信息。苦学了好几天的消息传递都不能达到目的的时候,我想起来 Viramate 提供了外部获取数据的 API, 那我直接调用 API 来得到整理过的信息不是更方便吗?说是这么说,看了半天源码之后发现它没提供现成的 RaidCode 直接返回,发邮件询问作者之后得知,原来有提供战场数据的返回,但没有直接的 RaidCode 返回,不过已经能满足我的需求了。

其实作者在说明文档中有写这个 API, 但他写返回内容的时候写了”a bunch of shit”,所以我当时看文档的时候也就忽视掉了这个 API.

有了现成的数据源,我只需要将其解析就行了。随后遇到了一些奇奇怪怪的小问题,大部分都是新手常见问题,值得一提的是,JS 的执行时间点与其在页面里的加载位置有关系,比如说,放在<head>里的要比<body>中的早执行(表意可能有问题)。

文本生成成功了,那么就是 Boss 图片的问题了。这里又出现了新的问题,GBF 这么多 Boss, 我一个个去下图片写信息要花太多时间。于是想到 GBF RaidFinder 有提供 Boss 数据导出的 json, 那么我写一个从这个 json 中获取信息并自动下载图片的程序来自动化不就行了。请出我们的 Visual Studio 和 C#.

自动化程序的大体思路是这样的:读 json 产生对象数组 -> 数组排序去重 -> 将原数组数据根据自己需求导入自己定义的对象数组中 -> 读自己定义的对象数组中的图片 URL 并进行下载。

在写排序的时候发现自己把以前学过的排序算法都忘记了,使劲回忆了不少时间才写出了一个冒泡排序。然后是去重的问题,我并没有学习过去重算法,Google 之,众说纷纭,我选择了一个使用 List 的方案,最后以一句精简的 Lambda: if (list.Exists(x=>x.Name_EN==_mb.Name_EN) == false){ list.Add(_mb); }搞定之。现在想来原理很简单,一个条件判断——“如果 List 中不存在同名(对象属性)对象,则添加之。

对了,C# 中还有个设计就是对象数组申明之后需要进行每个数组元素的初始化即创建对象,不然会运行时报错。

感叹一句,C# 是真的方便实用,MS 已经几乎给好了你所有需要的轮子,你只需要将这些东西拼起来,自己写点胶水就可以了。对于一个 Windows 平台上的小工具来说,C# 是特别方便的。

大体上这整一套开始有实用的代码写入是周日下午,最后写完半成品是在周一晚上,第一次写一个“能用”的小玩意儿还是很开心的。

>>endl;

Hello,World.\n

想自己架个 Blog 好几个月了,开始用了 Jekyll,在 Windows 上做本地生成不太方便,扔远程机器上有时候自己会忘记目录结构也很麻烦。

很早就听说过几个著名的博客框架,什么 WordPress, Ghost, Hexo, Jekyll. 最后我还是选择了 Hexo, 原因有几个:

  • 我需要静态文件
  • 我得看得懂
  • 可以在 Windows 平台上进行静态文件生成
  • 简洁

那么最后试用了一下 Hexo, 感觉不错,Windows 上跑的挺欢快,主题也挺多,修改起来自己也看得懂点。

还是要感谢 Node.js 这玩意儿

那么架好了,写些什么呢?

上上礼拜刚 Uninstall 了 PUBG, 给自己的理由是挂太多了不想玩,其实主要的一点是一开游戏一晚上就没了,大学时间已经不多了,还是多留给学各种各样的东西。

所以上礼拜写了 GBF2Weibo 这个半成品,学了点 JavaScript. 同时因为需要,写了个 C# 小工具来进行 Boss 数据的转化,具体过程写在之后的文章。

想了想,开篇文确实没什么能多说的,我就只能鞭策自己以后把玩游戏的时间多用来学习,没事的时候多写点文字随便记录一下,大概这也是我把 Blog 的 Title 设置为“随写”的原因吧。

>>endl;