Arch Linux 星球

September 28, 2016

Felix Yan

修复 Android ROM 的 Google 网络定位

一些定制、第三方 ROM 在安装了 Google 框架后,仍然无法使用其网络定位功能。我在网上搜索了许多资料,整理如下。

本文假设你的设备已经 Root,并已经安装了 Google 框架。我测试用的 ROM 为一加氢 OS。

一、准备工具

需要准备的工具有 zip、unzip、apktool、adb、zipalign,以及一个好使的文本编辑器。

(注意 zipalign 工具可能不在 $PATH 中,如 Arch AUR 包 android-sdk-build-tools 安装后会放在 /opt/android-sdk/build-tools/$pkgver/zipalign)

二、提取需要的资源

取出 ROM 中的 framework-res.apk,并反编译得到需要修改的文件:

adb pull /system/framework/framework-res.apk
apktool if framework-res.apk
apktool d framework-res.apk

三、修改文件

修改位置提供商相关设置,使用 Google 提供网络定位。

1、修改 framework-res/res/values/arrays.xml,找到 config_locationProviderPackageNames 的位置,确保 Google 在列表中。如我的 ROM 默认只有 com.android.location.fused 和 com.amap.android.location 两项,这时应当加入 com.google.android.gms,使得最终结果类似这样:

<string-array name="config_locationProviderPackageNames">
        <item>com.google.android.gms</item>
        <item>com.android.location.fused</item>
        <item>com.amap.android.location</item>
    </string-array>

2、修改 framework-res/res/values/bools.xml,启用 config_enableNetworkLocationOverlay 和 config_enableFusedLocationOverlay。如果原来的值是 false,把它们改成 true:

<bool name="config_enableNetworkLocationOverlay">true</bool>
    <bool name="config_enableFusedLocationOverlay">true</bool>

3、修改 framework-res/res/values/bools.xml,设置 config_networkLocationProviderPackageName 为 com.google.android.gms。

<string name="config_networkLocationProviderPackageName">com.google.android.gms</string>

(我一并修改了 config_fusedLocationProviderPackageName 为 com.android.location.fused,虽然可能是不必要的)

四、应用修改

1、重新编译,并从结果中提取出需要的部分:

apktool b framework-res
unzip -j framework-res/dist/framework-res.apk resources.arsc -d ./

2、将提取出的文件替换到原来的 framework-res.apk 中:

cp framework-res.apk framework-res-modified.apk
zip -u0 framework-res-modified.apk resources.arsc

3、对资源进行 4 字节对齐处理:

zipalign 4 framework-res-modified.apk framework-res-aligned.apk

4、将修改后的 ROM 和更新脚本上传到手机:

这个更新脚本是我自己写的,主要处理了权限问题:

install-framework-res.sh

#!/bin/sh
mount -o remount,rw /system
mv "$1" /system/framework-res.apk
chmod 644 /system/framework-res.apk
chown root:root /system/framework-res.apk
mv /system/framework-res.apk /system/framework/framework-res.apk

和修改后的 framework-res-aligned.apk 一起上传到手机:

adb push framework-res-aligned.apk install-framework-res.sh /sdcard/

5、运行脚本,替换 apk 文件:

adb shell

如果此时得到了 $ 命令符,请先获得 root:

su

然后运行脚本:

sh /sdcard/install-framework-res.sh /sdcard/framework-res-aligned.apk

6、重启到 Recovery,清空 Cache & Dalvik Cache,再次重启回到系统。

至此,你的手机应该重新拥有了网络定位功能,赶快打开一个除地图以外的需要定位的 App (比如 Ingress)测试吧!

参考资料:

by Felix Yan at September 28, 2016 02:39 PM

September 13, 2016

ヨイツの賢狼ホロ

利用 CUPS 和 Samba 在 Arch Linux 和 Windows 间共享打印机

社团新买的打印机到啦,于是就要设置一下呗~ 😋

CUPS,Samba 都是些啥?

CUPS(以前为 Common Unix Printing System,UNIX 通用打印系统的缩写,但现无官方全名) 是一个类Unix操作系统的组合式印刷系统,允许一台电脑作为打印服务器。 CUPS接受一个客户端的电脑进程,并送到相应的打印机。

虽然有其他的打印程序包例如LPRNG,但CUPS是相当流行和相对容易使用的。 它是Arch linux及许多其他Linux发行版缺省的打印系统。

ArchWiki:CUPS

Samba是一个用于局域网中的计算机间文件共享的软件,这么说您大概还摸不着头脑,那么网上邻居您听说过吧? 对,Samba就是干这个的。当年那个有点软公司设计了一套局域网计算机间的文件共享协议, 起名叫做SMB,就是Server Message Block的缩写。当时所有的Windows系统就都集成这种协议, 因此这个协议在局域网系统中的影响还比较大。后来,国际互联网,也就是Internet逐渐流行了起来, 有点软公司希望他们的这个协议能够一个用在Internet上,因此对其进行的整理, 更名为CIFS,也就是Common Internet File System。从名字可以看出,他们的期望是很高的 ,不过实际呢……反正,你现在用网上邻居上搜狐么?当然,不管怎样,CIFS或者说SMB协议在局域网中传输文件还是非常方便的。 当然,我们Linux系统之间也有很好的局域网共享文件的协议,叫做NFS, 网络文件系统的缩写。但无奈那该死的查皮不支持这个协议嘛,所以要想网络上的查皮和我之间能共享文件的话, 要么我这里有人能懂CIFS协议,要么查皮那里有软件能解析NFS协议。 然而毕竟还是我这里的软件大度一些,所以就有了用于支持SMB协议的软件——Samba。

笨兔兔的故事 - Ubuntu中文论坛

首先……😋

在 Windows 上连接好打印机,安装上驱动,再通过“设备与打印机”共享这个打印机,Windows 上的设置就完成啦~

记得记下来 Windows 电脑的 IP 地址和打印机的名称,还有给共享打印机的账户设置个密码。

然后……😋😋

打开汝的 Arch Linux ,先安装必要的软件包:

# pacman -S cups, ghostscript gsfonts samba

然后激活并启动 CUPS 服务:

# systemctl enable org.cups.cupsd.service --now

这个时候就可以通过 http://localhost:631 访问到 CUPS 的 Web 界面啦~

CUPS Web 界面

添加打印机 😋😋😋

首先点击 "Administration" 打开管理界面:

CUPS Administration 界面

然后点击 "Add printer",这时会要求汝登录.咱只试过 root 登录能成功.....

登录到管理界面

接下来选择要连接到哪种打印机啦,连接 Windows 打印机就选择 "Windows Printer via SAMBA" (通过 Samba 连接 Windows 打印机) 呗~

选择一种协议

接下来输入打印机的 URI 啦, 对于 Windows 打印机 ,URI 大概像这样:

smb://{用户名}:{密码}@{Windows 的 IP 地址}/{打印机名称}
要连接到哪个打印机?

接着用人类的语言描述一下这台打印机(例如名字和位置啦)~

描述这台打印机

然后依照打印机的品牌和型号选择适合的驱动程序呗:

咱这台 Samsung M2070 的打印机要从三星的网站上下载驱动 _(:з」∠)_

http://www.samsung.com/printersetup

选择打印机驱动程序

接着修改默认打印参数,保存,新的打印机就添加好啦~ 😋

修改默认打印参数

为了测试打印机,可以从 Maintaince 菜单中选择 “Print Test Page” 打印一张测试页试试 😋

Maintaince 菜单

还有记得添加汝自己成为可以使用打印机的用户:

Administration 菜单 添加允许使用打印机的用户

然后桌面环境下的程序应该可以看到打印机了啦~(例如 GNOME)

GNOME 下的打印机菜单

😋

by ホロ at September 13, 2016 04:00 PM

百合仙子

Linux 下的 Wi-Fi 分享

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

首先看看你的网卡和驱动组合是否支持这样的操作。

>>> iw list | grep -A2 combinations:
        valid interface combinations:
                 * #{ managed } <= 1, #{ AP, P2P-client, P2P-GO } <= 1, #{ P2P-device } <= 1,
                   total <= 3, #channels <= 2

上边这个输出说明支持,并且频道可以不一样。

然后,添加一个用途 AP 的网络接口,并配置 IP 地址。我的无线网络接口名字是 wlan0,因为我通过创建空 /etc/udev/rules.d/80-net-setup-link.rules 文件的方式禁用了 systemd 的网络接口改名。

sudo iw dev wlan0 interface add wlan0_ap type __ap
sudo ifconfig wlan0_ap 192.168.17.1

配置 NAT:

echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
sudo iptables -w -t nat -A POSTROUTING -s 192.168.17.0/24 -j MASQUERADE

配置 DHCP。我用的是 dnsmasq。它本来是作为 DNS 缓存用的,但是也支持 DHCP,那就用它了:

interface=wlan0_ap
no-dhcp-interface=wlan0
dhcp-range=192.168.17.50,192.168.17.150,12h

注意不要在其它只提供 DNS 服务的接口上提供 DHCP 服务,以免出现冲突。

然后就可以开启热点啦。hostapd 配置如下:

interface=wlan0_ap
driver=nl80211
ssid=名字
channel=1
hw_mode=g
ieee80211d=1
country_code=cn
ieee80211n=1
ieee80211h=1
ignore_broadcast_ssid=0
auth_algs=1
wpa=2
wpa_passphrase=secret
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP

最后把它们跑起来就可以了。

为了方便使用,我创建了个 systemd 服务 wlan0_ap.service:

[Unit]
Description=Setup wlan0_ap
Before=hostapd.service
After=sys-subsystem-net-devices-wlan0.device
After=iptables.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/iw dev wlan0 interface add wlan0_ap type __ap
ExecStart=/usr/bin/ip address add dev wlan0_ap 192.168.17.1/24
ExecStart=/usr/bin/iptables -w -t nat -A POSTROUTING -s 192.168.17.0/24 -j MASQUERADE
ExecStop=-/usr/bin/iptables -w -t nat -D POSTROUTING -s 192.168.17.0/24 -j MASQUERADE
ExecStop=/usr/bin/ip address delete dev wlan0_ap 192.168.17.1/24
ExecStop=/usr/bin/iw dev wlan0_ap del

[Install]
WantedBy=hostapd.service

systemctl enable wlan0_ap 之后就可以直接 systemctl start hostapd 来启动了~当然也很容易停止服务:systemctl stop hostapd wlan0_ap。我的 dnsmasq 总是开启的,所以就不用加依赖了。还有 ipv4_forward 我也是早就写到配置文件 /etc/sysctl.d/99-sysctl.conf 里的。

by 依云 at September 13, 2016 04:26 AM

September 10, 2016

百合仙子

Jupyter + matplotlib = ♥

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

matplotlib 是很不错的数据可视化库,然而每次写一个脚本,跑出来看完又回头改,改完再跑,实在是累。所以就有 IPython Notebook 啦,后来改名叫 Jupyter 了,不光支持 Python,还支持 Julia 什么的样子(在下一盘很大的棋呢)。

Arch Linux 用户使用以下命令安装:

sudo pacman -S jupyter-nbconvert jupyter-notebook

我没有装 mathjax 这个包。我就用 MathJax 官方的 CDN 地址好了。所以我的启动命令是这样子:

jupyter notebook --NotebookApp.mathjax_url=https://cdn.mathjax.org/mathjax/latest/MathJax.js

然后界面就会在浏览器里打开啦~

Jupyter notebook 最令我不爽的一点是,它的编辑区用起来很不习惯: 不支持 readline 式快捷键(就是 Emacs / bash 风格那些啦) 不支持选中复制、中键粘贴 * 不支持补全

我尝试过配置快捷键,但是还是不太会的样子,好像又没有现成而且可用的代码。

不过它的可视化和交互能力实在是太吸引人了~所以做一些交互式的数据处理时还是用用好了~

这里是演示。(当然只是导出的 HTML 页面~)

by 依云 at September 10, 2016 08:11 AM

如何取消对 WoSign 根证书的信任

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

WoSign 最近曝出一大堆问题,而且其处理问题的态度、解决问题的方式十分令人担忧。其官方形象也很糟糕,比如对国内 Let's Encrypt 用户进行 FUD 式威胁,比如只吊销了因 bug 误发的 GitHub 域名的证书,给某大学误发的证书视若无睹。具体问题有兴趣的可以去相关邮件组查看讨论。

这次问题我认为比起 CNNIC 要严重多了(最主要是这态度、这水准,就算它不主动作恶,也很容易被利用的样子),所以我获知情况之后就取消对了 WoSign 的信任。StartCom 签名 WoSign 的证书,所以需要一并吊销(反正也是一家人)。

火狐(桌面版)

依次打开「首选项」->「高级」->「证书」->「查看证书」,找到并选择 StartCom 和 WoSign 下的所有证书(使用 Shift 键可以选择连续的项目),然后点「编辑信任」按钮,取消弹出框中三个选项框的勾选。

Arch Linux

archlinuxcn 源用户直接执行命令:

sudo pacman -Sy revoke-disputable-ca

手动操作的话,是这样子。把需要取消信任的证书复制(不要软链接)到 /etc/ca-certificates/trust-source/blacklist/ 目录下,然后执行 update-ca-trust 命令即可。

我那个包里取消信任的证书是下边这八个:

CA_WoSign_ECC_Root.pem                    CNNIC_ROOT.pem                          StartCom_Certification_Authority_G2.pem  WoSign_China.pem
Certification_Authority_of_WoSign_G2.pem  StartCom_Certification_Authority.1.pem  StartCom_Certification_Authority.pem     WoSign.pem

Android

在「设置」->「安全」->「受信任的凭据」中禁用掉相关证书。这对 Opera Mobile 有效,但是对火狐无效。

目前还没找到火狐 Android 版禁用根证书的方式。

确认方法

访问 https://www.wosign.com/ 即可。

目前 USTC 已经更改证书,禁用这些根证书不影响 USTC 镜像源的使用。现在我因此不能访问的网站主要是 Python 邮件列表

by 依云 at September 10, 2016 07:39 AM

September 07, 2016

Phoenix Nemo

搭建一套权威 DNS 服务架构

萌 DNS 已经年久失修。尽管一直有计划完全重写出一套应用目前各种 DNS 特性和优化的完整平台,但是目前的精力不允许。所以为了先让萌 DNS 的用户们至少先有一个能支持 Let’s Encrypt 的 DNS 服务,决定暂时舍弃 GeoDNS 功能,使用一套更加成熟的解决方案提供服务。

搭配方案如下:

服务器部署:

  • 管理服务器 x1
    • MySQL Master
    • PowerDNS
    • PowerDNS-Admin, supervisor, virtualenv, gunicorn…
    • NGINX, Let’s Encrypt
  • DNS 服务器 x4
    • MySQL Slave
    • PowerDNS

在管理服务器上安装 PowerDNS 和 MySQL Master 的考量是由于 PowerDNS-Admin 使用 PowerDNS HTTP API,在管理服务器(或管理私网中)启动一个仅用于提供 API 和操作主数据库的 PowerDNS 实例能够减轻 Primary NS Server 的压力并提升安全性。整套架构使用 Ansible 进行自动化部署,不过好久没用了各种生疏,照着文档折腾好久的配置…

于是这里暂且记录下整个过程。有些坑只是作者一时疏忽或者有别的考量但没有明确记录,也许在未来的版本中会修复。

安装 PowerDNS

所有服务器均使用 Ubuntu 16.04,需要 PowerDNS 4.0 以上的版本。按照此页面的说明添加 PowerDNS 官方的仓库即可。

1
# apt install pdns-server pdns-backend-mysql mysql-server

由 dpkg 自动配置 PowerDNS 的数据库,然后删除 /etc/powerdns/pdns.d无关的配置文件。

1
2
# rm /etc/powerdns/pdns.d/pdns.local.conf
# rm /etc/powerdns/pdns.d/pdns.simplebind.conf

配置 MySQL Replication,管理服务器作为 Master,其他 DNS 服务器作为 Slave。细节不多讲,官方文档 或者 DigitalOcean Tutorial

管理服务器 (MySQL Master) PowerDNS 配置文件 /etc/powerdns/pdns.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
api=yes
api-key=yourapisecretkey
api-logfile=/var/log/pdns-api.log
config-dir=/etc/powerdns
guardian=yes
include-dir=/etc/powerdns/pdns.d
launch=
local-address=127.0.0.1 # 不对外提供服务
local-ipv6=::1
security-poll-suffix=
setgid=pdns
setuid=pdns
webserver=yes
webserver-address=127.0.0.1 # 仅向本机的 PowerDNS-Admin 调用。如果配置在内网,请使用内网 IP
webserver-allow-from=127.0.0.1/32 # 同上,如果使用内网则写 PowerDNS-Admin 在内网的 IP
webserver-port=8081
default-soa-name=ns1.example.com # 改为 Primary NS 的地址
default-soa-edit=INCEPTION-INCREMENT
default-soa-mail=hostmaster.example.com # 改为默认服务器管理员的邮箱地址,并将 '@' 替换为 '.'
default-ttl=3600

DNS 服务器 (MySQL Slaves) PowerDNS 配置文件 /etc/powerdns/pdns.conf

1
2
3
4
5
6
7
8
9
10
11
config-dir=/etc/powerdns
daemon=yes
disable-axfr=yes
guardian=yes
include-dir=/etc/powerdns/pdns.d
launch=
security-poll-suffix=
server-id=ns1.example.com # 改为当前服务器的 ID,ns1/ns2/ns3/etc...
setgid=pdns
setuid=pdns
version-string=anonymous # 可以写任意字符串恶搞_(:з」∠)_

安装 PowerDNS-Admin

作者有提供详细的教程但是还是有坑

安装依赖:

1
# apt install git python-pip supervisor virtualenv python-dev libmysqlclient-dev libsasl2-dev libldap2-dev libssl-dev letsencrypt

创建数据库,切换到普通用户权限,clone 仓库到本地,然后一步一步操作即可。

1
2
3
4
5
6
7
8
$ git clone https://github.com/ngoduykhanh/PowerDNS-Admin.git
$ cd PowerDNS-Admin
$ virtualenv flask
$ source ./flask/bin/activate
$ pip install -r requirements.txt
$ pip install mysql gunicorn
$ cp config_template.py config.py
$ vim config.py

配置文件 config.py 中需要更改的地方:

1
2
3
4
5
6
7
8
9
SECRET_KEY = 'yoursessionencryptkey'
SQLA_DB_USER = 'yourdbusername'
SQLA_DB_PASSWORD = 'yourdbpassword'
SQLA_DB_HOST = 'localhost'
SQLA_DB_NAME = 'yourdbname'
PDNS_STATS_URL = 'http://localhost:8081/'
PDNS_API_KEY = 'yourapisecretkey'
PDNS_VERSION = '4.0.0'
RECORDS_ALLOW_EDIT = ['A', 'AAAA', 'CNAME', 'SPF', 'PTR', 'MX', 'TXT', 'SRV', 'NS', 'SOA']

然后执行 ./create_db.py。如果没有报错说明数据库安装成功,执行 ./run.py 即可访问 http://127.0.0.1:9393 看到登陆页面了。

部署 Web 服务

直接跑 run.py 当然不科学。Supervisor 配置文件 /etc/supervisor/conf.d/pdnsadmin.conf

1
2
3
4
5
6
7
8
9
10
11
[program:pdnsadmin]
command=/home/pdns/PowerDNS-Admin/flask/bin/gunicorn run:app
directory=/home/pdns/PowerDNS-Admin/
user=pdns
autostart=true
stdout_logfile=/var/log/supervisor/pdns-stdout.log
stdout_logfile_maxbytes=1MB
stdout_logfile_backups=2
stderr_logfile=/var/log/supervisor/pdns-stderr.log
stderr_logfile_maxbytes=1MB
stderr_logfile_backups=2

创建 DHParam

1
2
# cd /etc/ssl/certs
# openssl dhparam -out dhparam.pem 4096 # 如果性能不够请使用 2048

NGINX 配置文件 /etc/nginx/site-enabled/pdnsadmin.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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
server {
listen 80;
server_name dns.example.com;

location /.well-known {
default_type "text/plain";
root /var/www/html;
}

location / {
return 301 https://dns.example.com$request_uri;
}
}

server {
listen 443 ssl;
listen [::]:443 ssl;
server_name dns.example.com;

ssl on;
ssl_certificate /etc/letsencrypt/live/dns.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/dns.example.com/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";
keepalive_timeout 70;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

ssl_dhparam /etc/ssl/certs/dhparam.pem;

add_header Strict-Transport-Security max-age=63072000;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;


access_log /var/log/nginx/dns.example.com.access.log;
error_log /var/log/nginx/dns.example.com.error.log;

location /.well-known {
default_type "text/plain";
root /var/www/html;
}

location /static {
alias /home/pdns/PowerDNS-Admin/app/static;
}

location / {
proxy_pass http://127.0.0.1:8000;
proxy_redirect default;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forward-IP $remote_addr;
port_in_redirect on;
server_name_in_redirect off;
proxy_connect_timeout 300;
}
}

记得把 dns.example.com 换成自己的域名。

签发 Let’s Encrypt。也不多讲。NGINX 配置中已经有了针对 Let’s Encrypt 的续期设置。

然后重启各项服务

1
2
# systemctl restart supervisor
# systemctl restart nginx

查看 PowerDNS-Admin 的运行状态,使用 supervisorctl status

添加 GLUE 记录

要使自己的 NS 生效,必须有保存在上级 NS 中的记录。很多域名注册商都提供了配置 GLUE 记录的功能,例如 Hexonet (1API):

Glue Records

简言之,需要把自己的 NS 服务器及对应的 IP 记录到上级 NS。完成之后,通过 PowerDNS-Admin 添加自己的域名,zone 类型为 NATIVE。然后添加所有 NS 服务器的 A/AAAA 以及所有的 NS 记录——你没听错,要自己写 NS 记录。其他域名也需要添加这些 NS 记录,否则不会托管。

Glue Records

收尾

全部完成之后就是一个完整功能的 DNS 服务了。如果希望启用 DNSSEC,需要在管理服务器中通过 pdnsutil 来添加 key。

由于目前 PowerDNS-Admin 没有限制不能添加提供的 NS 之外的名称服务器,所以其他域名按照添加 GLUE 记录的方法,也可以将这些 NS 服务器「变成」自己的 NS。

好了,不会说话了。讲效果——

一般来说,DNS 服务都会提供多台 NS 服务器域名,将域名的 DNS 改为这些 NS 服务器才能托管到该 DNS 服务上。但是现在只需要知道这套 DNS 的服务器 IP 地址,即可给自己的域名添加 GLUE 记录、NS 记录和 NS 对应的 A/AAAA 记录进而使用自己的域名作为 NS,而不需要用 DNS 服务的 NS 域名。当然一般就是看起来会比较厉害而已…

萌 DNS 已经年久失修。尽管一直有计划完全重写出一套应用目前各种 DNS 特性和优化的完整平台,但是目前的精

September 07, 2016 02:11 PM

用优雅的方式在 OS X 中为单个应用设置语言

买到 CLIP STUDIO PAINT Pro,激活之后发现不给启动,显示 Unsupported OS 并退出。搜索了下发现是因为语言设置的问题导致,需要将系统环境设置为应用所支持的语言才能运行。

嘛。日本人做事情也是让人无话可说,那么多应用都没有多语言支持的… 用能支持的语言来显示就好了嘛。

话说回来,我一开始设置的系统语言是简体中文,虽然后备语言加了 English 和日本語,不过有些不能自动变更语言的应用在更换系统语言为 English 之后变得很别扭。于是寻找可以单独设置应用语言的方法。

用惯了 Linux 再用 OS X 其实并没有那么容易的改变习惯… 当我准备尝试单独 export 一份 locale 再运行 app 的时候 OS X 直接告诉我不适用我的表情简直和伊莉雅一样。

睡了一觉起来继续 Google。找到了可以单独为应用设置语言并且 launch 的 app Language Switcher,看起来不错,但是每次启动 CLIP STUDIO PAINT 都要先打开这货,这不是我想要的效果。

于是最终找到一个合适的解决方案:用 defaults 命令。

原帖在这里

设置 CLIP STUDIO PAINT Pro 语言环境命令:

1
defaults write jp.co.celsys.CLIPSTUDIOPAINT.lip AppleLanguages '("en-US")'

其中 jp.co.celsys.CLIPSTUDIOPAINT.lip 可以在应用的显示包信息 -> Contents -> Info.plist 中找到。

执行后就可以直接双击启动啦~

最后献丑一张w

Kira( > ◡╹)~

买到 CLIP STUDIO PAINT Pro,激活之后发现不给启动,显示 Unsupported OS 并退出。搜索了下发现是因为语言设置的问题导致,需要将系统环境设置为应用所支持的语言才能运行。

嘛。日本人做事情也是让人无话可说

September 07, 2016 01:48 PM

Sierra 4G LTE EM7345 with Arch Linux

X1 Carbon 2015 内置 Sierra EM7345 4G LTE 适配器,系统里看到是这样:

1
2
$ lsusb
Bus 001 Device 002: ID 1199:a001 Sierra Wireless, Inc.

根据 ThinkPad EM7345 4G LTE Mobile Broadband - Overview and Service Parts 这块 EM7345 基本完美支持联通的 3G/4G 制式。

插入 microSIM 卡,然后安装需要的包:

1
# pacman -S usbutils usb_modeswitch modemmanager mobile-broadband-provider-info

启用 modemmanager 服务

1
systemctl enable modemmanager.service

然后加载内核模块 cdc_mbim,文件 /etc/mkinitcpio.conf

1
MODULES="... cdc_mbim"

重新生成内核镜像

1
# mkinitcpio -p linux # or change to your kernel preset here

重启即可在 NetworkManager 中新建 GSM 设备的 broadband (移动宽带) 连接。

顺便上一张图,老家小城市还是郊区所以 4G 信号几乎没有,还是达到了这个速度,点个赞(๑•̀ㅂ•́)و✧

Sierra EM7345 4G LTE Speedtest on China Unicom

参考文档:

X1 Carbon 2015 内置 Sierra EM7345 4G LTE 适配器,系统里看到是这样:

September 07, 2016 01:48 PM

ThinkPad X1 Carbon 2015 与久违的 Arch Linux

对 X1 Carbon 2015 垂涎已久。然而中国市场不提供定制配置、没有 16G 内存的版本、512G PCIe SSD 的型号配置触控屏。这些都不能忍…于是折腾了好久,打扰了至少三位在美国的朋友,最终在黑色星期五当天下单,前天顺丰到手。

先晒一下单。这个配置在联想美国官网购买的原价是 2622.60 美元,黑色星期五的各种优惠后价格是 1630 美元。嘛… 多出来的预算败了一块 1TB SSD 当移动硬盘,真是麻烦帮忙带回国的朋友了(っ‘ω’c)

X1 Carbon 2015 20BSCTO1WW

  • Intel Core i7 5600U 2.6GHz / 3.6GHz
  • 16G (2x8G) DDR3 1600MHz On-board RAM
  • 512G PCIe SSD
  • 2560x1440 QWHD IPS
  • Fingerprint Reader
  • Sierra LTE EM7345

其中 SSD 是 SAMSUNG SM951,测试读写速度分别为 1546MB/s 和 1260MB/sdmidecode --type memory 显示有两条镁光制造的内存,这个倒是和网络上流传的单根内存不太一样。不过两根都是 on-board,所以是无法更换的。

屏幕颜色偏暖,大概是为了长时间工作不会太劳累设定的。ThinkScope 提供了一份 ICC 文件,效果有点偏蓝(紫红?)。不过屏幕型号并不是页面上写的 LG LP140GH1-SPA2,而是 LG LP140QH1-SPB1。总之雾面屏加 86% sRGB coverage 导致它的显示效果比旁边的 MacBook Pro Retina 差了一大截,而且 HiDPI 带来软件上的问题… 嘛这个后面再说。

X1 Carbon 2015 整个机身做工很好,拿着很有份量(不是沉!)给人一种很结实的感觉,完全没有其他 ThinkPad 的塑料感。唯一略心颤的是屏幕没办法像 MacBook Pro 一样稳,和其他笔记本一样调整屏幕角度还是会晃动几下,大概是铰链设计的差异导致。键盘仍然是那个熟悉的手感——哪怕是悬浮式键帽,仍然和老式 ThinkPad 键盘手感不相上下。换到这么舒服的键盘之后打字速度已经快到让 fcitx 分不清键序啦( ´∀ )σ)Д`)其实是 GTK 程序的 bug。ThinkLight 改到键盘下方,可以更好地看清键帽更高大上了,但是没办法当作光源看其他东西… 不过本来也不怎么亮还是爱护下眼睛吧。触控板很舒服,虽然大概还是不够和 MacBook Pro 相比,毕竟人家有底层驱动优化,系统层还支持很多手势。单从手感上来讲还是很不错的。

新本本送到后开机检查硬件,然后当然是要删掉预装的 Windows 10 然后换上 Arch Linux 啦。之前 T420 的 UEFI 安装 Arch Linux 总是启动不能,然而 X1 Carbon 就很顺利。当然是关掉了 Secure Boot 的。

续航感觉还不错,中午送到开箱检查的时候就还有 60% 的电量,然后从下午开始到晚上一直在安装配置系统,到半夜的时候报告还剩 15% 电量。中间有几次编译,所以顺便看了下散热。室内温度大概 10 摄氏度,sensors 检测高负载时最高温度 57 摄氏度,一般工作温度 35-40 摄氏度。这是有点出乎意料的,本来以为超极本的散热都会很悲剧。不过据说其他人也有到过 80 度的,所以要再用用看。

Sierra LTE EM7345 是 microSIM 槽,然而手头只有 nanoSIM 所以还没用上。回去学校把流量卡补成 microSIM 再玩玩看。

安装过程完全不折腾。硬件兼容性报告只有一句话:Everything works out of box.

如果一定要在兼容性上挑刺儿的话,大概是 GPS 只有在 Windows 下才有办法打开,打开之后就可以直接在 Linux 下用了。

回到 Arch Linux 上。一年没用,KDE 已经快不认识了。通过更改 DPI、字体大小和图标大小,Qt5 的程序算是很好的支持了 HiDPI。然而一些 GTK / Qt4 程序就没那么好说话了… 总之用各种奇怪的办法让这些跟不上时代的程序变得勉强能看。

刚开始用 MacBook Pro 不久的时候,除去再也无法接受 retina 之下的显示效果(retina 有毒啊)之外,由于键盘、输入法(!!!)、快捷键、工具链、UNIX 生态等等问题上,OS X 上的工作效率只有 Linux 的 1/3 左右(是真的,很早的时候解决一个问题大概花了一个多小时,后来在 OS X 上再次遇到却花了一个下午)。

总之用来这几天,可以说是非常满意的。没有任何生产商设置的门槛,OS-Specific 的东西通过各种 折腾 Google、折腾 IRC 频道里的各位、折腾 ArchWiki… 等基本都解决了。现在看到它就有想摸一摸、想用它工作的冲动(๑•̀ㅂ•́)و✧然后上个图~

Desktop

KInfoCenter

最后的一点牢骚。

一年多没怎么碰 Linux 桌面,虽然看起来变化很大,但是实际上的提升基本没有感觉到。倒不如说,由于硬件技术一直在革新,Linux 桌面却没有了当年的势头。前段时间去 KDE 主页看的时候发现他们把捐赠放到了首页上,而且赞助页看起来好粗糙,完全不像是 KDE 一贯精致的设计风格。从对 HiDPI 的支持来看更是如此。KDE/High-dpi issues 页面从半年前到现在基本没有太大的变化…

嘛。当然了就算是钱多得没处花的某有点软的公司也没让自己的操作系统好好的支持 HiDPI ( ´∀ )σ)Д`)

开源界仍然有大量被广泛使用的应用保持着粗制滥造、works for me 等等的心态。虽然绝大多数不会有人为之付费,但是这并不是不认真的理由。而且这样下去也并不会有多少杀手级的应用出现。

虽然作为 DevOps 的话只要有好用的命令行工具链就万事大吉了。 更何况现在厨子整天瞎搞,果子就算还能继续赚无脑追捧的大众的钱,它还能制作多少 developer-friendly 的产品呢…
(´・ω・`)

对 X1 Carbon 2015 垂涎已久。然而中国市场不提供定制配置、没有 16G 内存的版本、512G PCIe SSD 的型号配置触控屏。这些都不能忍…于是折腾了好久,打扰了至少三位在美国的朋友,最终在黑色星期五当天下单,前天顺丰到手。

先晒一下单。这个

September 07, 2016 01:48 PM

August 22, 2016

Phoenix Nemo

想要导出 Telegram 贴图

Telegram 上出现了越来越多的优质贴纸,想要把这些贴纸用到其他 IM 平台上的时候就会比较麻烦,所以一直想要一键导出一个贴纸包的功能。

可惜的是,Telegram bot API 的限制,并没有任何简单的办法通过贴纸消息获得贴纸包的信息。寻找另外的途径,例如 telegram.me 的贴纸链接会定向到 tg://addstickers?set=[StickerSet]。搜索了一下现成客户端的源码,都是交给 MTProto 的 API 处理,也没有明确的解析过程。而这些客户端所调用的 messages.getStickerSet 也没有在官方的文档中列出。(吐槽:Telegram 的协议、文档和代码真是糟糕,查阅的时候我的表情一直是 黑人问号.gif

由于最近状况不是很好,所以只好暂时放弃继续读 webogram 的源码。因为读 Angular 的东西实在是折磨…

所以依然是选择直接发 sticker 再转为图片发给用户的模式。这样的已经有了相关的 bot,于是改为多个 sticker 打包、支持多语言、支持 jpg 和 png 以及批量缩放功能的 bot。需要安装 Node.js v4.0 及以上版本和支持 webp 的 ImageMagick。

虽然实现效果看起来还可以,但是并未实现最初希望的功能,所以只能是练手用的轮子而已。不过,这个轮子稍微尝试了一些新的东西。例如超简陋的内存数据库,而且很多细节考量更加周到,例如任务锁虽然不是写过最麻烦的,不过应该算是相对完善的。当然也考虑了内存数据库的手动释放以防内存爆炸为此还特地在群里讨论了 object children 被 undefine 而 object 其他 children 还在被引用的状态下是否可以回收部分内存的问题

源码的实现非常简单,但是好久不写代码还是手生,折腾了一下午写功能加一晚上和朋友们 debug。读源码戳 GitHub

这里有一只 bot 跑在测试环境,所以可以尝试一下。如果没理你说明沙盒没开,那么就请自己去跑源码来使用辣ᕕ(ᐛ)ᕗ

有几点坑,比如这个 node-telegram-bot-apionText 方法无法正确匹配 Negative Lookahead 的正则表达式(不应该啊…然而没深究),adm-zip 非常非常不好用,jszip 文档表述不清 API 调用复杂然而用起来了就还不错。

但是最坑的是,只为实现这么一个简单功能的 bot,我的 node_modules 目录下居然有

1
2
Phoenix-X1-Carbon :: js/telegram-stickerimagebot/node_modules ‹master› » ll | wc -l                                                                                               1
104

WHAT??? 104 个依赖包!!!

真是可怕…明明我已经尽可能减少不必要的依赖了…

Telegram 上出现了越来越多的优质贴纸,想要把这些贴纸用到其他 IM 平台上的时候就会比较麻烦,所以一直想要一键导出一个贴纸包的功能。

可惜的是,Telegram bot API 的限制,并没有任何简单的办法通过贴纸消息获得贴纸包的信息。寻找另外的途径,

August 22, 2016 07:15 PM

August 19, 2016

ヨイツの賢狼ホロ

知乎自答两则

farseerfc ,顺便测试一下咱写的 creatissue 脚本 😂😂

懒得加内文里的链接了呢~

使用 Arch Linux 做桌面有何优势和注意事项?

https://www.zhihu.com/question/46322733/answer/101649684

既然是前 Debian Testing 用户,就认为汝有一定的 Linux 发行版使用经验呗~

顺便猜汝问的是“日常使用 Arch Linux”呗.

  1. Arch Linux 有啥特性?

其实 Arch Linux 和其它发行版一样就只是一个发行版呐~然而每一个发行版的生态不一样, Arch 这边信奉的是以 “Keep It Simple, Stupid” 为核心的 Arch 之道啦。哦对了,还有一个名字叫做 Pacman 的软件包管理器。 滚动更新算不算是一个特性咧?

  1. Arch Linux 的优势?

应该是软件更新速度快和(更新时)比较稳定? (可以说都是拜 Arch 的滚动发行版属性所赐呗~)

还有比较完善的 Wiki ~

还有比较完善的 Wiki ~

还有比较完善的 Wiki ~ (重要的话说三遍2333)

Arch compared to other distributions (简体中文) 上有 Arch Linux 和几个发行版的比较,去看下呗~

  1. 安装 Arch Linux 要注意啥?

Beginners' guide (简体中文) 和 Installation guide (简体中文) 都是非常好的参考来源呐~ 按 wiki 的说法,前者适合新安装 Arch Linux 的用户,后者适合有经验的 Linux 用户呗。

  1. 使用 Arch Linux 时要注意啥?

首先要学习如何使用 Arch Linux 的招牌(?) pacman 啦。 Pacman (简体中文) 上有些常用命令,如果汝有使用其它软件包管理器 (例如 Debian 里的 apt)的经验,可以看一下 Pacman/Rosetta , 那里列出了几种不同的软件包管理器的不同命令的比较。

关于各种操作(例如安装各类软件,外观定制,系统维护等等) General recommendations 里有各种操作的索引,去看一下呗~

如果遇到了问题,ArchWiki ,Arch Linux Forums , Arch Linux 中文论坛 和 IRC channels (简体中文) 都是解决问题的合适的地方咯~ (当然要遵守各自的规则啦)

  1. 啥?有人说 Arch Linux 容易滚挂?

到底是从啥时候开始有这个说法的

怎样才能尽量避免archlinux滚挂? - Arch Linux 这里的几个回答非常棒,咱就简单的总结一下呗~

System maintenance (简体中文) 有些系统维护的常见技巧。

大家都认为长期不更新的 Arch Linux 更容易挂……所以至少要记得定期更新一下系统吧~

订阅 Arch Linux 新闻 (邮件列表 arch-announce 或者RSS: https://www.archlinux.org/feeds/news/ )消息不是很频繁,一般是在有重大更新时会提醒大家。

不要在一无所知的情况下打开 [testing] 仓库。如果想打开的话, Arch Linux TU 兼 Developer 成员 @晏然FelixYan 写了篇 Arch Linux [testing] 系列仓库简介 可以参考。

有时 pacman 会提示生成了一些 .pacnew 文件,这是为了避免覆盖一个之前被修改过的已存在文件呐 ,汝最好在更新完毕以后马上合并这些改动啦~(如果不处理,不当的配置可能导致软件功能出问题,甚至完全无法使用。)

不要使用某些 pacman 命令 (例如 --force,但是官方发通告要求这样做时除外~)

最后,手边最好准备一个 Live 环境(万一一不小心把系统搞挂了……)

  1. 最后……

每个人都可以为 Arch Linux 贡献自己的一分力量,如果汝有意愿的话, wiki 上的 Getting involved 页面有各种贡献的途径呐~

还有一件事…… 欢迎来 Arch Linux 中文社区玩! ( IRC 频道 #archlinux-cn @ freenode 是中心,同时还有 Telegram , XMPP,Tox 和 Gitter 多平台联通,可能是第二水的 IRC 中文频道?) 其他平台的加入方式在 IRC 上问问其他人就好啦~

Arch Linux的用户都有理想主义倾向吗?

https://www.zhihu.com/question/49439472/answer/116599094

(话说知乎啥时候能内置水平线标记……)

其实不止 Arch Linux ,几大主流发行版不都是一群有着相同理想主义倾向的用户/开发者们一手构建起来的呗~

Debian :以创建一个自由的类 Unix 操作系统为己任,大部分尽可能的采用自由软件 (后来从 Debian 衍生出的完全自由的发行版 gNewSense 获得了自由软件基金会的赞助 )。

Fedora :和 Debian 同样更多的专注于自由软件。和 Debian 偏向稳定不同, Fedora 的开发者更多的会和上游紧密协作,尽可能的快速推动新技术的应用和完善。

openSUSE:这个咱没用过,只知道他/她/它们做了个很出色的系统配置工具 YaST , 还有能给 openSUSE 和其他各种发行版构建软件包的 Open Build Service (OBS)。 至于 openSUSE 为啥没有其它发行版那么流行的原因,活跃于 openSUSE 社区的苏姐的回答应该解释的比较全面 : openSUSE 的人气为何远不如 Ubuntu 和 Fedora ? - 瑪麗蘇的回答

Gentoo:应该是除了 LFS (Linux From Scratch)以外定制程度最高的 Linux 发行版, 用户可以自由的选择自己喜欢的组件,无论是安装方式,需要的程序, 以至于init 程序( Gentoo 是目前为数不多的不默认采用 Systemd 的 Linux 发行版之一)。 许多用户喜欢的就是 Gentoo 的高度可定制性, 例如 长期使用Arch,Gentoo等滚动更新的发行版是怎样的一种体验? - 李小的回答 和 长期使用Arch,Gentoo等滚动更新的发行版是怎样的一种体验? - ZX Huo 的回答 。

Arch Linux:自称 " a lightweight and flexible Linux® distribution that tries to Keep It Simple." , 一个轻量化,可定制,试图遵循 KISS 原则 ( Keep It Simple, Stupid,对应中文为“保持简单,且一目了然”)的 Linux 发行版。 简洁,现代,实用和以用户为中心构成了 Arch Linux 用户和开发者们一贯共识的 “Arch 之道”(Arch Linux - ArchWiki)

(Ubuntu ?那是啥,好吃吗?啦啦啦……)

关于 Arch Linux 的可定制性,现任 Trusted User 之一的 fc farseer 这么写到:

我自己用 Ubuntu 從 8.04 經歷多次版本升級升到 12.04 ,期間雙系統裝裹 OpenSuSE 和Arch , 然後在 OpenSuSE 上完成了畢業設計(那時候只有suse提供了Xen補丁內核,這是我的畢業設計需要), 之後本科畢業後新臺機直接裝 Arch,現在3年多了一切穩定完好。這 3 年多我經歷了 Arch 從 rc.conf 到 systemd 的轉變, 經歷了 grub legacy 到 grub 2 的轉變,換過好幾個 DE 和 WM 然後現在穩定在 Awesome3.4 兩年多, 系統分區從原本的 ext4 換到過 btrfs 分區然後現在組 btrfs raid1 ,我換過顯卡,換過好幾塊硬盤, 期間滾掛過好幾次然後都修好了,自己作死折騰btrfs壞過也從備份中恢復好了。重要的是這個系統一直活着而且活得很好, pacman.log裏的裝機歷史能一直追溯到3年前裝的第一個包,我知道這裏面只有我需要的包, 只有我做過的配置,發生任何問題我都知道是系統的哪裏的問題。這是 Arch給我的安心感, 是Ubuntu不能給我的。反觀我用Ubuntu的那段時間,每次 dist-upgrade 都要麼立刻掛掉要麼用一段時間掛掉, 要麼就是升級的方案實在太將就然後換新的重裝。都說 debian穩定ubuntu穩定, 而那時的我沒有任何穩定的感覺,那時的我害怕每一個小包的升級,因爲我不知道升級了一個包之後會對別的包造成什麼不可預知的後果。 服務器系統那種有管理員管理的計算機集羣需要的穩定性,和桌面用戶需要的穩定性,在我看來是不同的概念。 我不怕一個升級之後東西壞掉然後需要我花兩個小時找方案把它修好, 但是我怕爲了某個新版本的庫而不得不升級的時候, 整個系統都變得面目全非導致我不得不花兩個小時重裝系統,然後這個全新的系統我不再認識了。

—长期使用Arch,Gentoo等滚动更新的发行版是怎样的一种体验? - fc farseer 的回答

所以嘛,既然选择了滚动更新的发行版,就要学会适应这种快速的变化呗~

另外还有一句,Arch Linux 的滚动更新模型是不支持部分升级的。

https://wiki.archlinux.org/index.php/System_maintenance#Partial_upgrades_are_unsupported

还有,Archer 哪里说要秒杀各大软件公司了啦 ?明明咱们连有多少用户都不怎么在意:

许多 Linux 发行版都试图变得更“用户友好”,Arch Linux 则一直是,永远会是“以用户为中心”。 此发行版是为了满足贡献者的需求,而不是为了吸引尽可能多的用户。 Arch 适用于乐于自己动手的用户,他们愿意花时间阅读文档,解决自己的问题。

报告问题、完善 Wiki 社区文档、为其它用户提供技术支持。 Arch 用户仓库 收集用户贡献的软件包。Arch 开发者都是志愿者,活跃的贡献者很快就能称为开发人员。

不要以偏概全好不好……

by ホロ at August 19, 2016 04:00 PM

August 17, 2016

百合仙子

换域名了

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

如题。域名换成了 blog.lilydjwg.me,别的暂时不变。浏览器访问时会自动跳转到新域名。

请 RSS 订阅读者更新订阅地址。

请网站上有链接到本博客的读者也更新一下旧链接。

我不知道旧域名到底能存在多久。当然也不知道这个网站还会存在多久。总之先把入口拿回来。

by 依云 at August 17, 2016 12:06 PM

August 09, 2016

ヨイツの賢狼ホロ

为MediaWiki安装可视化编辑器

为MediaWiki安装来自 维基媒体基金会可视化编辑器 .

连维基百科都要Hold不住啦~

许多新用户不会着手大幅度修改,而只是做些细节调整,不过仅仅阅读源代码就必须学标记语言了。当我们的用户在演示操作时,这把他们吓走了。

早在 2004 年,社群开始一再认识到必须采用更好的编辑方式。因为人们的请求,更重要的是他们的需要,所以我们开发了可视化编辑器。

Wiki 标记语言让新人害怕,这种程度会随着其他站点的迁离而加剧。如果我们不开发可视化编辑器,那么图表的走势会在接下来五年中变得更加糟糕。

MediaWiki.org

所以他们才 痛定思痛 决定开发可视化编辑器么😂

开始之前-检查一下要求

可视化编辑器(下面就说VisualEditor呗~)还需要一个叫 Parsoid 的程序来承担把wiki标记转化成html的任务啦(看下图)~,所以需要服务器来运行它呐~

Parsoid的工作原理

安装Parsoid(Ubuntu 14+ / Debian 7+ )

上游的指南在这(好好学英语呗~) https://www.mediawiki.org/wiki/Parsoid/Setup

Ubuntu和Debian系统的话直接添加MediaWiki.org的软件源然后通过apt安装就好了啦~

首先添加MediaWiki.org的GPG公钥:

sudo apt-key advanced --keyserver keys.gnupg.net --recv-keys 664C383A3566A3481B942F007A322AC6E84AFDD2

然后添加Parsoid源:

sudo echo "deb https://releases.wikimedia.org/debian jessie-mediawiki main" > /etc/apt/sources.list.d/parsoid.list

安装需要的软件包:

sudo apt-get update && sudo apt-get install curl parsoid

然后看下下面一节的内容修改一下配置文件呗~

其它系统?手动安装呗~

上游的指南在这(还是要好好学英语呗~) https://www.mediawiki.org/wiki/Parsoid/Developer_Setup

首先汝要装上Nodejs(>0.8,建议0.10或更新的版本呐~),还有git. 具体的安装方法为了避免降低正交性 (其实是系统太多不好写......),就麻烦汝自己去找了呐~

「呵。咱是贤狼,不是神呐。如果汝开始会期待起咱能够泄露天机给汝,那咱就得从汝眼前消失了呗。」
node --version # 如果是Debian或Ubuntu ,输入 nodejs --version

然后用git克隆版本库呗~

git clone https://gerrit.wikimedia.org/r/p/mediawiki/services/parsoid

用npm安装上相应的依赖:

npm install

然后看下面一节的内容修改一下配置文件呗~

修改配置文件

如果是通过软件源安装的,配置文件位于 /etc/mediawiki/parsoid/config.yaml

如果是通过git下载的,从parsoid目录中先复制一份样例出来呗~

cp config.example.yaml config.yaml

打开配置文件,找到这一段内容,然后改它~:

mwApis:
    - # This is the only required parameter,
      # the URL of you MediaWiki API endpoint.
      uri: 'http://localhost/w/api.php'
      # The "domain" is used for communication with Visual Editor
      # and RESTBase.  It defaults to the hostname portion of
      # the `uri` property below, but you can manually set it
      # to an arbitrary string.
      domain: 'localhost'  # optional

其中"uri"对应汝的wiki的api.php的位置,"domain"是汝的域名啦~. "prefix"可以自己起一个(反正因为换了API也没用啦~,不过测试时可能用得到) Prefix 真的没了……

启动服务

从软件源安装的?

sudo systemctl start parsoid # Debian Jessie ,用Systemd启动

sudo service parsoid start # Debian Wheezy 或Ubuntu ,用init.d脚本启动.

如果汝不是通过远程访问执行的命令,可以在浏览器上打开 http://localhost:8142 来进行测试.试着加载 http://localhost:8142/汝设置的前缀/汝的wiki上的一个页面 试试呗~

用git安装的?

npm start

或者:

node bin/server.js

可以用screen一类的工具让Parsoid在后台运行~

或者可以自己写一个 Systemd 单元 (听说这样更清真?

咱自己写了一个在这: https://gist.github.com/KenOokamiHoro/44d6e1b20f5bad4a0f56e9e225d2049a

如果汝不是通过远程访问执行的命令,可以在浏览器上打开 http://localhost:8000 来进行测试.试着加载 http://localhost:8000/汝设置的前缀/汝的wiki上的一个页面 试试呗~

修改监听地址便于远程测试

改这一段:

# Allow override of port/interface:
#serverPort: 8000
#serverInterface: '127.0.0.1'

反注释最后一行并改成0.0.0.0,就可以通过 http://服务器的IP地址:8000 访问啦~

安装VisualEditor扩展

上游的指南在这: https://www.mediawiki.org/wiki/Extension:VisualEditor

首先从 这里 获得扩展然后上传到汝的wiki上的extensions目录呗~

然后修改汝的LocalSettings.php:

require_once "$IP/extensions/VisualEditor/VisualEditor.php";

// 反注释下一行来默认启用可视化编辑器
#$wgDefaultUserOptions['visualeditor-enable'] = 1;

// 反注释下一行来启用测试中的功能
#$wgDefaultUserOptions['visualeditor-enable-experimental'] = 1;

//在除了主名字空间以外的名字空间中也启用可视化编辑器(下面的例子是用户名字空间)
$wgVisualEditorNamespaces=array_merge($wgContentNamespaces,array( NS_USER ));

完整的设置选项可以在扩展页面上找到.

然后在汝的wiki上试试看呗~

VisualEditor效果

by ホロ at August 09, 2016 04:00 PM

August 08, 2016

farseerfc

为什么 Linus Torvalds 不愿意将 Linux 变成 GPLv3 授权?

知乎 转载

和上篇文章一样,这篇也是来自一个知乎上我回答的问题。

原问题:为什么 Linus Torvalds 不愿意将 Linux 变成 GPLv3 授权?

我的回答:

这里有段 Linus Torvalds 在 DebConf 14 上的 Q&A: https://youtu.be/1Mg5_gxNXTo?t=47m20s

其中关于 GPLv3 和协议的那一段在47:20开始到57:00左右。 里面 Linus 对自己的观点澄清得很清楚了。 看u2b或者听英语有困难的请留评论,我抽空可以试着翻译一下。

DebConf 14: Q&A with Linus Torvalds

然后接下来就是我承诺的翻译了

Q: Do you agree that you undermine GPLv3? and ...

问:你是否同意说你贬低了 GPLv3 ? 以及……

L: Yes

L: 是的

Q: How can we get you to stop?

问:我们如何才能让你别这么做?

L: What?

L: 什么?

Q: How can we get you to stop?

问:我们如何才能让你别这么做?

L: Oh I hate GPLv3. I undermined it on purpose. I actually thought the GPLv3 extensions were horrible. I understand why people would want to do them but I think it should have been a completely new license.

L: 哦我讨厌 GPLv3 ,我是在故意贬低它。实际上我觉得 GPLv3 的扩展非常可怕。 我能理解为什么人们想要做这个,但是我觉得它本应是一个全新的协议。

Emm my argument for liking version 2, and I still think version 2 is a great license, was that, "I give you source code, you give me your changes back, we are even." Right? That's my take on GPL version 2, right, it's that simple.

嗯我喜欢版本 2 的那些理由,并且我仍然觉得版本 2 是一个非常棒的协议, 理由是:「我给你源代码,你给我你对它的修改,我们就扯平了」 对吧?这是我用 GPL 版本 2 的理由,就是这么简单。

And version 3 extended that in ways that I personally am really uncomfortable with, namely "I give you source code, that means that if you use that source code, you can't use it on your device unless you follow my rules." And to me that's, that's a violation of everything version 2 stood for. And I understand why the FSF did it because I know what the FSF wants. But to me it's not the same license at all.

然后版本 3 的扩展在某些方面让我个人觉得非常不舒服,也就是说「我给你源代码, 这意味着你必须服从我的一些规则,否则你不能把它用在你的设备上。」 对我来说,这是违反了版本 2 协议所追求的所有目的。然而我理解为什么 FSF 要这么做, 因为我知道 FSF 想要达成什么,但是对我来说这完全是不同的协议了。

So I was very upset and made it very clear, and this was months before version 3 was actually published. There was a discussion about this long before... There was an earlier version of version 3, years before actually, where I said "No, this is not gonna fly." And during that earlier discussion I had already added to the kernel that, "Hey, I don't have the version 2 or later". And there was no... And I was really happy then when version 3 came out, that I have done that something like 5 years before, because there was ever never any question about what the license for the kernel was.

所以我当时非常不安,并且表明了自己的观点,并且这是在版本 3 发布的数月之前。 在那很久之前曾经有过一场讨论……在版本 3 之前有一个早期的版本, 事实上几年之前,那时我就说过:「不,这不可能工作」。 并且在那个早期的讨论阶段我已经在内核里写好了「嘿,我可没有写过版本 2 或者更高版本」。所以之后也没有过(争议)……随后版本 3 出来的时候我非常开心, 因为我早在大概 5 年前做了预防,之后也就再也没有过关于内核的协议究竟是哪个 版本的讨论。

But I actually thought that version 3 is ... Uh, no ... I actually think version 3 is a FINE license, right. I'm a firm believer in, "If you write your code, it is your choice to pick a license." And version 3 is a fine license. Version 3 was not a good ... "Here we give you version 2, and then we tried to sneak in these new rules, and tried to force everybody to upgrade." That was the part I disliked. And the FSF did some really sneaky stuff, downright immoral in my opinion.

不过事实上我觉得版本 3 是……呃不……我事实上觉得版本 3 是个 不错 的协议, 对吧。我坚定地相信「如果是你写的代码,那么你有权利决定它应该用什么协议」。 并且版本 3 是个不错的选择。版本 3 不好的地方在……「我们给你了版本 2 ,然后我们试图偷偷混入这些新的规则,并且想逼着所有人都跟着升级」这是我不喜欢版本 3 的地方。并且 FSF 在其中做了很多见不得人的事情,我觉得做得很不道德。

Q: So you are talking about Tivoization?
译注: 关于 Tivoization
Tivoization 是 FSF 发明的一个词,表示 TiVo 的做法。 TiVo 是一个生产类似电视机顶盒之类的设备的厂商,他们在他们的设备中用到了 Linux 内核和很多别的开源组件,并且他们根据 GPLv2 协议开放了他们使用的组件的源代码。 然而他们在他们出售的设备中增加了数字签名,验证正在执行的系统和软件是他们自己 编制的软件,从而限制了用户修改运行软件的自由。这种做法在 FSF 看来是钻了 GPLv2 的法律上的空子,所以 FSF 提出了 GPLv3 封堵这种做法。

问:所以你在说 Tivoization 的事情么?

L: Ehmm, yeah the Tivoization is always my main, eh dislike of version 3. And, the FSF was being very dishonest thing. "Hey, we actually allow you to invalidate the Tivoization clause" and they tried to, they literally lied to people, and say "Hey, so that means that you can use GPLv3 without the Tivoization part", right. This is ... How many people heard this particular statement from the FSF? (Please raise your hands)

L: 没错,Tivoization 的事情一直是我反对版本 3 的主要根据。并且,FSF 在这件事上表现得极不诚实。「嘿,其实我们允许你无效化 Tivoization 条款」,这样他们试图, 应该说他们是在明白着欺骗别人,并且说「嘿,这意味着你可以使用除去 Tivoization 部分的 GPLv3」。 这很……在场的诸位中有谁从 FSF 那儿听过这个说法?(请举手)

Ok, maybe they only tried to convince me with that one. But they did try. And it was like, "I'm not stupid", right. Yes, you can ... The GPLv3 allows you to say "Ok, Tivoization is not an issue for us". But it allows somebody else to take the project, and say "Hey, I ... The GPLv3 without Tivoization is compatible with the full GPLv3, so I will now make my own fork of this, and I will start doing drivers that use the full version of version 3" And where am I stuck then? I am stuck saying "Hey I give you the source code, and now I can't take it back your changes". That's completely against the whole point of the license in the first place.

好吧,或许他们只试过对我用这套说辞,但是他们真的试过。我的反应是「我可不傻」,对吧。是的, 的确你可以…… GPLv3 允许你说「好, Tivoization 的事情对我们来说不是问题」, 但是它同时又允许别人接过这个项目,并且说「嘿,我觉得……去掉了 Tivoization 的 GPLv3 是兼容完整的 GPLv3 的,所以我可以 fork 这个项目,然后我将在自己的 fork 上用完整的 GPLv3 写驱动。」然后我就囧了。我的困境在于说「嘿,我给了你我的源代码,现在我却不能拿回你对它 的修改了」。这是彻底违背了我用这个协议最初的目的了。

So the FSF was, I mean the kind of stuff that was going on behind the scenes, ah, made me once and for all to decide to never had any thing to do with the FSF again. So if you wanted to give money to an organization that does good? Give it to the EFF. The FSF is full of crazy bittered people. That's just mine opinion. Uh, actually I have ... Ah ... I overstated that a bit, right. The FSF has a lot of nice people in it, but some of them are bit too extreme.

所以 FSF 是,我是说那时他们暗地里做的那些事情,让我当下决定永远不再和 FSF 有任何瓜葛。 所以如果你想捐钱给一个行善的组织,那就捐给 EFF 吧。FSF 充满了疯狂难处的人。这只是我的观点。 呃其实我……嗯……我说得有点过分了。FSF 里有很多不错的人,不过其中有些人有点过激。

Q: Well I wish the EFF care more about software freedom. But, uh, can you ... Do you think that Tivoization benefits me as a user somehow?

问: 嗯我也希望 EFF 能更多的关注于软件的自由方面。但是你能……你觉得 Tivoization 这种行为也能在某种方式上让我作为用户获益么?

L: No, no I don't. I mean that ... But that was never my argument. That was not why I selected the GPLv2. This is my whole point. It's not that I think Tivoization is necessarily something that you should strive for. But it is something that in my world view, it's your decision. If you make hardware that locks down the software, that's your decision as a hardware maker. That has no impact on my decision as a software maker to give you the software. Do you see where I am coming from? I don't like the locked down hardware, but at the same time that was never the social contract I intended with Linux.

L: 不,我不觉得。我的意思是……这从来都不是我的论据,这不是我选择了 GPLv2 的理由。 并不是说我觉得 Tivoization 是某种值得你去争取的权利,而是说在我的世界观中,这是你的决定。 如果你生产硬件去锁住了其中的软件,这是你作为一个硬件提供者的决定。 这完全不影响我作为一个软件提供者给你软件的决定。你能看出我的立场在哪儿了么? 我不喜欢上锁的硬件,但是同时这也从来不是我想要给 Linux 加上的的社会契约。

To me, umm, I mean, people may or may not realize GPLv2 wasn't even the first license for Linux. To me the important part was always "I give you software, you can do whatever you want with it. If you making improvements, you have to give them back." That was the first version of the license. It also had a completely broken clause which was completely insane and I was stupid. Hey it happened. My origin license says that you can't make money change hands. And that was a mistake. That was clearly just wrong and bad because it really didn't have anything to do with what I wanted. But I was young, I was poor, I didn't realize that the whole money thing wasn't the important part. And I have saw the errors in my ways, I saw the GPLv2 and said "Hey, that's the perfect license". And I saw the GPLv3 and I said "No, that's overreaching a lot, that's not what I wanted". And so I made Linux GPLv2 only, right.

对我来说,呃我想说,大家可能知道或者不知道, GPLv2 并不是 Linux 的最初的协议。 对我来说重要的部分一直是「我给你软件,你可以用它做任何你想要做的事情。如果你做了任何改进, 你需要把它交还给我。」这是协议最初的样子。最早的协议还有一条完全错误的条款,写得完全不合理, 那时我很傻。嘿我也傻过。我最初的协议说你不能用它赚钱。这是失策,这明显是不对的不好的, 因为它和我真正想要做的事情没有任何关系。但是那时我很傻很天真, 我没意识到钱的事情在其中完全不重要。然后我发现了其中的问题,我看到了 GPLv2 然后说「嘿, 这是个完美的协议」。然后我看到了 GPLv3 我说「不,这做得过分了,这不是我想要的」 所以我让 Linux 成为了仅限 GPLv2 ,对吧。

Q: So do you think getting the patches back is as useful even if you can't modify the device that it is used on?

问: 所以你是否认为,即使你不能修改跑着这个软件的设备,拿回对软件的修改也还是同样重要的?

L: Yeah, absolutely. And I mean TiVo itself is actually an example of this. Their patches were kind of crafty but I mean they were basically running on a, originally a fairly standard MIPS thing. And their patches were working around bugs in the chipsets they used. And they were valid patches. The fact that they then felt that their hardware had to be locked down someway. I didn't like it. But as I have mentioned, I felt that that was their decision.

L: 是的,当然。我想说 TiVo 它自己实际上就是一个例子。他们的修改有点复杂,但是我想说他们基本 是,一开始基本是运行在一套相当标准的 MIPS 设备上。然后他们的修改是想绕开他们用到的芯片上的 一些问题,并且这些是合格的修改。之后的事情是他们觉得他们需要锁住他们的硬件,我不喜欢这个。 但是就像我已经说的,我觉得这是他们的决定。

And they had real reasons for that. That's something people sometimes missed. There are sometimes reasons to do what TiVo did. Sometimes it's imposed on you by, wireless carriers. Sometimes it's imposed on you by Disney. Uh sometimes it's imposed on you by laws. The GPLv3 actually accepts the last one when it comes to things like medical equipment I think. But the point is that the whole Tivoization thing is, sometimes it's, there is a reason for it. And if you make ... I mean I am not a hardware designer. I think FPGA and stuff like that is really cool. But I always ... I mean I really don't want to impose my world view on anybody else. You don't have to use Linux. If you do use Linux, the only thing I asked for is source code back. And there is all these other verbiages in the GPLv2 about exact details, those aren't important. And that was always my standpoint.

并且他们有真正的理由去这么做。这是有时人们忽视的地方。有时是真的有理由去做 TiVo 他们做的事情。有时强加给你这种限制的是,无线运营商。有时强加给你的是迪士尼。 有时强加给你限制的甚至是法律。 GPLv3 在医疗设备之类的场合其实允许最后一种情况,我记得。 我的观点是,整个 Tivoization 的事情有时是有理由去这么做的。如果你生产…… 我是说我不是硬件设计者,我觉得 FPGA 之类的东西很酷,但是我……我的意思是我真的不想把我对世界的 看法强加给别人。你不是非得要用 Linux ,如果你想要用 Linux ,那么我唯一要求你做的事情是把源代码(变更)还给我。然后在 GPLv2 中还有很多繁文缛节规定了详细的细节,这些都不重要。这是我一直以来的观点。

Q: Ok, well I will stop my non-point of making noise now.
译注: 关于 ISC 协议
ISC 协议是一个开源软件协议,和两句的 BSD 协议功能相同。OpenBSD 项目选择尽量用 ISC 协议公开他们新写的代码。

问: 好吧那我就不浪费时间了。

L: I mean don't get me ... I mean I like other licenses too. I have used like the four, emmm... Which BSD license is the acceptable one? One of the BSD license is actually really nice. And it's actually the... What?

L: 我的意思是别误解……我也喜欢别的协议。我用过……到底是哪个 BSD 协议是可以接受的? 有一个 BSD 协议实际上非常不错。它实际上是……什么?

A: ISC

观众: ISC

L: ISC? And I actually encourage people who don't care about the giving code back but care about the "Hey, I did something cool, please use it". I encourage people to use the BSD license for that. And I mean the BSD license is wonderful for that. It so happens that I thought that for my project the giving back is equally important so I, for me BSD is bad. But the point is for me. The GPLv3 maybe the perfect license for what you guys want to do. And that's fine. And then it's the license you should use. It's just that when somebody else wrote the code you don't get that choice.

L: ISC?并且事实上我在鼓励那些不在意拿回修改但是在意「嘿,我做了一个很酷的东西,请用它」。 我鼓励这些人去用 BSD 协议做这些事情。我想说 BSD 协议在这种场合是完美的。 只是碰巧我觉得对于我的项目,拿回修改也同样重要,所以对我而言 BSD 不好。但是重点是 对我而言 。 GPLv3 可能对你们想要做的事情而言是完美的协议,这很好,并且这时你就应该去用 GPLv3 。只是当代码是别人写的时候,你没有这个选择权。

by farseerfc at August 08, 2016 07:15 AM

August 07, 2016

farseerfc

C语言中“.”与“->”有什么区别?

知乎 转载

转载几篇知乎上我自己的回答,因为不喜欢知乎的排版,所以在博客里重新排版一遍。

原问题:C语言中“.”与“->”有什么区别?

除了表达形式有些不同,功能可以说完全一样阿。那为何又要构造两个功能一样的运算符? 效率有差异?可是现在编译器优化都那么强了,如果真是这样岂不是有些多此一举


刚刚翻了下书,说早期的C实现无法用结构直接当作参数在函数间传递,只能用指向结构的指针在函数间进行传递!我想这应该也是最直观的原因吧。

我的回答

首先 a->b 的含义是 (*a).b ,所以他们是不同的,不过的确 -> 可以用 * . 实现,不需要单独一个运算符。 嗯,我这是说现代的标准化的 C 语义上来说, -> 可以用 * . 的组合实现。

早期的 C 有一段时间的语义和现代的 C 的语义不太一样。

稍微有点汇编的基础的同学可能知道,在机器码和汇编的角度来看,不存在变量,不存在 struct 这种东西,只存在寄存器和一个叫做内存的大数组。

所以变量,是 C 对内存地址的一个抽象,它代表了一个位置。举个例子,C 里面我们写:

a = b

其实在汇编的角度来看更像是

*A = *B

其中 A 和 B 各是两个内存地址,是指针。

好,以上是基本背景。

基于这个背景我们讨论一下 struct 是什么,以及 struct 的成员是什么。 假设我们有

struct Point {
        int x;
        int y;
};
struct Point p;
struct Point *pp = &p;

从现代语义上讲 p 就是一个结构体对象, x y 各是其成员,嗯。

从汇编的语义上讲, p 是一个不完整的地址,或者说,半个地址,再或者说,一个指向的东西是虚构出来的地址。而 x y 各是在 Point 结构中的地址偏移量。也就是说,必须有 p x 或者 p y 同时出现,才形成一个完整的地址,单独的一个 p 没有意义。

早期的 C 就是在这样的模型上建立的。所以对早期的 C 而言, *pp 没有意义,你取得了一个 struct ,而这个 struct 不能塞在任何一个寄存器里,编译器和 CPU 都无法表达这个东西。

这时候只有 p.x p.y 有意义,它们有真实的地址。

早期的 C 就是这样一个看起来怪异的语义,而它更贴近机器的表达。 所以对早期的 C 而言,以下的代码是对的:

p.x = 1;
int *a;
a = &(p.x);

而以下代码是错的:

(*pp).x = 1;

因为作为这个赋值的目标地址表达式的一部分, *pp ,这个中间结果没法直译到机器码。

所以对早期的 C 而言,对 pp 解引用的操作,必须和取成员的偏移的操作,这两者紧密结合起来变成一个单独的操作,其结果才有意义。

所以早期的 C 就发明了 -> ,表示这两个操作紧密结合的操作。于是才能写:

pp->x = 1;

嗯,这就是它存在的历史原因。 而这个历史原因现在已经不重要了,现代的符合标准的 C 编译器都知道 (*pp).x pp->x 是等价的了。

说句题外话, C++ 里面还发明了 .* ->* 这两个运算符(注意 ->* 不是单独的 -> * 并排放的意思),关于为什么要发明这两个运算符,而不能直接说 a ->* b 的意思就是 a ->(*b) ,这个就作为课堂作业吧。

by farseerfc at August 07, 2016 03:02 PM

启用 GitHub Issue 作为博客留言系统

从今天起本博客将启用 GitHub Issue 作为留言系统。 原本使用的 Disqus 将继续保留一段时间,目前没有关闭的计划。

换用 GitHub Issue 是计划了好久的事情了,最初重做这个主题的时候就有考虑过。 这个想法的契机是看到了这篇 GitHub hosted comments for GitHub hosted blogs ,然后立马觉得这个想法很符合寄宿在 GitHub Pages 上的博客。 一个限制是要求评论者必须有 GitHub 账户,考虑到我的博客的受众这个要求估计不算太过分。 使用 GitHub Issue 的好处么,比如自带的 GFMD 富文本格式,邮件通知,还有订阅和取消订阅通知,邮件回复, 这些方面都不比第三方留言系统逊色。

换用 GitHub Issue 另一方面原因是最近听说 Disqus 被部分墙了,想必以后墙也会越来越高。之前曾经试过在这个博客换上多说, 然而效果我并不喜欢,多说喜欢侵入页面加很多奇怪的东西,比如用户的头像通常是 http 的……也试过结合新浪微博的评论,而新浪微博越来越封闭,API 也越来越不靠谱。

使用 GitHub Issue 作为评论的方式比较简单,上面那篇博客里面提到了,代码量不比 加载 Disqus 多多少,而且没有了 iframe 的困扰,唯一麻烦的地方就是要稍微设计一下布局方式让它融入 现有的页面布局。 我参考上面的实现在这里 。 这个加载代码使用两个变量加载 Issue Comments ,一个是在 pelicanconf.py 里的 GITHUB_REPO ,可以指向任何 Repo ,我指向 farseerfc/farseerfc.github.io 的这个 GitHub Page repo ,另一个变量是每篇文章里需要加上 issueid 的元数据,关连文章到每个 Issue 上。

还有一个稍微麻烦的事情是现在每写一篇文章之后都要新建一个 issue 了。 手动操作有点累人,于是我 写了个脚本 自动搜索 pelican 的 content 文件夹里面文章的 slug 并且对没有 issueid 关连的 文章创建 issue 。

好啦新的留言系统的外观样式还在测试中,希望大家多留言帮我测试一下!

2016年8月7日19:30更新

新增了对 GitHub Issue comments 里面 reactions 的支持,套用 font-awesome 的图标(似乎没 GitHub 上的图标好看)。这个还属于 GitHub API 的实验性功能,要加入 Accept: application/vnd.github.squirrel-girl-preview HTTP 头才能拿到。

2016年8月7日23:16更新

感谢 @iovxw 的测试让我发现 github 的高亮回复和邮件回复是需要特殊处理的。 高亮回复用上了 这里的 CSS 邮件引言的展开事件直接用 jQuery 做了:

    $(".email-hidden-toggle > a").on("click", function (e){
  e.preventDefault();
  $(".email-hidden-reply", this.parent).toggle();
});

还得注意邮件的回复需要 CSS 里面 white-space: pre-wrap

by farseerfc at August 07, 2016 07:28 AM

August 06, 2016

中文社区新闻

TeXLive 2016 系列包发布

TeXLive 相关包已经更新到 2016 版。

最显著的变化是 biber 工具现在作为独立的包提供。 你可以用 pacman 像往常一样安装它。

现在 TeXLive 系列包会使用 Pacman 挂钩(Hook)升级了,所以它将比去年少一些输出。

by farseerfc at August 06, 2016 06:50 PM

August 05, 2016

ヨイツの賢狼ホロ

从零开始的 GnuPG 学习笔记 [0] - PGP,GPG 等相关概念扫盲

GnuPG 密钥从创建到注销,顺便丢一只雷姆 (雾 [1]

[1]雷姆(レム/Rem)是动画 「Re:从零开始的异世界生活 」(日文:Re:ゼロから始める異世界生活)的角色之一。

为啥需要密码学技术?

对于计算机的使用后果,没人比乔治·奥威尔在《1984》中的预言错得更离谱了。到目前为止,计算机创造的几乎所有实际的可能性空间都表明,计算机是权威的终结而非权威的开始。

—《失控》

在计算机和互联网的领域,自由和开放大概是主流。那些试图管制和封闭互联网的方法几乎都失败了呗~

类似 TorI2p 一类的匿名网络访问工具正被无数人(可能汝也是其中之一😋)用来因为各种原因隐藏自己的身份。 而类似 ZeroNet 的新兴软件更多的用到了 Bitorrent 一类的分布式技术。

而这些工具要如何安全的进行数据交换呢,就需要用到各种密码学技术了呐, 其实在上网的过程中,汝已经不知不觉的和各种密码学技术打交道了呢~

  • 在浏览各种 https:// 网站 (例如咱这里)时,汝的浏览器会和网站的服务器进行认证来保证汝要访问的服务器真的是这个网站所使用的服务器呐~
  • 在登录到各类网络服务时,总不能明文(就是按原样)传输汝的个人信息(其中可能会有汝的密码哦)吧?这时就需要客户端和服务器约定一种相互理解的方法来加密/解密各类数据呗~
  • ……

而各类密码学技术和工具正是帮助汝在这个无法完全(或是根本不能)信任的互联网中相对安全的传递数据的帮手咯~

好啦好啦……其实咱并不是密码学专家啦😋

PGP,OpenPGP 和 GPG(GnuPG)都是些啥玩意?

(啥,汝到现在连这三个词都没听说过?😂😂)

良好隐私密码法(英语:Pretty Good Privacy,缩写为PGP),一套用于讯息加密、验证的应用程序,采用IDEA的散列算法作为加密与验证之用。

PGP的主要开发者是菲尔·齐默尔曼(Phil Zimmermann)。齐默曼于1991年将PGP在互联网上免费发布。

后来,PGP 被 Symantec 公司收购成为了商业软件。

OpenPGP 是一套标准,大多数 PGP 软件(例如 GnuPG)都遵循这一标准。

GNU Privacy Guard(GnuPG或GPG)是一种加密软件,它是PGP加密软件的满足GPL的替代物。GnuPG依照由IETF订定的OpenPGP技术标准设计。GnuPG用于加密、数字签名及产生非对称匙对的软件。

GnuPG是自由软件基金会的GNU计划的一部分,目前受德国政府资助。以GNU通用公共许可证第三版授权。

而大多数 Linux 发行版中内置(或者在软件仓库中)的应该都是 GnuPG 啦。汝可以在终端里输入 gpg --version 来查看一下版本呗~(如果已经安装了的话)

#咱的 gpg --version 大概像这样,某些发行版(例如 Ubuntu )里可能还会有 gpg2~
gpg (GnuPG) 2.1.14
libgcrypt 1.7.2
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /home/horo/.gnupg
支持的算法:
公钥:RSA, ELG, DSA, ECDH, ECDSA, EDDSA
对称加密:IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256,
    TWOFISH, CAMELLIA128, CAMELLIA192, CAMELLIA256
散列:SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
压缩:不压缩, ZIP, ZLIB, BZIP2

GnuPG 的作用是?

至少咱自己经历过的作用有这两种呗~

  • 签名

    用来证明这个文件是某个人创建的,而且在到达汝的过程中没有被篡改呗~

    大部分 Linux 发行版的软件包管理器已经用上这个用途了呐~ (所以咱推测 gpg 应该已经安装在汝的系统上了呗~)

  • 加密

    在某处用汝自己的密钥对加密某些文字,或是文件。然后传输到某个地方以后再使用汝自己的密钥对解密这些内容,在传输的过程中,如果私钥不泄露的话,其他人只会看到约等于无意义的乱码而已呐~

然后请允许咱从维基百科上抄一张图下来😂😂

PGP 加密/解密的原理图

于是这另一个新坑就挖好了呢(雾😂😂,下次就文字直播生成一个汝自己的密钥对好啦~

by ホロ at August 05, 2016 04:00 PM

July 31, 2016

中文社区新闻

test-sec-flags: 需要协助

基于在 arch-general 邮件列表中的讨论, pid1 在 anthraxx, strcat, sangy, rgacogne 等人的帮助下创建了 test-sec-flags 项目用于测试诸多面向安全方面的编译和链接选项对于性能的影响。这个项目的目的是为了决定这些编译选项是否适合作为所有 Arch Linux 包打包时候的默认选项。我们的早期测试显示和我们目前使用的编译选项相比这些新的编译选项的性能损失几乎可以认为不存在,不过在进一步推进之前我们希望收集更多测试数据帮助判断。

请下载这里的源代码,根据 README 的提示安装和使用。在 results 子目录中关于如何从测试结果文件中提取需要的统计信息。

我们在 Github 的 test-sec-flags Wiki 页收集测试结果,请将你的测试结果添加到这里。特别的,我们非常期望看到 i686 的结果,因为之前的志愿者测试全部基于 x86_64 设备。

我们也欢迎改进补丁。

by farseerfc at July 31, 2016 11:20 AM

July 30, 2016

farseerfc

PacVis: 可视化 pacman 本地数据库

PacVis
Demo of PacVis

我为什么要做 PacVis

我喜欢 Arch Linux ,大概是因为唯有 Arch Linux 能给我对整个系统「了如指掌」的感觉。 在 Arch Linux 里我能清楚地知道我安装的每一个包,能知道系统里任何一个文件是来自哪个包, 以及我为什么要装它。或许对 Debian/Fedora/openSUSE 足够熟悉了之后也能做到这两点, 不过他们的细致打包的结果通常是包的数量比 Arch 要多个 3 到 10 倍,并且打包的细节也比 Arch Linux 简单的 PKGBUILD 要复杂一个数量级。

每一个装过 Arch Linux 的人大概都知道,装了 Arch Linux 之后得到的系统非常朴素,按照 ArchWiki 上的流程一路走下来的话,最关键的一条命令就是 pacstrap /mnt base , 它在 /mnt 里作为根调用 pacman -S base 装上了整个 base 组, 然后就没有然后了。这个系统一开始空无一物,你需要的任何东西都是后来一点点用 pacman 手动装出来的,没有累赘,按你所需。

然而时间长了,系统中难免会有一些包,是你装过用过然后忘记了, 然后这些包就堆在系统的角落里,就像家里陈年的老家具,占着地,落着灰。虽然 pacman -Qtd 能方便地帮你找出所有 曾经作为依赖被装进来,而现在不被任何包依赖 的包,但是对于那些你手动指定的包, 它就无能为力了。

于是我就一直在找一个工具能帮我梳理系统中包的关系,方便我:

  1. 找出那些曾经用过而现在不需要的包
  2. 找出那些体积大而且占地方的包
  3. 厘清系统中安装了的包之间的关系

关于最后一点「厘清包的关系」,我曾经看到过 macOS 系统架构图 和 Android 的系统架构图,对其中的层次化架构印象深刻,之后就一直在想,是否能画出现代 Linux 桌面系统上类似的架构图呢?又或者 Linux 桌面系统是否会展现完全不同的样貌? 从维基百科或者别的渠道能找到 Linux 内核、或者 Linux 图形栈, 或者某个桌面环境的架构,但是没有找到覆盖一整个发行版的样貌的。 于是我便想,能不能从包的依赖关系中自动生成这样一张图呢。

PacVis的老前辈们

在开始写 PacVis 之前,我试过一些类似的工具,他们都或多或少能解决一部分我的需要, 又在某些方面有所不足。这些工具成为了 PacVis 的雏形,启发了 PacVis 应该做成什么样子。

pactree

pactree 曾经是一个 独立的项目 ,现在则是 pacman 的一部分 了。 从手册页可以看出, pactree 的输出是由某个包开始的依赖树。 加上 --graph 参数之后 pactree 还能输出 dot 格式的矢量图描述,然后可以用 dot 画出依赖图:

pactree pacvis-git -d3 --graph | dot -Tpng >pacvis-pactree.png
pactree --graph
$ pactree pacvis-git -d3
pacvis-git
├─python-tornado
│ └─python
│   ├─expat
│   ├─bzip2
│   ├─gdbm
│   ├─openssl
│   ├─libffi
│   └─zlib
├─pyalpm
│ ├─python
│ └─pacman
│   ├─bash
│   ├─glibc
│   ├─libarchive
│   ├─curl
│   ├─gpgme
│   ├─pacman-mirrorlist
│   └─archlinux-keyring
└─python-setuptools
  └─python-packaging
    ├─python-pyparsing
    └─python-six
 $ pactree pacvis-git -d3 --graph | dot -Tpng >pacvis-pactree.png

从画出的图可以看出,因为有共用的依赖,所以从一个包开始的依赖关系已经不再是一棵 图论意义上的树(Tree) 了。最初尝试做 PacVis 的早期实现的时候,就是试图用 bash/python 脚本解析 pactree 和 pacman 的输出,在 pactree 的基础上把整个系统中所有安装的包全都包含到一张图里。 当然后来画出的结果并不那么理想,首先由于图非常巨大,导致 dot 的自动布局要耗费数小时,最后画出的图也过于巨大基本上没法看。

然而不得不说没有 pactree 就不会有 PacVis ,甚至 pacman 被分离出 alpm 库也和 pactree 用 C 重写的过程有很大关系,而 PacVis 用来查询 pacman 数据库的库 pyalpm 正是 alpm 的 Python 绑定。因为 pactree 的需要而增加出的 alpm 库奠定了 PacVis 实现的基石。

pacgraph

pacgraph 的输出
pacgraph

pacgraph 是一位 Arch Linux 的 Trusted User keenerd 写的程序,和 PacVis 一样也是用 Python 实现的。 比起 pactree , pacgraph 明显更接近我的需求,它默认绘制整个系统的所有安装包, 并且用聪明的布局算法解决了 dot 布局的性能问题。

pacgraph 的输出是一个富有艺术感的依赖图,图中用不同的字体大小表示出了每个包占用 的磁盘空间。通过观察 pacgraph 的输出,我们可以清楚地把握系统全局的样貌, 比如一眼看出这是个桌面系统还是个服务器系统,并且可以很容易地发现那些占用磁盘空间 巨大的包,考虑清理这些包以节约空间。

更棒的是 pacgraph 还提供了一个交互性的 GUI 叫做 pacgraph-tk ,显然通过 tk 实现。 用这个 GUI 可以缩放观察整幅图的细节,或者选中某个包观察它和别的包的依赖关系。

pacgraph 还支持通过参数指定只绘制个别包的依赖关系,就像 pactree 那样。

不过 pacgraph 也不是完全满足我的需要。如我前面说过,我希望绘制出的图能反应 这个发行版的架构面貌 ,而 pacgraph 似乎并不区别「该包依赖的包」和「依赖该包的包」 这两种截然相反的依赖关系。换句话说 pacgraph 画出的是一张无向图, 而我更想要一张有向图,或者说是 有层次结构的依赖关系图

于是就有了 PacVis

PacVis 刚打开的样子
PacVis on startup

总结了老前辈们的优势与不足,我便开始利用空余时间做我心目中的 PacVis 。 前后断断续续写了两个月,又分为两个阶段,第一阶段做了基本的功能和雏形, 第二阶段套用上 https://getmdl.io/ 的模板,总算有了能拿得出手给别人看的样子。

于是乎前两天在 AUR 上给 pacvis 打了个 pacvis-git 包,现在想在本地跑 pacvis 应该很方便了,用任何你熟悉的 aurhelper 就可以安装,也可以直接从 aur 下载 PKGBUILD 打包:

~$ git clone aur@aur.archlinux.org:pacvis-git.git
~$ cd pacvis-git
~/pacvis-git$ makepkg -si
~/pacvis-git$ pacvis
Start PacVis at http://localhost:8888/

按照提示说的,接下来打开浏览器访问 http://localhost:8888/ 就能看到 PacVis 的样子了。仅仅作为尝试也可以直接打开跑在我的服务器上的 demo: https://pacvis.farseerfc.me/ ,这个作为最小安装的服务器载入速度大概比普通的桌面系统快一点。

在 Windows msys2 跑 PacVis
PacVis on Windows msys2

另外补充一下,因为 PacVis 只依赖 pyalpm 和 tornado ,所以在别的基于 pacman 的系统上跑它应该也没有任何问题,包括 Windows 上的 msys2 里(尽管在 msys2 上编译 tornado 的包可能要花些功夫)。

PacVis 的图例和用法

操作上 PacVis 仿照地图程序比如 Google Maps 的用法,可以用滚轮或者触摸屏的手势 缩放、拖拽,右上角有个侧边栏,不需要的话可以点叉隐藏掉,右下角有缩放的按钮和 回到全局视图的按钮,用起来应该还算直观。

PacVis showing pacvis-git

pacvis-git 包的依赖

先解释图形本身,整张图由很多小圆圈的节点,以及节点之间的箭头组成。 一个圆圈就代表一个软件包,而一条箭头代表一个依赖关系。缩放到细节的话, 能看到每个小圆圈的下方标注了这个软件包的名字,鼠标悬浮在圆圈上也会显示响应信息。 还可以点开软件包,在右侧的边栏里会有更详细的信息。

比如图例中显示了 pacvis-git 自己的依赖,它依赖 pyalpm, python-tornado 和 python-setuptools ,其中 pyalpm 又依赖 pacman 。图中用 紫色 表示手动安装的包, 橙色 表示被作为依赖安装的包, 箭头的颜色也随着包的颜色改变。

值得注意的是图中大多数箭头都是由下往上指的,这是因为 PacVis 按照包的依赖关系做 了拓扑排序,并且给每个包赋予了一个拓扑层级。比如 pacvis-git 位于 39 层,那么它依赖的 pyalpm 就位于 38 层,而 pyalpm 依赖的 pacman 就位于 37 层。根据层级关系排列包是 PacVis 于 pacgraph 之间最大的不同之处。

除了手动缩放, PacVis 还提供了搜索框,根据包名快速定位你感兴趣的包。 以及在右侧边栏中的 Dep 和 Req-By 等页中,包的依赖关系也是做成了按钮的形式, 可以由此探索包和包之间的关联。

最后稍微解释一下两个和实现相关的参数:

Max Level

这是限制 PacVis 载入的最大拓扑层。系统包非常多的时候 PacVis 的布局算法会显得很慢,限制层数有助于加快载入,特别是在调试 PacVis 的时候比较有用。

Max Required-By

这是限制 PacVis 绘制的最大被依赖关系。稍微把玩一下 PacVis 就会发现系统内绝大多数 的包都直接依赖了 glibc 或者 gcc-libs 等个别的几个包,而要绘制这些依赖的话会导致 渲染出的图中有大量长直的依赖线,不便观察。于是可以通过限制这个值,使得 PacVis 不绘制被依赖太多的包的依赖关系,有助于让渲染出的图更易观察。

从 PacVis 能了解到的一些事实

一个 KDE 桌面的 PacVis 结果全图, 放大(17M)
A normal KDE desktop in PacVis

稍微玩一下 PacVis 就能发现不少有趣现象,上述「绝大多数包依赖 glibc 」就是一例。 除此之外还有不少值得玩味的地方。

依赖层次

系统中安装的包被明显地分成了这样几个层次:

  • glibc 等 C 库
  • Bash/Perl/Python 等脚本语言
  • coreutils/gcc/binutils 等核心工具
  • pacman / systemd 等较大的系统工具
  • gtk{2,3}/qt{4,5} 等 GUI toolkit
  • chromium 等 GUI 应用
  • Plasma/Gnome 等桌面环境

大体上符合直观的感受,不过细节上有很多有意思的地方,比如 zsh 因为 gdbm 间接依赖了 bash,这也说明我们不可能在系统中用 zsh 完全替代掉 bash。 再比如 python (在 Arch Linux 中是 python3)和 python2 和 pypy 几乎在同一个拓扑层级。

zsh depends on bash because of gdbm

zsh 因为 gdbm 间接依赖了 bash

不过偶尔显示的依赖层级不太符合直观,比如 qt5-base < qt4 < gtk2 < gtk3 。 qt5 因为被拆成了数个包所以比 qt4 更低级这可以理解,而 gtk 系比 qt 系更高级这一点是很多人(包括我)没有预料到的吧。

循环依赖

有些包的依赖关系形成了循环依赖,一个例子是 freetype2 和 harfbuzz,freetype2 是绘制字体的库,harfbuzz 是解析 OpenType 字形的库,两者对对方互相依赖。 另一个例子是 KDE 的 kio 和 kinit,前者提供类似 FUSE 的资源访问抽象层, 后者初始化 KDE 桌面环境。

freetype2 harfbuzz

freetype2 和 harfbuzz 之间的循环依赖

因为这些循环依赖的存在,使得 PacVis 在实现时不能直接拓扑排序,我采用环探测 算法找出有向图中所有的环,并且打破这些环,然后再使用拓扑排序。 因此我在图中用红色的箭头表示这些会导致环的依赖关系。

有些包没有依赖关系

PacVis Level 0

man-pages 和 licenses 没有依赖关系

有些包既不被别的包依赖,也不依赖别的包,而是孤立在整张图中,比如 man-pages 和 licenses 。这些包在图中位于最顶端,拓扑层级是 0 ,我用 蓝色 正方形特别绘制它们。

只看依赖关系的话 Linux 内核完全不重要

所有用户空间的程序都依赖着 glibc ,而 glibc 则从定义良好的 syscall 调用内核。 因此理所当然地,如果只看用户空间的话, glibc 和别的 GNU 组件是整个 GNU/Linux 发行版的中心,而 Linux 则是位于依赖层次中很深的位置,甚至在我的 demo 服务器上 Linux 位于整个图中的最底端,因为它的安装脚本依赖 mkinitcpio 而后者依赖了系统中的众多组件。

pacman -Qtd 不能找到带有循环依赖的孤儿包

pacman -Qtd cannot find packages with circle dependency

msys2 中带有循环依赖的孤儿包

这是我在 msys2 上测试 PacVis 的时候发现的,我看到在渲染的图中有一片群岛, 没有连上任何手动安装的包。这种情况很不正常,因为我一直在我的所有系统中跑 pacman -Qtd 找出孤儿包并删掉他们。放大之后我发现这些包中有一条循环依赖, 这说明 pacman -Qtd 不能像语言的垃圾回收机制那样找出有循环依赖的孤儿包。

PacVis 的未来

目前的 PacVis 基本上是我最初开始做的时候设想的样子,随着开发逐渐又增加了不少功能。 一些是迫于布局算法的性能而增加的(比如限制层数)。

今后准备再加入以下这些特性:

  1. 更合理的 optdeps 处理。目前只是把 optdeps 关系在图上画出来了。
  2. 更合理的 依赖关系抉择 。有时候包的依赖关系并不是直接根据包名,而是 provides 由一个包提供另一个包的依赖。目前 PacVis 用 alpm 提供的方式抉择这种依赖,于是这种关系并没有记录在图上。
  3. 目前的层级关系没有考虑包所在的仓库 (core/extra/community/...) 或者包所属的组。 加入这些关系能更清晰地表达依赖层次。
  4. 目前没有办法只显示一部分包的关系。以后准备加入像 pactree/pacgraph 一样显示部分包。

如果你希望 PacVis 出现某些有趣的用法和功能,也 请给我提 issue

by farseerfc at July 30, 2016 06:52 PM

July 29, 2016

Justin Wong

GPG 与 SSH Agent 转发

我一直有这样的问题,当我 SSH 到某个远程主机时,就很难进一步进行 SSH 和 GPG 相关操作,因为远端没有我的私钥,如果直接把私钥拷贝到远程,则非常不安全。 自从有了yubikey之后,这个问题更加严重:私钥在 yubikey 里,根本不可能“拷贝到远程”。

过去我的一些做法是使用 usbip,相当于把 yubikey “挂载”到远程的机器上,这个太 hacky 了,并且配置麻烦,不灵活。

直到我发现了 SSH 已经可以转发 UNIX Domain Socket。

首先 SSH Agent 的转发非常简单,只要你使用 SSH Agent 保存密钥,那么用 ssh -A 连接主机,或者在 ~/.ssh/config 里写上 ForwardAgent yes 即可。

GPG Agent 的转发相对麻烦一些,版本要求是: OpenSSH >6.7 以及 GnuPG >2.1 。

首先,本地的 GPG Agent 要加上 --extra-socket 选项,用于 SSH 转发。文档的解释是:

–extra-socket name

Also listen on native gpg-agent connections on the given socket. The intended use for this extra socket is to setup a Unix domain socket forwarding from a remote machine to this socket on the local machine. A gpg running on the remote machine may then connect to the local gpg-agent and use its private keys. This allows to decrypt or sign data on a remote machine without exposing the private keys to the remote machine.

一般在 ~/.gnupg/gpg-agent.conf 里加上 extra-socket /path/to/extra/socket 就好。

然后使用 SSH Remote Forwarding 将远端 socket 转发到本地,也就是让 SSH 在把远程主机的一个 unix socket 转发到本地 GPG Agent 监听的 extra socket 上即可。 这里需要注意几点:

  1. GPG 2.1 之后,不再使用 GPG_AGENT_INFO 环境变量,而是一定会连接 $GNUPGHOME/S.gpg-agent (一般是 ~/.gnupg/S.gpg-agent)。
  2. GPG 2.1.13 之后,如果存在 /run/user/$UID/gnupg 目录, 则会把 gpg-agent 的 socket 放过去,如果不存在,则 fallback 到 $GNUPGHOME 里。
  3. 如果远端已经跑着一个 gpg-agent 了,就需要先关掉,否则 ssh 就无法监听需要转发的 socket 了

所以,使用以下命令进行 SSH 连接,才能成功转发 gpg agent

1
2
ssh -R /run/user/REMOTE_UID/gnupg/S.gpg-agent:/path/to/S.gpg-agent.extra \
-o StreamLocalBindUnlink=yes user@example.com

这里的 StreamLocalBindUnlink 是让 ssh 连接断开的时候,把远端监听的 socket unlink 掉,不然下次连接就会转发失败了。

这个参数比较长,很麻烦,所以也可以在 ~/.ssh/config 里加上

1
StreamLocalBindUnlink yes
RemoteForward /run/user/REMOTE_UID/gnupg/S.gpg-agent /path/to/S.gpg-agent.extra

亲测,在使用 yubikey 的情况下,远程主机可以正常进行签名、解密等操作,但是gpg --card-edit是被禁止的。

p.s. 测试的时候,确保远端没有 gpg-agent 在运行,执行一下 gpg-connect-agent /bye, 如果提示说 no running gpg-agent - starting '/usr/bin/gpg-agent' 就说明转发失败了。

以上。

我一直有这样的问题,当我 SSH 到某个远程主机时,就很难进一步进行 SSH 和 GPG 相关操作,因为远端没有我的私钥,如果直接把私钥拷贝到远程,则非常不安全。 自从有了yubikey之后,这个问题更加严重:私钥在 yubikey 里,根本不可能“拷贝到远程”。

过去我的一些做法是使用 usbip,相当于把 yubikey “挂载”到远程的机器上,这个太 hacky 了,并且配置麻烦,不灵活。

直到我发现了 SSH 已经可以转发 UNIX Domain Socket。

July 29, 2016 10:31 AM

July 24, 2016

ヨイツの賢狼ホロ

一瞥 Arch Linux 中的 filesystem 软件包

闲来无事,然后就没有然后啦😂

动机?

今天看了看知乎上的某个问题: 长期使用Arch,Gentoo等滚动更新的发行版是怎样的一种体验?

好几个 Arch Linux 用户都是在一开始列出了 /var/log/pacman.log 的第一行,用的是 head 命令。

# 咱没有各位的历史悠久啦~
$ head -1 /var/log/pacman.log
[2014-11-18 19:37] installed filesystem (2014.10-1)

然后这个 filesystem 是啥咧?

然后 farseerfc 这么写到:

pacman -Ql filesystem 看下它都有什麼唄。 這個包就是提供最基礎的 Arch Linux 的目錄結構和一些不屬於任何別的包的配置文件。 這樣 Arch Linux 裏面任何系統文件都在 pacman 管轄範圍內了。

嗯……😋

😋 开始行动

那就首先照着 fc 的写法来一遍呗~

[horo@yoitsu-surfacebook ~]$ pacman -Ql filesystem
filesystem /bin
filesystem /boot/
filesystem /dev/
filesystem /etc/
filesystem /etc/arch-release
filesystem /etc/crypttab
filesystem /etc/fstab
filesystem /etc/group
filesystem /etc/gshadow
filesystem /etc/host.conf
filesystem /etc/hosts
filesystem /etc/issue
filesystem /etc/ld.so.conf
filesystem /etc/ld.so.conf.d/
filesystem /etc/motd
filesystem /etc/mtab
filesystem /etc/nsswitch.conf
filesystem /etc/passwd
filesystem /etc/profile
filesystem /etc/profile.d/
filesystem /etc/profile.d/locale.sh
filesystem /etc/resolv.conf
filesystem /etc/securetty
filesystem /etc/shadow
filesystem /etc/shells
filesystem /etc/skel/
filesystem /home/
filesystem /lib
filesystem /lib64
filesystem /mnt/
filesystem /opt/
filesystem /proc/
filesystem /root/
filesystem /run/
filesystem /sbin
filesystem /srv/
filesystem /srv/ftp/
filesystem /srv/http/
filesystem /sys/
filesystem /tmp/
filesystem /usr/
filesystem /usr/bin/
filesystem /usr/include/
filesystem /usr/lib/
filesystem /usr/lib/modprobe.d/
filesystem /usr/lib/modprobe.d/usb-load-ehci-first.conf
filesystem /usr/lib/os-release
filesystem /usr/lib64
filesystem /usr/local/
filesystem /usr/local/bin/
filesystem /usr/local/etc/
filesystem /usr/local/games/
filesystem /usr/local/include/
filesystem /usr/local/lib/
filesystem /usr/local/man/
filesystem /usr/local/sbin/
filesystem /usr/local/share/
filesystem /usr/local/share/man
filesystem /usr/local/src/
filesystem /usr/sbin
filesystem /usr/share/
filesystem /usr/share/man/
filesystem /usr/share/man/man1/
filesystem /usr/share/man/man2/
filesystem /usr/share/man/man3/
filesystem /usr/share/man/man4/
filesystem /usr/share/man/man5/
filesystem /usr/share/man/man6/
filesystem /usr/share/man/man7/
filesystem /usr/share/man/man7/archlinux.7.gz
filesystem /usr/share/man/man8/
filesystem /usr/share/misc/
filesystem /usr/src/
filesystem /var/
filesystem /var/cache/
filesystem /var/empty/
filesystem /var/games/
filesystem /var/lib/
filesystem /var/lib/misc/
filesystem /var/local/
filesystem /var/lock
filesystem /var/log/
filesystem /var/log/old/
filesystem /var/mail
filesystem /var/opt/
filesystem /var/run
filesystem /var/spool/
filesystem /var/spool/mail/
filesystem /var/tmp/

嗯 filesystem 的作用大概有这几个:

  • 首先摆好一个 Linux 发行版基本的目录结构。

    大多数 Linux 发行版的目录结构都是遵循 文件系统层次结构标准 的啦,Arch 也不例外~

  • 然后放些 Arch 特有的文件

    例如默认设置啦( 这不是废话么 ),甚至还有一个手册页(汝不妨试试 man archlinux ?)

所以嘛……

by ホロ at July 24, 2016 04:00 PM

wicast

在非KDE桌面下Qt5.7主题崩坏的解决方案

前段时间 Qt5.7 更新移除了 QGtkStyle 这个模块,直接导致了非 KDE 环境下 Qt 应用主题直接崩坏(

在 ArchWiki 上找了下解决方案,发现一个叫 qt5ct 的包可以在非 KDE 下设定 Qt 应用的主题(oxygen、breeze)。

安装好后首先在菜单栏里打开 qt5ct(这玩意是有 .desktop 文件的),咱选择的是用 breeze,字体个人喜欢用 noto。

之后在你的 .xprofile 里加上一句 export QT_QPA_PLATFORMTHEME=qt5ct 重启 X 后那些 Qt 应用就能直接用 KDE 主题辣

已知问题:

ss-qt5 会崩溃,启动 ss-qt5 的时候记得去掉这个环境变量。 默认没法用暗色主题,breeze 自带的 color-scheme 和 qt5ct 不兼容,无奈花了点时间,对着 arc-dark 的颜色自己做了一份配色:https://github.com/wicast/dotfiles/tree/master/qt5ct/.config/qt5ct/colors

July 24, 2016 10:06 AM

July 23, 2016

ヨイツの賢狼ホロ

AOSCC 2016 游记 - 第三天

AOSCC 2016 围观日记最终章(大雾

去 AOSCC 会场围观了下,然后拖延症又发作了 *3 😂

怪了,今天有人没出席拖延症患者互助协会的活动。

第三天......

还是多图杀猫+原谅咱的渣照相技术😂

前奏

今天是个平常的一天,大家都在各自摸鱼🐟,甚至又玩起了 UNO 牌😂

又玩起了 UNO 牌😂

😐 果冻特首的打包教室

Install AOSC OS on  Deepin

特首试图用 Deepin 的 LiveUSB 安装 AOSC OS (然后失败了😂

这是色彩校正

这个看起来和摄像头类似的物体竟然是用来校正色彩的 🤦

ThinkPad 信仰充值中心二分部 😂

ThinkPad 信仰充值中心二分部 😂

换大屏幕

换大屏幕以后就舒服多了~

现场修 issue

特首施展了现场修 issue 技能 😂

😅 AST 讨论区兼微软信仰充值中心 😂

画风突变

画风突变😂😂

来排排坐

AOSCC 微软信仰充值中心 😂

😯 AOSC OS 要成为模拟器系统么 (雾

新鲜出炉的 vba-m

新鲜出炉的 vba-m 😂

隔壁 OS X 来砸场啦

OS X 来砸场啦 😂

NDSL

真机笑而不语😏

各种小插曲......

Icenowy Icenowy

被特首抢了观众的 Icenowy 在默默的继续调试自己的板子……

Icenowy

(好像有啥奇怪的东西混进来了😂

现场直播白学

白学家进入现场, 打死!

围观狮子赶工社区网站

🙄 围观狮子赶工社区网站中……

FSF FSF

听说有人要加入 FSF 神教? 😂

Coding.net x GitCafe

GitCafe 的精神继任 Coding.net 借尸还魂啦😂

这不清真 😂

这不清真 这不清真 Act 2 这不清真 Act 3

糟糕!你们竟然昏了头脑把圣战者公审了!他引爆了藏在衣服里的炸弹,和所有人同归于尽了 #圣战者胜。😂

然后……

Jelly Bai 在 BroncoTc 的提醒下发现忘记像去年一样照集体照了 🤣😂

BroncoTc | Keybase√, [18.07.16 19:16] 卧槽

BroncoTc | Keybase√, [18.07.16 19:16] 我们忘了拍合影。

liushuyu 🐟, [18.07.16 19:16] GG

liushuyu 🐟, [18.07.16 19:17] 建议开始 AOSCC 2017 的筹划

Mingcong Bai, [18.07.16 19:17] Oh sh*t.

ヨイツの賢狼ホロ 😋(*), [18.07.16 19:18] 下一次第一天就拍合影吼不吼啊😂

Mingcong Bai, [18.07.16 19:18] [In reply to ヨイツの賢狼ホロ 😋(*)] 吼啊

gumblex, [18.07.16 19:18] [In reply to BroncoTc | Keybase√] 🌚这应该是第一天中午的事情

Mogician Yang, [18.07.16 19:18] 滋磁一个

Jactry Zeng, [18.07.16 19:19] [In reply to Mingcong Bai] 这次会续了不少啊 xD

ヨイツの賢狼ホロ 😋(*), [18.07.16 19:19] [In reply to Mingcong Bai] 😂 /me 然而下一次来不来难说了

KayMW | Syntax-Breaker | 不想猎取灵魂的咸鱼不是好灵魂画手 | 0x547E5906116A1966, [18.07.16 19:19] [In reply to ヨイツの賢狼ホロ 😋(*)] 还真应该这样……有时候不知道谁就突然不见了(比如今天中午的A2

KayMW | Syntax-Breaker | 不想猎取灵魂的咸鱼不是好灵魂画手 | 0x547E5906116A1966, [18.07.16 19:20] [In reply to KayMW | Syntax-Breaker | 不想猎取灵魂的咸鱼不是好灵魂画手 | 0x547E5906116A1966] 还有昨天还是前天的 Bob Cao(

Icenowy 请大家不要在 SoC 上套用 PC 的 GPU 概念, [18.07.16 19:20] [In reply to KayMW | Syntax-Breaker | 不想猎取灵魂的咸鱼不是好灵魂画手 | 0x547E5906116A1966] a2 最后回来啦

IMisakaTransferFrame4e21 神乐坂美蒋, [18.07.16 19:21] 应该和AOSCC 2015一样,人没到齐就合多张

KayMW | Syntax-Breaker | 不想猎取灵魂的咸鱼不是好灵魂画手 | 0x547E5906116A1966, [18.07.16 19:21] [In reply to Icenowy 请大家不要在 SoC 上套用 PC 的 GPU 概念] 然而那个时候人基本走光啦(

by ホロ at July 23, 2016 04:00 PM

百合仙子

发包太快,请勿跟踪

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

之前写的那个处理 DNS AAAA 的程序,后来请求量大的时候就经常报错。经过研究,是在sendto的时候返回了「Pemission Denied」错误。后来的 Rust 版本也发生了类似的问题,得到操作系统返回的代码「EPERM」。

我翻了半天 man 手册,其中只说到向广播地址发包可能会得到 EACCES 错误。Google 也没有得到结果(都是些权限不够的问题,但我的程序是 root 跑的呀,并且错误比较零星)。后来发到 shlug 邮件列表中询问,才终于得知了和我有同样问题的人,但是也没有结论,只是说关掉 iptables 就正常了。可我的程序依赖 iptables 呢……而且我要的不仅仅是解决方案(实际上这个问题并没有造成什么可感知的影响,就算有,我也有办法 migrate),我更想知道为什么。

确定是发包太快造成的问题,拿着相关关键词去搜,还真找到了一些有用的信息。比如之前看过的 CloudFlare 低延迟 UDP 实验时会让 iptables 不跟踪相关数据包,有人在使用 SIP 协议时也遇到了同样的问题,并且在内核日志的帮助下解决了。于是我照着做,让 conntrack 放过我发出的 UDP 包:

iptables -t raw -I OUTPUT -p udp -m udp --sport 53 -j NOTRACK

然后不仅那些错误都没了,而且处理速度快了一倍!(图中红虚线是发生错误的时候。)

程序统计信息

by 依云 at July 23, 2016 06:40 AM

July 22, 2016

ヨイツの賢狼ホロ

AOSCC 2016 游记 - 第二天

AOSCC 2016 围观日记续集(误

去 AOSCC 会场围观了下,然后拖延症又发作了 *2 😂

你是拖延症患者,每天除了摸鱼🐟什么都不干,你很忧心,为此加入了拖延症患者互助协会。

第二天......

还是多图杀猫+原谅咱的渣照相技术😂

前奏:出发~

「昨晚,秘密警察突然失踪,说不定是有人报复?想必是凶多吉少了……」酒店老板在收了一笔可观的小费之后,告诉了大家这个情报。

还是A2的游戏直播

还是老样子,开始前先玩会儿游戏~

🐷 Gumblex 的表情高清重制直播

Gumblex 的表情高清重制直播

(道具是自由且开源的 Inkscape 哦~)

Gumblex 的表情高清重制直播 Gumblex 的表情高清重制直播

这张用了 全景(不能) 变焦以后更糊了 😂

Gumblex 的表情高清重制直播

😯 Junde Yhi 关于安同开始程序的介绍

安同开始程序(Anthon Starter Kit),可以去 repo.aosc.io 获取演讲时用到的幻灯片。

(原谅咱真找不到更合适的词啦,况且 LibreOffice Impress 也叫“幻灯片” 😂😂

https://repo.aosc.io/aosc-documentation/aoscc-2016/junde-yhi-ast-startup-kit/speech-anthon-starter.pdf

唔~

唔~

AST Speech Uno😂

然后后面有人玩起了 Uno 牌😂

😋 Junde Yhi 和 liushuyu 🐟 关于分布式 ABBS 的构想

ABBS ,全称 AutoBuild Build Service 。是 AOSC OS 管理软件包编译配置树的工具(目前是这样

还是老样子,演讲时的幻灯片在这:

https://repo.aosc.io/aosc-documentation/aoscc-2016/junde-yhi-distributed-abbs/distributed-abbs.pdf

DABBS_1 DABBS_2 DABBS_3 DABBS_4

(瓶装毒品😂😂)

照例还是 Extra:

Arthur2e5 is playing NEKOPARA ~

这回怪了,没人投票?你们终于意识到投票杀人是不人道的了吗?

夜幕降临,人们都活在恐惧中,彻夜难眠。这漫长的夜晚竟然......还是有好几个小时 😂😂

😋

by ホロ at July 22, 2016 04:00 PM

July 21, 2016

ヨイツの賢狼ホロ

AOSCC 2016 游记 - 第一天

AOSCC 2016 围观日记 (误

去 AOSCC 会场围观了下,然后拖延症又发作了😂😂

AOSC(C) 是啥?

AOSC ,全称 Always Overuse Shell Community Anthon Open Source Community ,安同开源社区。 是一个主要学生组成的开源社区,主要致力于 AOSC OS 的开发工作。

AOSC OS 是安同开源社区的主要项目,它是一个“白”手起家(?),采用 dpkg 作为软件包管理器的 Linux 发行版, 按照 jeffbai: 可爱的特首(误) Jelly Bai 的想法:

“在我们的发行版真的拿得出手前(希望至少能和 Arch 比比整洁度),真不希望我们像 Deepin 一样被捧来捧去......”

而后面加个 C (Conference) 就是一年一度的见面会啦~ (今年好像是第二届?

然后作为在其间打酱油的咱怎么会想到去参加这个呢? (难道是因为被调侃了?

liushuyu 🐟, [09.07.16 17:52] 萌狼跟谁住啊(

ヨイツの賢狼ホロ 😋(*), [09.07.16 17:55] 🌚

Cheng Cao, [09.07.16 17:57] [In reply to liushuyu 🐟] 会发生什么

ヨイツの賢狼ホロ 😋(*), [09.07.16 18:03] [In reply to Cheng Cao] 😋

liushuyu 🐟, [09.07.16 18:05] [In reply to Cheng Cao] 旭日初升,恶臭四溢。AOSCC 与会人员们寻着气味而走,赫然发现【xxx】身首异处,躯体被撕成了碎片。这回糟了!

KayMW | Syntax-Breaker | 不想猎取灵魂的咸鱼不是好灵魂画手 | 0x547E5906116A1966, [09.07.16 18:17] [In reply to Cheng Cao] 会被吃

KayMW | Syntax-Breaker | 不想猎取灵魂的咸鱼不是好灵魂画手 | 0x547E5906116A1966, [09.07.16 18:17] [In reply to liushuyu 🐟] 萌狼:“下一个吃谁呢~”

ヨイツの賢狼ホロ 😋(*), [09.07.16 18:18] 😂

请听题:上面要补多少个括号? 😂😂

第一天......

多图杀猫+原谅咱的渣照相技术😂

前奏:当地桥好像很多的样子......

(当地桥好像很多的样子~)

前奏:这是啥?

(当心电离辐射......#滑稽)

前奏:导向牌

(简朴的导向标志)

AOSCC 与会人员们聚集在会场 —— 大家都如释重负,因为昨晚似乎无人受袭。

正在打游戏的 A2 ww~ 正在打游戏的 A2 ww~

在白特首来之前先来围观下 A2 ~

维他柠檬茶

夭寿辣,会场聚众吸毒啦😂😂

locale-gen

现场生成 locale 中(貌似 AOSC 没给 /etc/locale.gen 上注释😂

ThinkPads

ThinkPad 信仰充值中心一分部 😂 (画面中间的是果冻特首的 W541 ,旁边的是 A2 的 X1 Carbon)

Longson

还有特首的龙芯笔记本~

WhiteBoard

Hmm...清真猪肉公共许可证, 嗯可以,这很清真

Raspberrypi

现场装 X 中的树莓派 (然而不久有人把线碰掉然后就关机了, 毕竟出来混迟早是要还的嘛 😂)

AOSCC17 AOSCC201

AOSCC 2017,下一站广州!😋

AOSCC Core 4

AOSCC 2016 与会者选出的 AOSC OS Core 4 的开发代号是 "Duang-Duang"(努力保持严肃……);

夜幕降临,人们都活在恐惧中,彻夜难眠。这漫长的夜晚竟然有几个小时! 😂😂

Extra

Naive Blue

😂😂

by ホロ at July 21, 2016 04:00 PM

July 16, 2016

Hexchain Tong

跨架构升级 Fedora

有个很久以前建立的 Linode VPS,系统是 32 位的 Fedora。在 Linode 换成 KVM 时被要求换成了 64 位内核,看似没有问题就一直在使用。前些天发现许久不用的 strongswan 不能连接,报错信息让人感觉用户空间的什么东西和内核的什么东西不合拍,加上这个 Fedora 20 已经停止了更新,便萌生了作死变换架构然后升级的念头。

在这期间 Linode 一共给我发了 27 封提醒邮件,Orz...

Linode Events Notification

整个过程中主要参考了这篇文章。

大致过程与原文相同,先滚系统,然后安装发行版提供的 64 位内核并确保启动,然后执行命令输出软件包列表,并替换 i686x86_64 生成要安装的软件包列表,然后下载所有软件包准备。

# rpm -qa --qf '%{name}.%{arch}\n' |grep -E '\.i.86' |sed s/i.86/x86_64/g >rpmlist.txt
# yum --downloadonly --downloaddir=$SOMEPLACEWITHSPACE install $(cat rpmlist.txt)

此时要注意,由于目录结构的区别,要首先安装 filesystem 这个包,否则 /lib64 会成为一个目录,而不是到 /usr/lib64 的软链接。安装完成后可以继续安装所有软件包:

# rpm -Uvh filesystem*.rpm --replacepkgs --replacefiles --ignorearch
# rpm -Uvh *rpm --replacepkgs --replacefiles --ignorearch

注意 SELinux 相关包的状态,如果出现问题可能无法启动。我遇到的情况是莫名其妙的丢了 selinux-policy-targeted 这个包,导致重启之后 dbus 启动不能,卡住 systemd。

重启,确定系统正常之后可以删掉剩余的 *.i686* 包了。如果需要的话,使用 rpmconf -a 来处理各类 .rpm{save,new}

接下来是 Linode 限定部分。

  • 先在控制面板里做一个 snapshot
  • 全程使用 Glish 进行操作
  • 启动卡住时,进 Rescue 模式,chroot 进去用 journalctl -b -1 看日志

Linode 给虚拟机分配的磁盘一般是格式化好的一个完整文件系统镜像,相当于只有分区的内容,不是完整的磁盘。好在 ext 系基本都可以缩小,Linode 控制面板里也方便修改分区大小。实际上中途折腾失败时恢复 snapshot 自动建立的磁盘只有 23GB,而实际文件系统的使用量不到 10GB,不知道这个数字是怎么算出来的。

磁盘镜像的问题带来了第二个坑:bootloader。由于只有文件系统,装不上 bootloader,只能使用 Linode 的 GRUB2 方式启动系统。这种方式是由 Linode 提供 GRUB2,然后读取分区中的 /boot/grub/grub.cfg 作为配置文件进行启动,而 Fedora 默认的 GRUB2 配置文件在 /boot/grub2 里…与此相关的还有诸如 GRUB 界面乱码、卡死等问题。

为了解决这些坑,并且避免这些神奇的配置在以后升级过程中带来其他玄学问题,我创建了一个新的 unformatted/raw 格式的磁盘,进入 Rescue 分区,并将原磁盘的内容 rsync 到新磁盘的分区中。然后 chroot 进去,用 grub2-install /dev/sda 科学的安装 GRUB2。最后将启动方式改成 Direct Disk。

最大的折腾感受:滚动大法好!跨版本升级什么的太坑啦!

by hexchain at July 16, 2016 03:33 PM

July 02, 2016

Felix Yan

不双清给一加氢 OS 刷上 Google Apps

最近入爪一台一加 3,解锁刷 root 后几乎配置完了所有东西,然后才发现忘记了 gapps。网上看到许多人在这种情况下刷 gapps 遇到了各种各样的问题,一般都被建议双清解决。我查找了一些资料后,决定试试不双清自己修复权限问题。

安装 OpenGApps

这里的假设是已经刷过第三方 Recovery,我这里是 TWRP。从 OpenGApps 网站下载对应的包(我这里对应的是 ARM64、6.0),我选择了 nano 包。

重启进入 Recovery 刷入此包。然后不要急着重启,因为大量网友反应此时重启后会不断 fc。我在一加论坛找到了这样的方法,经实测有效(针对 TWRP,其他 Recovery 请自行调整):此时应回到 Recovery 首页,进入 Mount 页面勾上 System,然后回到首页依次选择 Advanced -> File Manager -> system -> priv-app -> SetupWizard,然后点击右下的选择气泡,最后点击 Delete 删除这个文件夹。

重启正常进入系统后,点击 Google Play 或直接添加 Google 帐号即可。

遇到的问题

一、Google Play 无法正常下载应用

Google Play 下载或更新任何应用时,提示 DF-DLA-15 错误。我找到的方法是进入应用管理清空 Google Play 及 Google Play Services 的数据后重试。

二、Google 联系人同步选项消失

帐户管理中的 Google 帐号内只剩下健身、人脉、应用数据,联系人同步不见踪影。Reddit 上有人指出授权 sync adapter 读写联系人即可,但 H2OS 的应用管理界面中似乎没有办法直接操作,因此我用 adb 手动进行了授权:

$ adb shell
$ pm grant com.google.android.syncadapters.contacts android.permission.READ_CONTACTS
$ pm grant com.google.android.syncadapters.contacts android.permission.WRITE_CONTACTS

执行后,重启手机即可,不需要如原文所说删除、重新添加 Google 帐号。

by Felix Yan at July 02, 2016 08:18 AM

June 26, 2016

中文社区新闻

screen-4.4.0-1 将无法连接(attach)旧的会话

如果升级到 screen-4.4.0-1 你将无法再次连接上(reattach)用旧版本 screen 开启的会话。所以请确保升级前已经关闭了所有旧的会话。

by farseerfc at June 26, 2016 06:49 PM

June 25, 2016

quininer kel

青龙会起源猜测

青龙会起源猜测

Fri Jun 24 20:03:11 2016

老伯脸色渐渐和缓,道“这桌子里有三百七十六份卷宗,每一份卷宗,都代表一宗财富,管理它的人。本来只有我一个人能指挥,因为他们也只接受我一个人的命令。”
律香川在听着!
老伯道“但无论谁,只要有了我的秘令和信物,都可以直接命令他们,现在我也全都交给你”
他又补充道“我对这三百七十六人的秘令和信物都不同,若是万一弄错,去的人立刻就有杀身之祸。”
律香川一直在静静地听着。
他本来就觉得老伯是个了不起的人,现在这种观念更加深直到现在,他才知道老伯的财产竟是如此庞大,如此惊人,就算用“富可敌国”四个字来形容,也不过分。要取这些财产,已不容易,要保持更不容易。
除了老伯外,他简直想不出还有第二个保持得这么久、这么好的秘密。
—— 《流星·蝴蝶·剑》

《流星蝴蝶剑》看到这一段的时候,第一个想起的是青龙会。

如此庞大的组织不禁引人深思,而《七种武器》里说:

“正月初三。”门外的人也重复说了两遍:“正月初三。”
这是日期,不是人的名字。也许不是日期,而是一个约好了的暗号。
但是现在这个暗号却代表一个人,属于一个极庞大秘密组织的人。
四百年来,江湖中从来未有过比“青龙会”更庞大严密的组织。
它的属下有三百六十五个分舵,分布天下,以太阴历为代表,“正月初三”,就代表它属下的一个分舵的舵主。
—— 《七种武器 之 离别钩》

四百年里从未有过比青龙会更庞大严密的组织。 而照《流星蝴蝶剑》的说法,孙玉伯的势力却似乎更大。

由此本人开了个脑洞 —— 青龙会的起源就是孙玉伯!

“我杀他,只因为我有个朋友不想再让他活下去。”
“你也有朋友?”思思笑了,“我从来不知道你也有朋友。”
她想了想之后又问:“你那个朋友随便要你做什么事你都答应?”
狄青麟居然点了点头。
“只有他才能让我这么做,因为我欠他的情。”狄小侯接着说:“他是现存江湖中最庞大的一个秘密组织首脑,曾经帮过我一次很大的忙,唯一的条件是需要我为他做事的时候,我也不能拒绝。”
他又说:“这个组织叫青龙会,有三百六十五个分舵,每一州每府每一县每一个地方都有他们的人,势力之大,绝不是你能想得到的。”
—— 《七种武器 之 离别钩》

  • 使用不为人知的秘密来控制权势者,典型的青龙会风格。
  • 称呼对方为“朋友”,典型的老伯风格。

律香川垂下头,黯然道“不必留给我…。”
老伯沉下了股,厉声道“你难道想死”
律香川头垂得更低。
老伯道“你绝不能死,因为你还要等机会不但要等机会替我报仇,还要等机会将我这番事业复兴,我没有儿子你就是我的儿。”
律香川道“是”
老伯展颜道“所以我大部分财产你都可自由支配,其中只有我特别注明的几份是例外。”
他神情忽然变得很奇特,缓缓接着道“那几份财产我是留给小蝶的。”
—— 《流星·蝴蝶·剑》

  • 老伯将卷宗分出了一部分留给女儿孙蝶,解释了为什么青龙会是三百六十五个分舵,而不是三百七十六。

高老大笑道“但你并不是没有来历的人,我已替你安排了个来历。”
孟星魂道“什么来历?”
高老大道“你姓秦叫秦中亭,是鲁东秦家的人,秦护花秦二爷的远房侄子,因为从小就跟着秦二爷手下的海客出海去做生意了,似从未在中原露过面,所以也就没有人认得你。”
—— 《流星·蝴蝶·剑》

龙五道:“你知道他是谁?”
柳长街道:“我不能确定。”
龙五道:“不妨说说看。”
柳长街道:“昔年有个了不起的少年英雄,九岁杀人,十七岁已名动武林,二十刚出头,就已身为七大剑派中崆峒一派的掌门,刀法之高,当世无双,人称天下第一刀。”
龙五道:“你没有看错,他就是秦护花。”
—— 《七杀手》

  • 《流星蝴蝶剑》和《七杀手》在同一时代,而《七杀手》在《七种武器系列》之前(又说七种武器之七)。 因此老伯或者某人使用老伯的资源创建了青龙会是可能的。

其他方向的例证,因为这里引用了丁情的小说,所以年表实际上是错的。 例如

小香摇摇头:“不会,李探花虽然把他的飞刀绝技传给了我祖父,却被我曾祖父知道了,当时就挑断了我祖父双手的筋络,使他终生不能发挥那些技艺。”
“这是为什么呢?难道你家跟李探花有什么过不去?”
小香只说了一句话:“我姓龙,我本名叫龙天香。”
谢先生偏又多问了一句:“你高曾祖父一定叫龙啸云。”
—— 《圆月弯刀》

《三少爷的剑》后续《圆月弯刀》里出现了龙啸云的后人,李寻欢到丁鹏之间差了近百年的时间。 所以《三少爷的剑》时间上应该在《边城浪子》之后,《飞刀,又见飞刀》之前。

不过这是题外话。《流星蝴蝶剑》时间上在《七种武器系列》之前应该是共识。

老伯没有回答只是接着道:“你只要一走进那镖局,就会看到一个又矮又脏的跛老人。他一定会问你是谁,你千万不能回答,连一个字都不能回答,要等他问你七次之后,你才能说‘潜龙升天’,只说这四个字,他就明白是我要你去的了。”
—— 《流星·蝴蝶·剑》

他微笑着道:“现在你该完全明白了吧?”
孟星魂摇摇头。他的确不能完全明白,因为他太激动,太欢喜。几乎已完全无法思索。
易潜龙很理解所以接着道:“我非但没有出卖老伯,也没有溜走。我从来就没有溜走过。”
孟星魂忽然理解,所以就替他说了下去,“别人以为你溜走的时候,其实你正在暗中为老伯训练那一批新血。”
易潜龙道:“不错,无论任何组织都和人一样,时时刻刻都需要新的血液补充,否则他不但会衰老腐败,而且随时都可能崩溃。”
孟星魂目中忍不住流露祟敬之色,因为他觉得在面对着的,是个伟大的朋友。
易潜龙也看得懂,微笑着道,“其实那也算不了什么,那些年轻人非但充满了热情,而且全都很忠实,要训练他们并不是件困难的事。”
—— 《流星·蝴蝶·剑》

  • 老伯有一个朋友叫易潜龙,也许是青龙会名字的来源? 比如老伯将卷宗传给给了易潜龙,易潜龙借此创立了青龙会。

不过以上都是毫无证据的牵强猜测。 只怪青龙会太过神秘,而七种武器尚未补全,也不可能补全了。

by quininer kel at June 25, 2016 12:22 AM

LastAvengers

编写便于打包的 Makefile

网络上关于 Makefile 的教程不少,但似乎都止于「如何用 Makefile 自动编译程序」, 而关于如何用 Makefile 安装程序的文章却寥寥无几。(也可能是我关键词不对,反正我搜了好久都没搜到) 最近在做 Srain 的时候,算是琢磨出了对于 make install 的比较正确的写法,

首先,对于生成的项目是单可执行文件的情况下,直接 install -755 xxx /usr/bin/xxx 就好了。 但是并非所有项目都只要单个可执行文件,程序可能还包含了 man 文档,icons,图片,配置文件等,这里只考虑项目需要已。

假设项目结构如下,代码文件里写了什么不重要~

.
├── build
├── data
│   └── pixmaps
│       └── srain-avatar.png
├── Makefile
└── srain.c

题外话:关于图标

对于图标,[1] 规定了图标在文件系统上的位置,程序只需要根据图标的名称就可已获得图标(当然要借助各种库函数,比如 gtk 的 gtk_image_new_from_icon_name), 根据 spec 看,程序应该依次检查 $HOME/.icons$XDG_DATA_DIRS/icons/usr/share/pixmaps

$XDG_DATA_DIRS 为空时,$XDG_DATA_DIRS 会默认为 /usr/local/share/:/usr/share/ [2](感谢 csslayer 指出)。

因此把图标安装在 /usr/share/pixmaps/usr/local/share/icons/usr/share/icons 下都是可行的,Arch Linux 偏向于安装在最后一个目录。 于是可以像这样安装 16x16 的图标:

cd data/icons/16x16; \
for png in *.png; do \
            install -Dm644 "$$png" \
                "$(DESTDIR)/usr/share/icons/hicolor/16x16/apps/$$png"; \
        done

PREFIX

除了图标之外,其他的数据文件应该如何组织? 对此 GNU 给出了他的规范 [3]:

GNU make 提供了 prefix 等变量确定各种文件安装的位置:

  • prefix 是下述变量的前缀,默认的 prefix 值应该是 /usr/loacl
    • exec_prefix 是下述变量的前缀,通常和 prefix 相等
      • bindir 安装可执行文件的位置,其值应为 $(exec_prefix)/bin
      • ...
    • datarootdir 用来安装只读的,架构无关的数据文件,其值应为 $(prefix)/share
    • sysconfdir 用来安装只读的配置文件,其值应为 $(predix)/etc
    • ...

[3] 中列出了各种用途的目录,但事实上我们不需要把数据文件分成那么细的粒度。对于简单的项目,只有 prefix 是必要的,其他路径都可以 hardcode。

make install 可以这么写(为了命名统一,prefix 用大写):

PREFIX = /usr/local

install:
    install -Dm755 "build/srain" "$(PREFIX)/bin/srain"
    cd data/pixmaps; \
        for png in *.png; do \
            install -Dm644 "$$png" \
                "$(PREFIX)/share/srain/pixmaps/$$png"; \
        done

放置各种文件的规范有了,但程序应该如何找到他的数据文件呢? 用 gcc 的 -D 参数声明一个宏,在编译的时候告诉程序的 prefix:

CC = gcc
CFLAGS = -O2 -Wall 
DEFS = -DPACKAGE_DATA_DIR=\"$(PREFIX)\"

TARGET = build/srain

$(TARGET): srain.c
    $(CC) $(CFLAGS) $(DEFS) $^ -o $@

在程序中你就可以根据这个宏在获得你的数据文件:

#ifndef PACKAGE_DATA_DIR
#define PACKAGE_DATA_DIR "/usr/local"
#endif

gchar *get_pixmap_path(const gchar *filename){
    gchar *path;

    path = g_build_filename(PACKAGE_DATA_DIR, "share",
            "srain", "pixmaps", filename, NULL);

    if (g_file_test(path, G_FILE_TEST_EXISTS)){
        return path;
    }

    g_free(path);
    return NULL;
}

注意上面的代码使用了 glib 函数库,当指定 prefix 为 /usr,程序便会从 /usr/share/srain/pixmaps 里寻找图片。

自行编译安装的程序通常被安装在 /usr/local, 这也是 GNU 推荐的 prefix
Arch Linux 的包的 prefix 通常是 /usr

如上一番设定后,程序经过编译和安装后便可以运行指定的任意目录上了,你也可以指定为 $(PWD)/build 方便调试。

make PREFIX=/usr; make PREXI=/usr install 后,产生的文件如下:

/usr/bin/srain
/usr/share/srain/pixmaps/srain-avatar.png

DESTDIR

上面的 make install 直接将各种文件安装在了目的文件系统上,如果 Makefile 写错的话,可能对系统造成破坏, 直接安装也不利于打包,正确的做法是,由 make install 得到程序所有文件的列表和路径, 再由包管理器把这些文件和路径存为软件包, 安装的时候根据路径把文件放到应该放的位置(这大概就是 Staged Install?)。 (这里感谢青蛙老师 hexchain 的指导)

变量 DESTDIR 就是用来实现 Staged Install 的,把之前的 make install 改成这样:

PREFIX = /usr/local
install:
    install -Dm755 "build/srain" "$(DESTDIR)$(PREFIX)/bin/srain"
    cd data/pixmaps; \
        for png in *.png; do \
            install -Dm644 "$$png" \
                "$(DESTDIR)$(PREFIX)/share/srain/pixmaps/$$png"; \
        done

注意 DESTDIR 变量只应该作用在 install 阶段,make PREFIX=/usr; make PREFIX=/usr DESTDIR=/tmp/ 会把所有文件都安装在 /tmp 下, 所有的影响都被限制在该目录内。这次生成的文件应该是:

/tmp/usr/bin/srain
/tmp/usr/share/srain/pixmaps/srain-avatar.png

之后再由包管理器把这些文件打成包,安装到系统中。

Configure

上面的 Makefile 有处不优雅的地方是,makemake install 的时候必须指定相同的 PREFIX,不然安装后的程序肯定是运行不了的,而 make 本身并不能 解决这个问题,因为 make 是「无状态」的。

[5] 提供了一个脚本来让解决这个问题,将 Makefile 改名为 Makefile.in,运行 ./configure --prefix=xxx 来获得一个拥有指定 prefix 的 Makefile,这样就可以不用每次敲 make 都输入 PREFIX=xxx 了。

于是大家都去用 autotool 了

#!/bin/sh

prefix=/usr/local

for arg in "$@"; do
    case "$arg" in
    --prefix=*)
        prefix=`echo $arg | sed 's/--prefix=//'`
        ;;

    --help)
        echo 'usage: ./configure [options]'
        echo 'options:'
        echo '  --prefix=<path>: installation prefix'
        echo 'all invalid options are silently ignored'
        exit 0
        ;;
    esac
done

echo 'generating makefile ...'
echo "PREFIX = $prefix" >Makefile
cat Makefile.in >>Makefile
echo 'configuration complete, type make to build.'

PKGBUILD

这样的一个项目打包起来是很愉快的 :)

pkgname=srain

...
build() {
    cd ${pkgname}
    mkdir build || true
    ./configure --prefix=/usr
    make
}

package() {
    cd ${pkgname}
    make DESTDIR=$pkgdir install
}

参考

  1. Icon Theme Specification
  2. XDG Base Directory Specification#Environment variables
  3. GNU Coding Standards#Variables for Installation Directories
  4. GNU Coding Standards#DESTDIR: Support for Staged Installs
  5. Practical Makefiles, by example

June 25, 2016 12:00 AM

June 17, 2016

百合仙子

Linux 作业控制实践

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

事情的起因是这样子的。

有一个非常常用的调试工具叫 strace。输出的信息是纯文本,一大片看起来累。在 Vim 里可以给它高亮一下,就好看多了。再加上各种搜索、清理,以及非常赞的 mark.vim 插件,用起来就舒服多了!

然而我并不想每次都让 strace 写到文件里然后再拿 Vim 去读,因为还得记着清理那些文件。如果数据量不大的话,直接通过管道传给 Vim 多好。

于是有了如下 zsh 函数:

(( $+commands[strace] )) && strace () { (command strace "$@" 3>&1 1>&2 2>&3) | vim -R - }

效果是达到了,但是这样子要中断 strace 的话,得去另一个终端里去 kill。按 Ctrl-C 的话,SIGINT 也会被发给 Vim,导致 Vim 显示空白。

所以嘛,得把 Vim 放到一个单独的进程组里,这样就不会在 Ctrl-C 的时候收到 SIGINT 了。但是,Vim 还得用终端啊。

一开始,我用自制的 expect.py 模块,给 Vim 分配了一个新的终端。这样子 Ctrl-C 好用了。然后我发现 Ctrl-Z 不好用了……

Ctrl-Z 还是挺方便的功能,临时需要执行个命令,不用开新的 shell(以及 ssh),直接按一下 Ctrl-Z,完事之后再回来,多好啊!就跟 zsh 的 Alt-q 一样方便好用呢。

于是就想还是不开 pty 了。直接子进程放新组里跑。这样 Vim 在尝试向终端输出时会收到 SIGTTOU 信号,因为它不是前台进程组。找了一下,用 tcsetpgrp 就可以把指定进程组放到前台了。然后发个 SIGCONT 让可能已经停下来了的 Vim 继续。

然后,当 Vim 收到 SIGTSTP 而停止的时候,我的程序该怎么知道呢?搜了一下,原来这种情况下也会收到 SIGCHLD 的!我以前一直以为只有子进程退出才会收到 SIGCHLD 啊……然后是一个关于 SIGCHLD 的坑,之前在 pssh 里看到过的,这次没有及时想到:不给 SIGCHLD 注册信号处理器时是收不到 SIGCHLD 的!不过诡异的是,我的这个程序有时却能够收到——在我使用 strace 跟踪它的时候……

于是,当 Vim 收到 SIGTSTP 时,把我们自己设置成前台进程组,然后给自己发一个 SIGTSTP 也停下来好了。令人意外的是,后台进程在调用 tcsetpgrp 时竟然也会收到 SIGTTOU。不过没关系,忽略掉就好了。

当用户 fg 时,就再把 Vim 设置成前台进程,并给它一个 SIGCONT 让它继续就好了。

最终的成品 vimtrace 在这里我的 zsh 配置是这样子的:

if (( $+commands[vimtrace] )); then
  (( $+commands[strace] )) && alias strace='vimtrace strace'
  (( $+commands[ltrace] )) && alias ltrace='vimtrace ltrace'
else
  (( $+commands[strace] )) && strace () { (command strace "$@" 3>&1 1>&2 2>&3) | vim -R - }
  (( $+commands[ltrace] )) && ltrace () { (command ltrace "$@" 3>&1 1>&2 2>&3) | vim -R - }
fi

后记:

strace 有时候还是会改变进程的行为的。这种时候更适合用 sysdig。Arch 刚刚更新的 sysdig 版本已经修正了崩溃的问题了~不过 Vim 对 sysdig 的输出就不像 strace 那样有好看的语法着色了。

其实我当时用 systemtap 来看信号发送情况更方便一些。不过那个需要内核调试符号,几百M的东西,装起来累啊……

by 依云 at June 17, 2016 08:21 AM

June 12, 2016

ヨイツの賢狼ホロ

在 Windows 中写 C 程序

说着说着一个学年就要过去了啦~

要说这半年(现在不是六月了么)印象最深刻的是啥,就是帮忙解决了身边不少同学的相同的问题……

--farseerfc 果然是先知啊(雾

ヨイツの賢狼ホロ 😋, [11.06.16 20:43] 😂😂

ヨイツの賢狼ホロ 😋, [11.06.16 20:43] /me 刚刚解决了些问题👍

ヨイツの賢狼ホロ 😋, [11.06.16 20:44] 解决了些社团同学的问题😂

farseerfc 😂, [11.06.16 20:44] [In reply to ヨイツの賢狼ホロ 😋] 感覺牙縫裡還夾著頭髮(

ヨイツの賢狼ホロ 😋, [11.06.16 20:44] [In reply to farseerfc 😂] 😂啥

莉莉艾塔·K·A (Лилы-Айта К.А.) , [11.06.16 20:44] [In reply to farseerfc 😂] ?!

farseerfc 😂, [11.06.16 20:44] [In reply to ヨイツの賢狼ホロ 😋] 一些骨頭在萌狼肚子裡(解決

ヨイツの賢狼ホロ 😋, [11.06.16 20:45] 😂

Felix Yan, [11.06.16 20:45] 太可怕了

Felix Yan, [11.06.16 20:45] 狼最近食欲很好啊

好了玩笑开完了(再纠结这个的话要不要亲自体验一下?😋)。其实就是因为这学期的 C 语言课,然后就栽在用啥写程序这个问题上了……

然而那些搞得咱想 **(😋) 的老师竟然还在用 VC6?? 对,就是那个老掉牙的而且在 Windows 7 以后的系统不好装的 Visual C++ 6 (╯^﹏^)╯ ┻━┻

所以在 问的不耐烦(实在吃不下) 之后,咱决定写点啥了……

最简单的方法:换 Linux 啦~

此处 Linux = 基于 Linux 内核的操作系统 😂

确实 Linux 上写 C 程序更方便些啦~

  • 大多数的 Linux 发行版上都带有 GCC (啥?汝不会连 GCC 都不知道是啥吧 , 赶紧补习一下吧~
  • 可能还会有手册页,包括标准库的大多数内容.
  • 另外,如果想继续深入学习的话,Linux 应该也算一门技能吧......

然而:

  • Linux 是个操作系统,这就注定了汝可能要花好长的时间先去学习如何使用这个操作系统😂
  • ......

所以咧?

如果汝有心情在这一领域深入下去 (而不是为了通过考试) ,可以尝试一下~ 😋

或者在 Windows 上搭建一个类 Unix 子系统?

最适合觉得装在真机或者虚拟机上太麻烦的人啦~

类 Unix 子系统其实就是运行在 Windows 上的一个程序啦~ 它用来提供POSIX系统调用的API, 这样在 Linux 等类 Unix 系统上写成的程序就可以通过重新编译来在 Windows 下运行啦~

目前名气最大的类 Unix 子系统有两个,分别是 CygwinMSYS2 , 如果非要咱钦定一个的话......那一定是 MSYS2 啦,因为有咱喜欢的 pacman 😋

考虑到长度的关系具体怎么安装咱下次再说吧 (挖坑的节奏......)

挑一个合适的集成开发环境?

集成开发环境(Integrated Development Environment,简称IDE)是一种辅助程式开发人员开发软体的应用软体, 在开发工具内部就可以辅助编写原始码文本、并编译打包成为可用的程序,有些甚至可以设计图形介面。

IDE通常包括程式语言编辑器、自动构建工具、通常还包括除错器。有些IDE包含编译器/直译器, 如微软的Microsoft Visual Studio,有些则不包含,如Eclipse、SharpDevelop等, 这些IDE是通过调用第三方编译器来实现代码的编译工作的。有时IDE还会包含版本控制系统和一些可以设计图形用户界面的工具。 许多支援物件导向的现代化IDE还包括了类别浏览器、物件检视器、物件结构图。 虽然目前有一些IDE支援多种程式语言(例如Eclipse、NetBeans、Microsoft Visual Studio),但是一般而言 ,IDE主要还是针对特定的程式语言而量身打造(例如Visual Basic)。

---- Wikipedia:集成开发环境

所以已经有先人想到了这个问题制作了很多(?)的集成开发环境啦~ 然而咱并没用过 (咱都是直接用 Arch Linux 的😏) ,这里列出几个咱见过的集成开发环境.

  • C-Free 好像是中国人开发的 IDE,好想要付费的样子 🤔
  • Code::Blocks 跨平台的自由软件。
  • Dev-Cpp 也是跨平台的自由软件. (话说学校的电脑里明明装着 Dev-Cpp 为啥还用 VC6 (╯ ̄﹏ ̄)╯ ┻━┻ )
  • Visual Studio ,这其实是个大型 IDE,对初学者来讲太重了些。不过最近更新的 Visual Studio 2015 Update 1 加入了 clang 作为编译器的功能,也可以拿来做 C 编译器啦~

GCC+文字编辑器?

其实上面提到的 IDE 里面一定是有编译器的,多半是GCC😂

其实 GCC 是有向 Windows 移植的,就是 MinGW 啦:

MinGW(Minimalist GNU for Windows),又称mingw32,是将GCC编译器和GNU Binutils移植到Win32平台下的产物,包括一系列头文件(Win32API)、库和可执行文件。

另有可用于产生32位及64位Windows可执行文件的MinGW-w64项目,是从原本MinGW产生的分支。如今已经独立发展.

---- Wikipedia:MinGW

实际应用上咧,多半会有已经打包好的 MinGW,可以帮助汝快速的准备工作啦~,例如 tdm-gcc

然后就是找个合适的文字编辑器啦~ 无论是 Atom , Visual Studio Code , 或者 Notepad++ 等等,挑一个自己顺手的就行啦~


好吧咱又算 抛砖引玉(挖坑) 了一次 😂😂😂

by ホロ at June 12, 2016 04:00 PM

百合仙子

SIGHUP, nohup, disown 以及 expect + sudo + bash + ssh

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

这些东西都和终端消失的时候(比如 ssh 连接中断)有关,但是细节上又各有不同。

nohup,去 coreutils 看源码就知道,是忽略 SIGHUP 然后 exec 相应的命令。信号处理器如果被设置成忽略,那么在 exec 之后依旧是忽略(与设置成用户自定义函数的情况不一样)。man 7 signal 可以看到说明。

disown 这个,我去看 zsh 的源码了。然而只看到 zsh 把进程从它的任务列表里删掉了,根本没提 SIGHUP 的事情。后来看到这个答案才知道原来 shell 也会发 SIGHUP 信号。

当然内核也会发 SIGHUP。查阅 drivers/tty/tty_io.c 可知,内核会给 session leader 及其组发 SIGHUP 和 SIGCONT,也会给前台进程组发,但是不会给后台进程组发 SIGHUP。那个是 shell 发的,所以 disown 之后后台进程就不会被 SIGHUP 干掉了。

所以,前台进程组如果没有被信号杀掉的话,会收到两次 SIGHUP 信号,一次 SIGCONT 信号。而后台进程组只会收到一次 SIGHUP。disown 过的不会收到任何信号。当然那些没死的进程,如果去读写终端,还是会得到 EIO 错误,写的时候还会收到 SIGPIPE 信号。

strace 可以观察到这些过程。

最后一个,出了问题。通过 expect 调用 sudo,然后登录服务器。终端断开时,expect 被 SIGHUP 杀死。sudo 会把用户发的信号传给它的子进程,但是内核发的不传。而 zsh 给 sudo 发信号时会因为权限原因而发送失败。于是后边的 bash 和 ssh 都会收不到 SIGHUP 信号。但是终端消失它们是能感知到的,所以这个出问题的进程树才这么深嘛。ssh 发现终端消失了,它干了什么呢?当然是通知对端终端没啦,然后等回复。对端 sshd 收到消息之后说,「哦哦,我去把 /dev/ptmx 给关掉。」于是 sshd 关掉了三个 /dev/ptmx 中的其中一个。所以这个 sshd 下的 bash 进程并不会得到 EIO 错误,还继续跑着。于是 sshd 还继续等着它跑完。于是这边的 ssh 还在等对端的 sshd 回复。于是这棵进程树就 hang 在这里了……

结论:还是 systemd 好啊,会话关闭时直接干掉这个会话启动的所有进程。需要在会话结束之后依旧运行的,自己用 systemd-run --user --scope xxx 启动就好。留下这些 sudo、ssh、bash 的还好,占用的资源不多。supervisorctl 这种的就囧了,死循环地读 stdin 又读不到东西,浪费一颗 CPU。

by 依云 at June 12, 2016 10:24 AM

June 05, 2016

Issac Ge

只有 Python 高手知道的 tuple

熟悉 Python 的人都知道,它从语法上支持的内置数据结构一共四种,即 tuple, list, dict, set 等, sequence comprehension 一共有三个,唯独没有 tuple comprehension, 其形式被解析为生成器表达式,而且表示单元素的 tuple 也很不一样,需要额外添加一个在新手看来十分碍眼的逗号(1,).

但其实我们只简单地把 tuple 理解为一个 immutable 版 list 了,并没有深刻理解到它的本质。推上有人如此一针见血地指出:

我终于发现了,tuple 既可以当数据结构,又可以当模式来匹配变量。所以 tuple 说穿了是一个「不规则又不可变的数据结构或模式」,自然没有「推导规律」介入的余地,也难怪没有所谓的 tuple comprehension 了。

一旦洞察 tuple 的本质后,您就发现,tuple 原来大有文章:

其一,事实上,返回多个值的函数实则是在返回一个 tuple, 只不过可以省略括号而已。一旦理解透这个,就不会再写出 tp, label_tp = [], [] if len(result) == 0 else zip(*result) 这大坑了。

其二,只有一个变量的 tuple 在模式里可谓等价于变量本身,于是不是说 (1,) 里的逗号多余,而是它本身的括号就多余,毕竟没人爱写 (a,) = (b,); 其实 () 才是唯一真正特殊的 tuple; 于是纯括号就可以被名正言顺地赋予数学上的意义了,即 (a) 等于 a, 而且其实这还带来了方便 wrap line 的额外好处:

1
2
3
hfm_dir_str = (
'/home/acgtyrant/Projects/HamsterForMTK/'
'Hamster_Android_SDK/src/com/mapbar/hamster')

其三,虽说没多少人喜欢 (1,) 这写法,但我们可以分拆 sequence 值成多行,且每行后更有一个逗号!这对强迫症患者真是终极福音:

1
2
3
4
5
6
7
8
9
10
11
12
phodopus_evaluate_command = (
command_pathname,
'-v', video_pathname,
'--proto', proto_pathname,
'--model', model_pathname,
'--mean', mean_pathname,
'-c', cascade_model_pathname,
'--lf_proto', lf_proto_pathname,
'--lf_model', lf_model_pathname,
'--lf_mean', lf_mean_pathname,
'--noshow',
)

于是我习惯分拆函数的超长形参列表多行了,且最后一行以右括号结尾;多行的 sequence 值则倒数第二行以逗号结尾,倒数一行以右括号结尾且不缩进。

其四,tuple 不光可当安全的 immutable 数据结构,而且效率公认比 list 好

此外,tuple 在模式匹配上也威力十足:

其一,方便交换变量:a, b = b, a, 毕竟等价于 (a, b) = (b, a) 模式匹配嘛。

其二,我在 坑坑重重的 Extended Iterable Unpacking 已提到过 PEP 3132 – Extended Iterable UnpackingPEP 448 – Additional Unpacking Generalizations, 您会发现原来它们也不过是模式匹配嘛。此外,我们倒不能直接用星号 unpack generator, 但照样可以模式匹配 a, *_ = range(10), 毕竟只要后者能迭代就行了。现在看来,由于我已经洞察了 tuple 的本质,对它原本的坏印象也没有了。

其三,如果您想要可读性更好的模式匹配,可以试试 collections.namedtuple 库。

最后谢谢 @lilydjwg 和 @catsinrain 对我原推的启发,详见此推文的 timeline:

Written with StackEdit.

熟悉 Python 的人都知道,它从语法上支持的内置数据结构一共四种,即 tuple, list, dict, set 等, sequence comprehension 一共有三个,唯独没有 tuple comprehension, 其形式被解析为生成器表达式,而且表示单

June 05, 2016 09:13 AM

June 02, 2016

Issac Ge

坑坑重重的 Extended Iterable Unpacking

学 Python 久了,就渐渐地发现了它的一些瑕疵,比如园括号不像方括号和花括号一样,即表示包含一个元素的 tuple 时要加碍眼的逗号 (1,), 贯彻推导语法时返回的是生成器而不是 tuple; 缩进不与作用域等价;现在我又发现,Extended Iterable Unpacking 也算是个坑。

$ ipython
Python 3.5.1 (default, Mar  3 2016, 09:29:07) 
Type "copyright", "credits" or "license" for more information.

IPython 4.2.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

 In [1]  a = ''.split()

 In [2]  a
 Out[2]  []

 In [3]  a = 'a'.split()

 In [4]  a
 Out[4]  ['a']

 In [5]  a, b = 'a'.split()
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-5-703eacb578ed> in <module>()
----> 1 a, b = 'a'.split()

ValueError: not enough values to unpack (expected 2, got 1)

 In [6]  a, b = 'a b'.split()

 In [7]  a, b
 Out[7]  ('a', 'b')

 In [8]  a
 Out[8]  'a'

 In [9]  b
 Out[9]  'b'

 In [10]  a = *['a']
  File "<ipython-input-10-78ebc69aca60>", line 1
    a = *['a']
       ^
SyntaxError: can't use starred expression here


 In [11]  a = ['a'][0]

 In [12]  a
 Out[12]  'a'

您看出来了吗?左边的变量有一个时,不 unpack, 直接 binding 整个 sequence, 而不是 sequence 里的第一个 元素;若要 biding sequence 里的第一个元素,只能通过索引引用,没有 unpack 的余地;当所要 biding 的变量有两个以上时,就 unpack sequence 并各自绑定各自的了,但数量要对得上!除非用星号匹配。于是这语法就和括号一样反直觉了。

此外 Python 3.5 实现了 PEP 448 – Additional Unpacking Generalizations, 用起来倒是舒服。

最后出题考读者:

tp, label_tp = [], [] if len(result) == 0 else zip(*result) 有什么惊天大坑?在 Disqus 回复即可,答得好的同学奖一个 featured comment 和 vote.

Written with StackEdit.

学 Python 久了,就渐渐地发现了它的一些瑕疵,比如园括号不像方括号和花括号一样,即表示包含一个元素的 tuple 时要加碍眼的逗号 (1,), 贯彻推导语法时返回的是生成器而不是 tuple;

June 02, 2016 02:13 AM

May 30, 2016

Issac Ge

要先判断 zip 接收的是不是空集

1
2
3
4
5
tp, label_tp = zip(*[
(log_rect, label_rect)
for log_rect in log_rects
for label_rect in label_rects
if _is_same_target(log_rect, label_rect, overlap_rate)])

您看出来这有什么陷阱了吗?当列表为空时,zip 函数的返回值就只有一个,即 label_tp 没有可以被 biding 的对象。

除了主动事先判断返回值的长度,似乎没有更好的办法了。

Written with StackEdit.

1
2

May 30, 2016 03:01 AM

不存在所谓的 with 作用域

自从开始用 with 管理资源后,我产生了一种致命的错觉:缩进等价于作用域,尤其是 with 语句会构成一种作用域。于是我对以下代码大吃一惊:

1
2
3
with open('.zshenv') as file_:
a = file_.read()
print(a)

a 居然可以在其所定义的上一层代码块访问到!当然,file_ 也可以访问,虽然已经被关闭了。于是说穿了,不存在所谓的块即作用域,函数才是元作用域单元。话说回来,这反常算是 Python 缩进语法的美中不足吧。

于是我就只在 with 语句处理和资源有关的部分了,其他语句挪到和 with 同等缩进的代码块里,有必要时就提前定义变量

Written with StackEdit.

自从开始用 with 管理资源后,我产生了一种致命的错觉:缩进等价于作用域,尤其是 with 语句会构成一种作用域。于是我对以下

May 30, 2016 02:54 AM

May 29, 2016

ヨイツの賢狼ホロ

MediaWiki 网站搬家记

如何把 MediaWiki 网站搬到另外一个服务器上?

这篇纯粹是来凑数的2333~

第一步:备份数据库 ......

说实话咱只用过 MySQL/MariaDB 😂,所以 mysqldump 解决 😂

# 这里用了一个重定向标准输出到某个文件
# mysqldump [连接数据库的各种选项,例如用户名啥的] [数据库名称] > somefile.sql
$ mysqldump -u wikiuser -p somedb > somefile.sql

然后输入密码,稍等片刻就会发现汝的当前目录下多了个文件 (例如 somefile.sql ),这就是导出的数据库啦~

第二步:传输文件

假设汝的 MediaWiki 安装在 /path/to/mediawiki 😂

如果汝能物理访问汝的两台服务器, 那就直接把 /path/to/mediawiki 和上一步备份的 SQL 转储复制过去不就好啦~ (╯・ω・)╯ ┻━┻

或者如果汝能用 SSH 连接两台服务器的话,可以试试这个:

tar czf - /path/to/mediawiki | ssh username@server tar xzf - -C /path/to/mediawiki

这一行命令做了这些:

  • 把 /path/to/mediawiki 打包成归档文件,不过输出到标准输出.

    (千万别说汝不知道啥叫管道以及管道怎么用) 😂

  • 通过 ssh 连接到目标服务器.后面是连接到服务器上以后执行的命令.

  • 后面的 tar 命令解开一个归档文件,中间孤独的 hyphen ("-") 表示要解开的文件来自标准输入. -C 参数用于改变解开到的目录.

别忘了把转储的数据库文件也 copy 过去😂

然后输入密码,稍等片刻 again ......

如果不行的话,那就传统的 FTP Copy 过去,就是可能慢点 😂

第三步: 还原数据库备份

mysql (MariaDB 也是这个命令):

# 这里用了一个重定向某个文件到标准输入
# mysql -u [用户名] -p [数据库名] < somefile.sql
$ mysql -u wikiuser -p somedb < somefile.sql

一些收尾工作

  • 数据库连接信息变了就去 LocalSettings.php 里改😏
  • 连外网的就去改 DNS 😂

好了大概就是这个 样子😂😂

by ホロ at May 29, 2016 04:00 PM

百合仙子

配置 Postfix 通过外部 SMTP 服务器发邮件

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

程序要发邮件。

我不想自己去连外部 SMTP 服务器,因为我懒得自己去处理各种错误。我们服务器上很多程序用的是 heirloom mailx 软件的 mail 命令。结果是有些服务器上有好几个甚至几十个 mail 进程卡在那里了。还有不知道通过什么东西发邮件的,偶尔会有邮件没发出来,发出来了的还因为在一个字符的多个字节之间换行再编码导致 mutt 和 Android 的 GMail 程序显示为乱码的。

所以我要用 Postfix,让它来处理这些杂事。之前只把 Postfix 用作普通的 SMTP 服务器过。然而现在目标邮寄地址是腾讯企业邮箱,对由子域名发出的邮件很不友好,老是扔垃圾箱里,连加白名单都没用……于是搜了一下,Postfix 是可以作为客户端登录到 SMTP 服务器来发信的。不过资料比较少,好不容易配置好了,自然要记录一下。

要登录腾讯企业邮箱发信,main.cf 里写上:

relayhost = [smtp.exmail.qq.com]:587

smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_use_tls = yes
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
smtp_sender_dependent_authentication = yes
smtp_generic_maps = hash:/etc/postfix/generic

/etc/postfix/sasl_passwd 里边写用户名和密码,比如 user@example.com 用户的密码是「password」,就这么写:

[smtp.exmail.qq.com]:587 user@example.com:password

/etc/postfix/generic 里配置信封上的发件人(MAIL FROM 命令)的地址重写,不然腾讯不收:

@hostname user@example.com

hostname 就是 Postfix 里那个 myhostname,默认是机器的主机名。这句配置的意思是,本来发件人地址是这个主机名的,全部改写成 user@example.com 这个。

然后生存 hash 数据库,并更改权限(更好的做法当然是创建的时候就弄好权限):

postmap /etc/postfix/sasl_passwd
postmap /etc/postfix/generic
chmod 600 /etc/postfix/sasl_passwd*

就绪,启动或者重新加载 Postfix 就可以了:

systemctl reload postfix

by 依云 at May 29, 2016 07:57 AM

May 28, 2016

Felix Yan

Pacman Hooks 简介

Pacman 5.0 带来了 Hooks 支持,但在大规模应用前,我们留出了一个多月的时间来让用户先升级到 Pacman 5.0(因为同时升级 pacman 和有定义 hooks 的包会导致无法正常执行这些 hooks)。现在距离 Hooks 正式投入使用已经过去了一个月,我觉得是时候介绍一下 Hooks 和如何使用它了。

先来看一个简单的 Hook:

[Trigger]
Type = File
Operation = Install
Operation = Upgrade
Target = usr/lib/tmpfiles.d/*.conf

[Action]
Description = Creating temporary files...
When = PostTransaction
Exec = /bin/sh -c 'while read -r f; do /usr/bin/systemd-tmpfiles --create "/$f"; done'
NeedsTargets

这个 Hook 的作用是:当检测到安装或更新的包文件中存在 usr/lib/tmpfiles.d/*.conf 时,在更新后对每个文件调用 systemd-tmpfiles --create 方法。前面的检测部分定义在 [Trigger] 部分,后面执行的操作定义在 [Action] 部分。下面我们分别了解一下这两部分。

一、[Trigger] 部分

首先需要了解的是可以用于触发的条件类别(Type)。上面的例子里使用了文件(File),即当操作中的包中存在对应文件时触发。另一个可选的 Type 是软件包名(Package),即直接匹配操作中的包名。

接下来,操作(Operation)选项限制了对软件包的操作类别。可以选择的操作有安装(Install)、更新(Upgrade)和删除(Remove)。一个 Hook 需要在多种操作执行时,如例子中那样写成多行即可。常用的组合有三种全部写上(更新缓存、数据库等)、写 Install+Upgrade(执行安装时的一次性操作)及与之对应的 Upgrade+Remove(卸载时的一次性操作)。

最后,我们需要定义具体的目标(Target)。如果目标是文件,这里需要写其相对根目录的完整路径,但需要去掉开头的 / 字符。通配符(*、?)可以使用,具体匹配时会使用 fnmatch 方法。同样的,在一个 Hook 中可以定义多个目标,类似例子中的 Operation 那样写成多行即可。

二、[Action] 部分

先看看 Hooks 的执行时机:

2016-05-28-130821-7661a5

可以看到,有两类明显不同的 Hooks: Pre-transaction Hooks 和 Post-transaction Hooks。

Pre-transaction Hook 在具体操作发生前执行,此时待升级的软件包还未被升级,待删除的软件包还未被删除,还可以让它们来绽放最后的光芒。因此,这种 Hook 通常和上面 [Trigger] 部分的 Upgrade、Remove 操作搭配使用。如 gconf 包的 gconf-remove Hook,会在 gconf schema 被删除前调用 gconfpkg --uninstall 命令来卸载对应的 schema。

Post-transaction Hook 则与它相反,是在操作完成后执行。如上面的 tmpfiles Hook。

这两种不同的类型被定义在 When 选项中,分别写作 PreTransaction 和 PostTransaction

Description 选项仅包含一个供人类阅读的描述信息。目前的通用做法是用动词进行时作为开头,英文省略号作为结束。显示在终端中会成为这样的效果:

(1/1) Creating temporary files...

Exec 选项定义了具体执行的命令。和上面 Target 选项不同,这里不但需要写出待执行命令的完整路径,还需要保留最前方的 / 字符。如果在命令中需要用到前面 Trigger 得到的具体结果(如上面例子),你还需要在 [Action] 部分写一行 NeedsTargets 来让被匹配到的目标成为 Exec 选项的 stdin 输入,一行一个。值得注意的是如果匹配到的目标是文件,我们在对它进行操作前也需要补上最前方的 / 字符,如上面例子中使用的 "/$f"

此外,[Action] 部分还有一些其他选项:

  • Depends 选项:定义 Hook 运行时需要的依赖。如果触发时对应依赖关系不满足,Hook 会拒绝运行。可以定义多次。
  • AbortOnFail 选项:当 Hook 执行失败时终止整个操作。这个仅对 Pre-transaction Hook 有效,毕竟 Post-transaction 发生在操作之后,定义这个选项没有意义。这个选项和 NeedsTargets 选项一样不需要任何参数。

总结

姗姗来迟的 Hooks 功能替代了许多原本在 .install 文件中定义的操作,大幅减少了在每个包中重复写这些操作的困扰,也节省了大量重复执行操作浪费的时间。目前有很多常见操作已经采用了 Hooks,但还有很多仍然在完善中。如果你在用的 AUR 包还没有采用这些 Hooks,请不要犹豫,赶快改改拍在维护者脸上吧!

关于哪些通用操作已经采用了 Hooks,可以参考这个 Wiki 页面。此外,如果想找更多 Hooks 的例子来研究,可以打开本地的 /usr/share/libalpm/hooks/ 目录,你已经安装的 Hooks 都在这里。

参考资料:上文中的 Wiki 页面,以及 pacman 源码

by Felix Yan at May 28, 2016 06:05 AM

May 24, 2016

Issac Ge

在 Python 里小试 Optional 手法

Python 天生不支持 Option 类型,typing 有个 Optional, 但也就只能用来当 type hints 而已。

当然,这并不妨碍我们自行贯彻 Optional 手法。今天我写的函数 parse 会把所有 *_pathname 都打开并解析其内容,它有四个可选参数,其中三个的默认值是 None.

1
2
3
4
5
6
7
def parse(
log_pathname,
label_pathname,
tp_pathname=None,
fp_pathname=None,
fn_pathname=None,
overlap_rate=kitti_rate):

也就是说用户可以直接调用 parse(log_pathname, label_pathname), 即不打算提供剩下的参数。这时 parse 可以自发构造临时文件并代替所要打开的文件,前者当然是空的,于是不怕照常被解析。

于是我们就需要判断对象是否为 None, 是则继续沿用原来的值,反之则用指定默认值的函数了,即类似于:

1
2
3
4
5
6
7
8
9
def a(b, c):
if b is None:
return c
else:
return b
d = None
a(d, 1)
e = 2
a(e, 1)

显然 a(d, 1) 为 1, a(e, 1) 为 2.

我看了支持 Optional 的编程语言,Haskell 用 fromMaybe(大概?),Rust 用 unwrap_or, C++17 用 std::optional::value_or(顺便独家爆料下,起这函数名的同行就在 C++ 众里,真是吾辈的福气)。

虽说 Python 没有这样的函数,但已经有足够简单好用的表达式了a = b or c.

言归正传,光判断 *_pathname 还不够,得用 tempfile.NameTemprorayFile 充当前者为 None 时所打开的文件才行。于是我仿照 Rust 的 unwrap_or, 封装了一个特化函数:

1
2
3
4
5
def _unwrap_or_tempfile(pathname, mode='r'):
if pathname is None:
return tempfile.NamedTemporaryFile(mode=mode, delete=False)
else:
return pathname.open(mode)

最后,其实 Python 标准库也有若干当对象为 None 时就返回指定 default 值的函数:next(iterable[, default]), dict.get(key[, default])dict.setdefault(key[, default]) 等等。于是我们可以在需要时,贯彻这样的 Optional 手法。

Written with StackEdit.

Python 天生不支持 Option 类型,typing 有个 Optional, 但也就只能用来当 type hints 而已。

当然,这并不妨碍我们自行贯彻 Optional 手法。今天我写的函数

May 24, 2016 09:23 AM

May 21, 2016

百合仙子

当 SSD 坏掉之后

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

某天,我注意到系统日志中有如下报错:

ata2.00: exception Emask 0x0 SAct 0x80 SErr 0x0 action 0x0
ata2.00: irq_stat 0x40000008
ata2.00: failed command: READ FPDMA QUEUED
ata2.00: cmd 60/18:38:64:ad:96/00:00:00:00:00/40 tag 7 ncq 12288 in
         res 41/40:00:64:ad:96/00:00:00:00:00/00 Emask 0x409 (media error) <F>
ata2.00: status: { DRDY ERR }
ata2.00: error: { UNC }
ata2.00: configured for UDMA/133
sd 1:0:0:0: [sdb] tag#7 UNKNOWN(0x2003) Result: hostbyte=0x00 driverbyte=0x08
sd 1:0:0:0: [sdb] tag#7 Sense Key : 0x3 [current] [descriptor] 
sd 1:0:0:0: [sdb] tag#7 ASC=0x11 ASCQ=0x4 
sd 1:0:0:0: [sdb] tag#7 CDB: opcode=0x28 28 00 00 96 ad 64 00 00 18 00
blk_update_request: I/O error, dev sdb, sector 9874788
bcache: bch_count_io_errors() sdb1: IO error on reading dirty data from cache, recovering
ata2: EH complete

啊,看来我的 SSD 要坏掉了么?!拿 bcache-status 看了一下状态,已经500多个报错了,但是我并没有遇到什么问题。看了一下 SSD 的 SMART 信息,也是500多个报错。这种报错出现已经有几天了,但是似乎影响并不大?SMART 报告也说「状况正常」。那就等有时间再处理好了,先把 bcache 缓存策略从「writeback」改成「writethrough」好了。我当时是这么想的。

出事的 SSD 是笔记本自带的,16G,被我用作缓存了。使用的是 bcache,一年之前我写文章讲过的。没想到刚刚一年,就开始出问题了。

过了一两天之后。我正上班中,同步 MediaWiki 数据时发现自己的机器又连不上了。我起初以为是网络问题,因为我记得很清楚我的机器是开着的。但是过了一会儿它还是不能访问。我 ping 了一下,却发现是通的!登陆到我作为路由器的树莓派上却发现,网络是正常的。能 ping 通笔记本,但是从树莓派上也 ssh 不了,访问 nginx 也没回应。所以笔记本还在线,但是系统出问题了。奇怪的是,访问另一端口上我用 Tornado 写的 Web 程序时却是正常的。

终于等到了下班。回到家里之后就听见笔记本风扇呼呼地响着。赶紧打开查看。htop 显示 journald 正在使用 CPU。于是去看 journald 日志,心里顿时凉了半截:日志只记录到上午,但满是上边那样的 SSD 报错。进一步的检查发现,/ 分区已经被挂载为只读,syslog-ng 日志比 journald 日志记录了更多的报错。火狐已经不知道什么时候挂掉了,并且启动不了。sudo 还是好的,但是运行 zsh 时会段错误。运行 bash 的话,会报一点错,可以看到有些文件已经变成无意义的数据了。bash 能启动,但是很奇怪的是,输入不了字符 e……想起还装了 dash,于是用这个连最基本的补全都没有的 shell,配合还没有挂掉的连着 VPS 的 mosh 上的 IRC 上网友们的帮助,尝试禁用 SSD 缓存。

结果是失败了。关于 bcache 有些资料与我看到的情况并不一致。重启会报一些错,然后我进入了 initramfs 里的 shell,尝试禁用 SSD,依旧失败中,脏数据写不回去,所以禁用不了缓存……不过看到了缓存中脏数据只有几百K。当然单位是什么我就不知道了……

放弃。又一天,我改从救援系统进入。记得有个工具能把普通分区转成 bcache。手机上网找到了,blocks。但是它并不能把 bcache 转回来。好在是开源项目,我读了一下代码,结合别人的说法,结论是:把普通分区转为 bcache,只要把分区缩小,在起始处空出一点空间,然后写入 bcache 的超级块就可以了。于是反过来,只要跳过 bcache 的超级块来读,就可以读到原来的分区数据了。

但是,bcache 超级块有多大呢?不知道。不过之前看到过一个扫数据的脚本,用类似的办法找一下分区数据的位置好了:

for i in {1..20}; do dd if=/dev/sda2 skip=$i | file -; done

file 显示在第8块的地方发现了「LUKS encrypted file」。这就是我要找的文件系统了!

为保险起见,先读读看。使用 losetup 把 /dev/sda2 映射成只读的 loop 设备,但是跳过开头的 8192 字节(dd 的块是 512 字节一个)。然后用 cryptsetup 解密。解密成功了。只读挂载解密之后的 ext4 文件系统。挂载成功了。看了一下内核日志,没有报错,没有警告。chroot 进去,正常,没有段错误,配置文件没有变成无意义的乱码。一切进行得好顺利!损坏程序比我以为的要轻不少呢!

为了确认损坏情况,我进行了一次模拟备份,也就是 rsync 的「--dry-run」选项。这样与最近的一次备份作比较,看看差异。结果很乐观,rsync 只报了十来个 I/O 错误。不过这也说明文件系统还是有问题的。

又一天。开始恢复系统了。还是从救援系统进入。进入 gdisk,删除原来的 sda2 分区,新建一个小了 8192 字节的分区。经验表明这样子删掉再重建分区表是没有问题的。也确实没出什么问题。不带 bcache 的文件系统出来了。解密之,然后使用 fsck 修复。修复过程中,fsck 问了我一大堆是不是要修复的问题。修复完毕之后,更改内核选项以便适应新的分区表,重启。

一切正常。不过根据之前 rsync 和修复过程中提到的文件名,去看了一下那些文件。都是最近更新系统时的一些 Python 文件。有一些文件消失了,另一些文件的权限和类型变得很奇怪。删掉,重装安装对应的软件包。完事了~不过没有了 SSD 缓存,能够感觉到有些操作会慢不少。

这 SSD 也真容易坏啊。刚刚一年呢。而且坏的过程很快,预警期只有几天。现在 SMART 报告已经出现过1000多个错误了,但整体评估还是「磁盘状况正常」……

好在我用的都是自由软件,虽然可能找遍整个互联网都没有个说法,但是还有实现它们的源码可以阅读,可以自己去思考解决方案。当然啦,就算这个 bcache 完全坏掉了,我也不需要太惊慌,因为我有备份嘛,更麻烦,但最多只损失几天的数据,不会突然之间什么都没有了。

by 依云 at May 21, 2016 08:45 AM

May 17, 2016

Issac Ge

御用 Path 规范

我曾经写过御用文件 IO 命名规范,那时给文件对象名起个 file 后缀,即 *_file, 且规定:凡格式贯彻 *_filename, *_pathname*_dir 的 identifier 都一定指向 str 对象,且当时只考虑 Linux 上的路径拼接,自然直接用 / 当 sep.

不过如今用 Python 处理路径多了,不免开始考虑模块化,对应的则有经典 os.path 库,但 JaHIY 推荐了 Python 3.4 新出的 pathlib, 我试了下,发现明显比前者好用多了,有很多有用的函数,比如 PurePath.suffix, PurePath.parent PurePath.name, PurePath.with_namePurePath.home 等等,此外直接用除法符号当拼接路径的操作符也令人眼睛一亮。于是我重新制定了基于路径上的新命名规范:

其一,所有 *_filename, *_pathname*_dir 的 identifier 都统统用 Path 类型,用没有 IO 副作用即不影响文件系统的子类型 PurePath 也可以。

1
home_dir = Path.home()

其二,pathname 一样用绝对路径,filename 用不包含任何目录分隔符的相对路径。不论是不是目录,都不再加额外的目录分隔符后缀,比如 /, 当然,文件名还是要加 suffix.

其三,拼接目录用 /, 必要时还可以用括号来 wrap line:

1
2
3
4
testset_dir = home_dir / 'BigDatas/daytime/testset'
cascade_model_dir = (
rp_dir
/ 'models/cascade_models/20x20-HAAR-14-0.99-0.5')

其四,虽说核心对类型是 Path 而不再是 os.path 所处理的 str, 好在互相转换也方便,只要在外围把 Path 类型对象传入接收 str 对象的函数时,再使用 str 函数转换即可,就和外围处理具体编码内部处理 Unicode 一样,甚至也可以用 map 来一气呵成地转换;反之亦然,即用 Path 函数转换,甚至可以无缝地直接套在原本的 format 函数上:

1
filename = Path('{}{}{}'.format('cascade', num_stage, '.xml'))

话说要是 Python 内置库自发支持 pathlib 就好了,这样不用在 open 里显式转换为 str 对象了,直接传路径来来去去,多爽!

其实 pathlib 还封装了 Path.open 函数,多谢 JaHIY 的提醒。

其五,为了照顾不熟悉 pathlib 的同行,可以用 type hints 来强调您所期望的 filename, pathnamedir 等类型为 Path.

其六,其实只要遵循以上编程规范,跨平台自然也就水到渠成了。

Written with StackEdit.

我曾经写过御用文件 IO 命名规范,那时给文件对象名起个 file 后缀,即 *_file, 且规定:凡格式贯彻

May 17, 2016 02:20 AM

May 16, 2016

Issac Ge

大话类型之乱伦

性向来是人类文明的禁忌,那是因为一旦放开这禁忌,那么「乱伦」会由于成本小而变得泛滥成灾,对人类群体的利益往往弊大于利,比如大脑与身体都尚未成熟的儿童怎么保护好自己的性权利?尚未经济独立的早恋少女怎么分娩并抚养子女?婚生子女和私生子之间怎么划分财产?同性恋怎么繁殖后代?性反转人士怎么上厕所?更别说近亲繁殖的子女往往具有基因缺陷了。

同理,在编程语言中,类型的乱伦行为也是大忌。一个类型家族的对象与另一个类型家族的对象发生关系,繁殖出新对象,如果父母彼此没有血缘(继承)关系,那么跟谁姓(类型),继承什么财产(属性)也比较好办,只要有章(语法与源代码)可循就行了,比如 C++ 用 operator 函数来规定双亲的繁殖行为。反之呢,乱伦现象就产生了!

事实上,我不觉得 Python 是真正意义上的强类型语言,因为它的 bool 是 int 的子类,且彼此可以发生关系。原则上不同类型的对象不等值,但 Python 里 1 == True 返回 True, 而且 bool 与 int 类型可以进行四则运算,如果 True/False 真单纯被转换 int 类型且运算结果是 int 好了,但事实上 1 + False == True 依然返回 True! 和直觉很不符,也就是说您很难说清 bool 与 int 的私生子到底跟谁姓,其值到底是什么,所以我才说这叫乱伦嘛,弊大于利,所以我就一直避免这种运算。

同理,对一切类似的乱伦行为保持警惕。比如 C++ 的多重继承语法可能不好用,因为既然父母彼此生殖隔离,那就很难明确子女到底继承了什么样的基因(属性),说难听点就是个怪胎;还有,虽说 Python 支持在 if 语句里调用对象的 __bool__(), 但您凭什么认为一切人都是男的?不光有天生的女性,也有爱女装的伪娘,您又是否有主宰后者上哪厕所的权利?所以说到底不要指望一切类型都显式支持 __bool__, 可读性也不好,所以我便习惯在 if 语句里只用纯粹的 bool 类型对象。

Written with StackEdit.

性向来是人类文明的禁忌,那是因为一旦放开这禁忌,那么「乱伦」会由于成本小而变得泛滥成灾,对人类群体的利益往往弊大于利,比如大脑与身体都尚未成熟的儿童怎么保护好自己的性权利?尚未经济独立的早恋少女怎么分娩并抚养子女?婚生子女和私生子之间怎么划分财产?同性恋怎么繁殖后代?性反转

May 16, 2016 04:55 AM

御用文件 IO 命名规范

Update: 御用 Path 规范 有 break 本规范。

我琢磨了一会该怎么命名文件 IO 上相关的对象,想好后,御用文件 IO 命名规范如下:

  • file 指被任意现代常规文件 IO 函数(比如C的 fopen(), C++ 的 ifstream() 和 Python 的 open()等)打开的文件对象名,被打开的文件可以是文本文件或二进制文件。
  • 用非常规文件 IO 函数打开文件时,一般用返回值的类型名来命名。比如:fd 指被 POSIX 底层文件 IO(比如C的 open() 和 Python 的 os.open()等)打开的文件描述符对象名;举一反三,可以用 image 命名 OpenCV 的 cv::imread() 打开的 cv::Mat 对象,可以用 dir 命名 POSIX 的 opendir 打开的 DIR * 变量,可以用 socket_fd 命名 POSIX 的 socket() 打开的 socket 描述符等。尽量别用缩写
  • filename只包含文件名、不含任何路径(包括相对路径)的字符串对象名。
  • pathname 指包含绝对路径的文件名的字符串对象名。
  • file, fd, img, dir, socket_fd, filename, 和 pathname均加前缀,以进一步区分,比如 image_filename, samples_pathname 等;不过,若只是个在函数内用的临时变量,也可以不用加,方便;也可以再加 s 后缀,以表明它在 Python 中可能是对应的 list, 在 C++ 中则可能是对应的 std::vector 容器等。
  • 不论字符串对象是 filename 还是 pathname ,如果字符串值中的文件是目录,一定要加 / 后缀;否则,就加文件格式后缀。
  • 在项目用文件 IO 函数时,如果要处理的文件和项目源代码无关,则必传 pathname 字符串对象;反之,可以用 filename 字符串对象,必要时再追加表示相对路径或绝对路径的字符串对象。

Written with StackEdit.

Update: 御用 Path 规范 有 break 本规范。

我琢磨了一会该怎么命名文件 IO 上相关的对象,想好后,御用文件 IO 命名规范如下:

May 16, 2016 04:01 AM

Python 作用域解析之补遗

有人把 Python 作用域解析规则总结为 LEGB, 确实够精炼简要。但我还要继续补遗:

其一,所谓 global 命名空间,都是隶属某模块名的。于是当解释执行(注意没有加 -m 参数)某 Python 源代码文件,或在交互式环境里,这个文件或交互式环境本身所谓的 global 命名空间,其实同样隶属一个模块,它的名字就叫 __main__. 如果您在被解释执行的文件或交互式环境定义一个函数对象 a, 那么 print(a.__module__) 会返回一个 str 对象,其值为 __main__. 说来好笑,我曾经纳闷有什么办法能访问到这模块,后来想想,其实我本来不就在文件和交互式环境本身里面啊,当然能随便直接访问了。

其二,import a, print(a.b) 很好理解,会先在 __main__ 模块解析到 a 这模块的名字,接着就在后者的 global 命名空间继续解析到 b.

其三,print(sum.__module__), def sum(): pass, print(sum.__module__) 会先后输出 __builtins____main__, 但这不是因为 rebinding 了 builtins 命名空间的 sum ,而是在 __main__ 模块的 global 命名空间定义了 sum 对象且后者被先解析到而已。此外您也可以__builtins__ 当成模块对象(注意不是 str 对象)来访问它 global 命名空间的值,比如 print(__builtins__.__dict__) 就返回一个字典对象,后者把 str 对象映射为您可以访问的内置对象。说起来其实这里很微妙,因为 __builtins__ 本身应该被解析为 __main__ 模块 global 命名空间的某对象了,但您并没有 import 它,也就是说它从一开始就默认存在,但偏偏又不隶属「如同字面意义上所真正内置」的 __builtins__ 模块的 global 命名空间!事实上您还可以显式 import builtins, 再继续访问它的属性……比如 print(builtins.__dict__) 就返回和 print(__builtins__.__dict__) 一样的值。

其四,del 可以在 __main__ 的命名空间删掉对库的引用,比如 import sys 后再 del sys, 您会发现 sys 库又访问不到了,可谓变相的 unimport. 那么 del __builtins__ 会发生什么?您在 __main__ 模块的 global 命名空间删掉了对 __builtins__ 的引用**,您自然没法用 int, str 之类的内置对象了,而且连 import builtins as __builtins__ 之类的补救方案都执行不了,因为连 __import__ 都找不到了。何等丧心病狂的 hack!

其五,from a import * 应该会直接把 a 模块所有 global 变量归属到 __main__ 模块的 global 命名空间,但是您如果试试输出模块 m 里的 b 函数所属的模块名的话,即 print(b.__module__), 它返回 m 而不是 __main__; 此外,如果 mn 各有函数 b, 那先后 from m import * from n import * 的话,那 print(b.__module__) 返回 n. 我把这灾难叫做作用域偏移

最后总结编程规范:

  1. 禁止一切 from * import * 形式的语句
  2. 不要乱动一切以下划线开头的东西,自然包括 __builtins__.
  3. 通过 del 来 umimport 库。
  4. 不要在 local 或 global 空间命名和 builtin 空间某对象重复的 identifier, 可以在名字后面加一个下划线以区分,比如 str_.

Written with StackEdit.

有人把 Python 作用域解析规则总结为 LEGB, 确实够精炼简要。但我还要继续补遗:

May 16, 2016 02:19 AM

May 15, 2016

Issac Ge

什么情况下 map 比 list comprehension 好?

事实上,list comprehension 公认效率比 map 好所以当 map 比 list comprehension 可读性好且不在乎性能时,可以优先用前者。

那问题又来了:什么时候 map 的可读性比较好?当且只当低阶函数是您所熟悉的 Python 函数,便利的 sequence 对象也够一目了然时。比如我就经常用它转换命令列表,够一气呵成:

1
2
3
4
5
6
7
8
traincascade_command = [
command_pathname,
'-w', weight,
'-h', height,
'vec', vec_pathname,
]
traincascade_command = map(str, traincascade_command)
subprocess.call(traincascade_command)

妈妈再也不用担心我不小心传 int, pathlib.Path 进命令列表了,写的 list comprehension 又长又臭得超出 79 个字符了。同理,rects = map(int, rect_strs) , positives = map(abs, integers) 之类的精炼表达式也可以。

因为您很清楚 str, intabs 等是一元函数,作用是什么;反之,即用您所不熟悉的 Python 函数,比如 a = map(b, c), 这时您往往会产生四重疑惑:

其一,b 是一个 callable 对象吗?
其二,b 可以只接受一个形参吗,即它到底是不是一元函数?
其三,c 是否为 sequence 对象?
其四,c 的 iterable 元素又是什么鬼?

更别说用雪上加霜的 lambda 了。

但换用 list comprehension 就没这问题:a = [b(d) for d in c], 显然 b(d) 表达了 b 彻彻底底是个一元函数,且 c 作为 sequence 对象时 iterable 元素是 d, 最终 a 会被 bind 到一个 list 对象。可读性更胜一筹。

举一反三,您可以琢磨什么情况下 filter, funtools.reduce 等也能如法炮制。

事实上,list comprehension 公认效率比 map 好所以当 ma

May 15, 2016 10:41 PM

May 12, 2016

ヨイツの賢狼ホロ

入手 Surface Book

这可不是oo什么的...... 😂😂

简单说就是咱搞了台 Surface Book 回来 (不是顶配所以不要说咱土豪啦😂😂

搞 Windows _(:з」∠)_

  • 升级到了最新的预览版 ( 用 Microsoft 账户登录就好)
  • 装了 Office 2016 (汝会明白为啥的😏
  • 把 osu! 复制到了 Surface Book 上 (用 Surface Pen 玩 osu! 的感觉真是酸爽😏

当然作为 Arch Linux 用户怎么不会去装 Arch Linux 呐?

  • 于是和 上篇文章 一样,用 Windows 内置的磁盘管理收缩了一个空闲分区出来. <(ノ=﹁"﹁=)ノ┻━┻

  • 因为懒得用 hashtool 给内核签名,于是咱直接关了安全启动:

    开机时按住音量加键和电源键进入 Sueface UEFI,在 "Security" 一节里把 "Secure Boot" 设置成 "Disabled" 就好.

装 Arch Linux ~(>_<~)

因为咱原来有个装着 Arch Linux 的移动硬盘,所以咱就计划直接把移动硬盘上的 Arch Linux 复制到 Surface Book 上.

但是因为 Linux 里其实是有些虚拟文件系统 ( 例如 /dev , /proc 一类的 ), 所以只好先用另一个 Arch Linux 的 Live ISO 启动 (╯ ̄皿 ̄)╯ ┻━┻

截至咱写这篇文章的时候, Arch ISO 里的内核 ( 像是4.4? ) 没法驱动 Surface Book 的键盘底座,所以坠吼搞一个 USB 键盘 😂
  • 首先按照 ArchWiki 的 Beginning Guide ,把刚刚分配出来的空闲空间新建一个分区.
  • 然后把原来的 Arch Linux 分区和新的分区挂载到两个位置 (假设源分区是 /mnt ,目标分区是 /target )
  • 接下来用 rsync 来同步内容:
# rsync的 -a 参数表示 "归档" 选项.
# -A 是保留 :ruby:`ACL|访问控制列表`
# -X 是保留扩展属性

# rsync -aAX /mnt/ /target

最后上一张图 😂

最后上一张图

by ホロ at May 12, 2016 04:00 PM

May 10, 2016

Phoenix Nemo

使用 Unbound 搭建更好用的 DNS 服务器

用了好久的 DNSMasq 方案终于在大半年前彻底炸掉了。

原因不光是 DNSMasq 性能和安全性完全不足以撑起公网缓存/递归 DNS 的任务,也有想要做反污染和加速的时候确实太蛋疼的问题。

现在使用的方案是 Unbound+DNSCrypt,外带一份加速列表。这段时间看来,不管在我本机还是在公网服务的两台,效果和反馈都很不错。

准备工作

需要的程序:

  • unbound
  • dnscrypt-proxy
  • makefile
  • git

makefilegit 用于处理 dnsmasq-china-list

Unbound 配置

修改文件 /etc/unbound/unbound.conf。没有这个文件的话,一般需要找一下软件包里提供的配置 example 文件复制过去。这里列出的仅包含需要修改的部分,其他的按照默认配置一般没有问题。

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
num-threads: 2 # 线程数可以修改为物理核心数
interface: 0.0.0.0 # 侦听所有 IPv4 地址
interface: ::0 # 侦听所有 IPv6 地址
# 如果只需要本机使用,则一个 interface: 127.0.0.1 即可
so-rcvbuf: 4m
so-sndbuf: 4m # 本机使用的话,这俩 buf 可以取消注释
so-reuseport: yes # 如果开了多线程,就写 yes
msg-cache-size: 64m # 本机可以设置 4m 或者更小
rrset-cache-size: 128m # 本机可以设置 4m 或者更小
cache-max-ttl: 3600 # 建议设置一个不太大的值...专治各种运营商 DNS 缓存不服
outgoing-num-tcp: 256 # 限制每个线程向上级查询的 TCP 并发数
incoming-num-tcp: 1024 # 限制每个线程接受查询的 TCP 并发数
# 下面这四个不需要解释了吧,不想用那个就写 no
do-ip4: yes
do-ip6: yes
do-udp: yes
do-tcp: yes
tcp-upstream: no # 默认是 no,隧道状态比较稳的话也不需要写 yes。一些情况下强制使用 tcp 连上游的话写 yes
access-control: 0.0.0.0/0 allow # 本机用的话建议设置 127.0.0.0/8 allow,局域网用适当调整
root-hints: "/etc/unbound/root.hints" # 没有的话在 ftp://FTP.INTERNIC.NET/domain/named.cache 下载一份
hide-identity: yes # 不返回对 id.server 和 hostname.bind 的查询。
hide-version: yes # 不返回对 version.server 和 version.bind 的查询。
# 不过下面有 identity 和 version 的自定义选项,不隐藏这些的话,修改下选项还可以卖个萌(´・ω・`)
harden-glue: yes # 建议打开
module-config: "iterator" # 禁用 DNSSEC 检查,如果上游不支持 DNSSEC 就关掉。注意这个选项有可能在其他 include 的文件里
unwanted-reply-threshold: 10000000 # 针对各种网络不服,数值为建议值,具体可以自己修改看看效果
do-not-query-localhost: no # 一般是为了防止扯皮丢包开着,不过等下要用 DNSCrypt 所以关掉
prefetch: yes # 蛮好用的,开着吧
minimal-responses: yes # 省带宽,开着吧。本机用可以关掉
# 关键部分来了,把默认查询全部丢给 DNSCrypt。使用 [地址]@[端口] 指定查询地址和端口,默认端口 53。
# 然后把国内的地址丢给国内的缓存服务器。这两个选项的顺序不能错哟。
# 如果使用隧道查询,把这个地址改为隧道对端的地址,或者一个国外的 DNS 服务器都可以,例如 8.8.8.8。
# 具体看是在对端开 DNS 还是直接用国外的服务器。后者的话,前面 outgoing-interface 可以直接设置隧道本地端的地址,不过要配合 dnsmasq-china-list 的话,还是写路由表比较合适,否则不够灵活。
include: "/etc/unbound/accelerated-domains.china.unbound.conf"
forward-zone:
name: "."
forward-addr: 127.0.0.1@5353

DNSCrypt 配置

修改文件 /etc/default/dnscrypt-proxy

1
2
DNSCRYPT_PROXY_LOCAL_ADDRESS=127.0.0.1:5353 # 设置侦听在 127.0.0.1 端口 5353
DNSCRYPT_PROXY_RESOLVER_NAME=cisco # cisco 其实蛮快的,但是慢的话就去用个别的吧。d0wn 的那堆服务器真的不稳定,和名字一个样...

如果使用 systemd 的话这个文件就没用辣,看这里看这里

修改文件 /usr/lib/systemd/system/dnscrypt-proxy.socket

要修改的部分:

1
2
ListenStream=127.0.0.1:5353
ListenDatagram=127.0.0.1:5353

127.0.0.1:5353 就是上面 unbound 配置里 DNSCrypt 的监听地址。

dnsmasq-china-list 来加速

首先 clone 这个仓库到本地,然后在 Makefile 里修改 SERVER=114.114.114.114,改为你觉得最合适的国内缓存 DNS 服务器。114DNS 最不太近的一段时间里都挺残的所以不建议用。

执行 make unbound 来生成一份 unbound 配置,然后放在上面 unbound 配置里写的地址,也就是 /etc/unbound/accelerated-domains.china.unbound.conf

如果还需要一些特定的缓存上游设置,要放在 include: "/etc/unbound/accelerated-domains.china.unbound.conf" 这句前面。来举一只栗子。

举一只果子的栗子。

AppStore 的加载和下载速度一直在国内饱受一些极客们的诟病,然而同时饱受诟病的运营商 DNS 解析 AppStore 的下载地址反而是国内的 CDN 地址,速度会非常快。

需要使用 dig 工具,并且要在国内的网络环境下测试。Linux 发行版里都有包可以装,OS X 则自带。

第一条命令:dig +trace a100.phobos.apple.com.

递归追踪解析结果,这个记录被 CNAME 到了 a100.phobos-apple.com.akadns.net.

第二条命令:dig +trace a100.phobos-apple.com.akadns.net.,得到这条记录被 CNAME 到了 a1-a200.itunes-apple.com.akadns.net.

第三条命令:dig +trace a1-a200.itunes-apple.com.akadns.net.,看到了 CDN 的地址,a1-a200.phobos.apple.chinacache.net.

所以如果有国内的地址直接去跟踪解析 akadns.net 的 DNS 的话,一般是可以正确解析到国内 CDN 的。先找一个 akadns.net 的权威 NS 地址,比如 a1-128.akadns.net 对应的 IP 是 193.108.88.128。同时还得有国内的 CDN 地址也从国内地址去解析,那么配置里这样写:

1
2
3
4
5
6
forward-zone:
name: "akadns.net."
forward-addr: 193.108.88.128
forward-zone:
name: "chinacache.net."
forward-addr: 119.29.29.29 # DNSPod PublicDNS 的服务器地址

多次尝试之后,发现还有一个 CDN 地址 0gq2p7eckbs26f.mwcname.com,那么也把这个地址交给 unbound 通过国内网络解析。

1
2
3
forward-zone:
name: "mwcname.com."
forward-addr: 119.29.29.29

一并加到上面的配置里,然后来测试下。

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
Phoenix-X1-Carbon :: ~ » dig @127.0.0.1 a100.phobos.apple.com

; <<>> DiG 9.10.3-P4 <<>> @127.0.0.1 a100.phobos.apple.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24454
;; flags: qr rd ra; QUERY: 1, ANSWER: 14, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;a100.phobos.apple.com. IN A

;; ANSWER SECTION:
a100.phobos.apple.com. 3596 IN CNAME a100.phobos-apple.com.akadns.net.
a100.phobos-apple.com.akadns.net. 117 IN CNAME a1-a200.itunes-apple.com.akadns.net.
a1-a200.itunes-apple.com.akadns.net. 297 IN CNAME a1-a200.phobos.apple.chinacache.net.
a1-a200.phobos.apple.chinacache.net. 1799 IN CNAME a1-a200.phobos.apple.cncssr.chinacache.net.
a1-a200.phobos.apple.cncssr.chinacache.net. 1799 IN CNAME cc00109.h.cncssr.chinacache.net.
cc00109.h.cncssr.chinacache.net. 120 IN A 223.99.228.87
cc00109.h.cncssr.chinacache.net. 120 IN A 113.207.33.15
cc00109.h.cncssr.chinacache.net. 120 IN A 113.207.33.12
cc00109.h.cncssr.chinacache.net. 120 IN A 202.110.80.14
cc00109.h.cncssr.chinacache.net. 120 IN A 61.179.105.154
cc00109.h.cncssr.chinacache.net. 120 IN A 61.179.105.7
cc00109.h.cncssr.chinacache.net. 120 IN A 119.188.138.172
cc00109.h.cncssr.chinacache.net. 120 IN A 120.192.248.195
cc00109.h.cncssr.chinacache.net. 120 IN A 221.181.39.76

;; Query time: 233 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Apr 28 00:34:02 CST 2016
;; MSG SIZE rcvd: 387

走国内 CDN 了吧~

重启相关服务,更改自己所用的 DNS 地址,完事儿收工(「・ω・)「

=== 2016-04-30 14:00 更新 ===

如果需要 edns-client-subnet 支持的话,需要手动编译源码安装。命令

1
2
3
4
# 克隆源码
svn co http://unbound.nlnetlabs.nl/svn/branches/edns-subnet/
# 编译安装
./configure --enable-subnet --with-libevent && make && sudo make install

配置文件的格式

1
2
# 默认向所有服务器发送 edns-client-subnet
send-client-subnet: 0.0.0.0/0

如果只对特定权威 DNS 发送 edns-client-subnet 请求,则按照此格式写多行 IP。

用了好久的 DNSMasq 方案终于在大半年前彻底炸掉了。

原因不光是 DNSMasq 性能和安全性完全不足以撑起公网缓存/递归 DNS 的任务,也有想要做反污染和加速的时候确实太蛋疼的问题。

现在使用的方案是 Unbound+DNSCrypt,

May 10, 2016 06:53 AM

May 08, 2016

ヨイツの賢狼ホロ

浅说基于 Linux 内核的操作系统 (7) - 双系统 Tips & Tricks

终于决定跳出虚拟机啦~

到底是啥原因让汝决定在自己的电脑上装 Linux 咧?

简单来说有下面两点:

  • 虚拟机的性能不足 (卡卡的很贴心)
  • 认为自己积累了一定的经验,希望再向前一步呗~

Act 1:该知道汝的电脑是 BIOS 还是 UEFI 启动了呗~

如果不知道的话,😋

  • 首先打开设置 ( Windows 8/8.1 叫做 "电脑设置"),然后通过 "更新和恢复" -> "恢复" -> "高级启动" 重启电脑.

如果是 UEFI 启动的话,大概是这个样子:

UEFI 系统启动之后大概像这样

没错就是有个 "使用设备" 的选项 😂

Act 2:在硬盘上准备一块空闲空间

不然要把 Linux 装到哪里去呐?

这里拿来演示的是 Windows 7 以后都自带的 “磁盘管理” 程序,应该能解决大多数问题 _(:з」∠)_

  • Windows 8 以后的系统可以通过按下 Windows + X 的菜单里找到 “磁盘管理”
磁盘管理在这~
  • 嗯,大概就是这样子的呗 (虽然具体的磁盘分区可能和咱的不一样)
大概长这样~
  • 汝哪个硬盘分区比较空闲? 右键点击它,有一个"压缩卷的选项"
”压缩卷“ 在这~
  • 输入压缩的大小 _(:з」∠)_
多少
  • 然后就多了一块未分配的空间 😂
多了一块未分配的空间

如果汝的硬盘分区有些刁钻而磁盘管理没法解决的话,AOMEI 家的分区助手不错, 这是官方网站 , 这是分区教程

Act 3:准备安装介质

其实基本上用的都是 U盘啦~

于是继续推荐编程随想的 如何用 ISO 镜像制作 U 盘安装盘(通用方法、无需 WinPE)

啥时候咱自己写一篇类似的...... 😂😂

Act 4:(UEFI 专属环节 (雾)) 关掉安全启动

啥是安全启动? 为啥要关掉咧?

安全启动是一个由电脑行业的成员开发的安全标准,它有助于确保仅使用受制造商信任的软件启动你的电脑。

当电脑启动时,固件会检查每个启动软件的数字签名,包括固件驱动器(选项 ROM)和操作系统。如果签名正常,则电脑启动,而且固件会将控制权交给操作系统。

然而默认情况下预装 Windows 的电脑中只会默认带有 Microsoft 的签名,而不是所有的 Linux 发行版都有能力获得签名的 Pia!<(=o ‵-′)ノ☆

所以就要关掉啦~ 😂😂

那么怎么关咧?

不过各种硬件实在是太多啦,咱实在是没法一一列举嘛~

  • Microsoft 提供的概述
  • 对于预装 Windows 的电脑,最好去看看生产商的支持网站.
  • 或者可以 Google 一下 ~(>_<~)

然后就是开始安装啦~如果遇到问题的话,先学习一下 提问的智慧 , 然后去汝安装的发行版的支持论坛问问呗~

by ホロ at May 08, 2016 04:00 PM

May 04, 2016

Issac Ge

惰性求值可能会导致作用域偏移

在 with statement 的返回语句处理前者所打开的资源,会发生什么?好在 Python 的语法十分妥当,确保了 return 语句还在 with 作用域之内,即在资源被回收之前,就会该处理好的就处理好

但是,若返回涉及资源的生成器表达式时,那又会如何呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Python 3.5.1 (default, Mar  3 2016, 09:29:07) 
[GCC 5.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> def a():
... with open('.zshenv') as file:
... return (line for line in file)
...
>>> a()
<generator object a.<locals>.<genexpr> at 0x7f900079c048>
>>> for b in a():
... print(b)
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in <genexpr>
ValueError: I/O operation on closed file.
>>>

印象中,Python 向来是一门基于垃圾回收机制的动态语言,语法设计得十分精良:变量即指向对象的指针;LEGB 确保作用域互不侵犯;with statement 就牢牢地划定了工程师可以访问资源的地方,资源在作用域里一定存在,反之则反,大家写起来也安心。

但是惰性求值打破了这份美景。事实上,生成器表达式本身就意味着惰性求值,即迭代到哪,哪里才会被求值并赋值,除此之外的「值」要么还没被迭代到,要么在迭代过后被销毁。于是我们可以说在上例中,惰性求值偏移了这些迭代对象的作用域到 with statement 之外,再在访问这些资源时已经晚了。

此外,据我所知,lambda 也可能会导致惰性求值

whenever any of the returned functions are called, the value of i is looked up in the surrounding scope at the time it is called (and by then, the loop has completed, so i has already been assigned its final value of 4)

事实上,Python 本身还是一门 late binding 语言,也许不为人知的某角落会发生无谓的惰性求值,害得作用域被偏移了,只能小心为上。总之先制定新编程规范:其一,不要在 with statement 里返回涉及资源的生成器表达式;其二,如果生成器表达式里的 lambda 或函数被绑定错了实参,可以构造一个默认参数并再传实参。

最后分享一篇有趣的文章:蟒之惰性

Written with StackEdit.

在 with statement 的返回语句处理前者所打开的资源,会发生什么?好在 Python 的语法十分妥当,

May 04, 2016 02:42 AM

April 30, 2016

百合仙子

愛される花 愛されぬ花

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

很早就听过这首歌,但现在才知道这首歌讲的是什么。很喜欢这首歌的歌词,不过像《ひとり上手》一样,好悲伤啊。

找到正确的对照版歌词并不是那么容易的,因为大陆网站莫名其妙地对日文汉字进行了「简化」。标注读音的就更难得了,所以我专门制作了标注汉字读音的中日对照版歌词,有兴趣的朋友可以看看:愛される花 愛されぬ花.pdf。感谢 farseerfc 进行校对。

我没有在 YouTube 上找到中岛美雪演唱的版本,所以只好用网易云音乐这个歌词并不正确版本啦: http://music.163.com/song?id=624802

泱泱大国,连周边国家的文字都不能写对,我也是醉了……

by 依云 at April 30, 2016 10:09 AM

April 29, 2016

百合仙子

一个系统,两套网络

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

创建并配置一个新的网络命名空间

公司 VPN 用的网段是 192.168.1.0/24,而我家里的网络,就像大多数人的一样,也是 192.168.1.0/24。网段冲突了。当然啦,隔离得相当好的 lxc 可以解决这个问题。可是它隔离得太好了,我可不想再多维护一套环境。那么,就只隔离网络好了!

正好之前看到 iproute2 套件可以管理网络命名空间。那么,就用它啦。

首先,创建一个名为 vpn 的网络命名空间:

ip netns add vpn

现在如果进去看的话,会发现里边只有一个孤零零的 lo 网络接口,所以里边是一片与世隔绝的黑暗。我没有其它的网络接口给它用。桥接当然是可以尝试的,只是需要更改已有的网络配置。所以还是用另外的方案吧。弄根网线来,把里边和外边连接起来好了。

创建一对 veth 接口。这就是我们的「网线」~

ip link add vpn0 type veth peer name vpn1

一端留外边,另一端移到 vpn 里边去:

ip link set vpn1 netns vpn

接好网线的两端:

ip link set vpn0 up
ip netns exec vpn ip link set vpn1 up

好了,现在两个网络之间可以通信了~当然,只是链路层。为了使用 TCP/IP,我们得分配 IP 地址。在外边的这个就不需要 IP 地址了,因为我要把它接到一个网桥上,网桥自己有 IP 的。

brctl addif br0 vpn0

这里 br0 是我已有的网桥(给 lxc 用的那个)。如果你没有的话,就自己按以下方法弄一个。我用的是 bridge-utils 里的 brctl 命令。iproute2 也可以做的。

brctl addbr br0
ifconfig br0 192.168.57.1
iptables -t nat -A POSTROUTING -s 192.168.57.1/24 -j MASQUERADE

最后的 iptables 命令是做 NAT 啦。当然内核的 IPv4 转发功能还要开启的。

vpn0 这端弄好了,再给 vpn1 分配 IP,并设置相关路由表项:

ip netns exec vpn ip address add dev vpn1 192.168.57.101/24
ip netns exec vpn ip route add default via 192.168.57.1

现在就可以在里边连 VPN 啦~

ip netns exec vpn openvpn ...

当然也可以去里边开个 zsh 用

ip netns exec vpn zsh

不过要注意如果跑 GUI,或者连接 D-Bus 的话,需要手动把相关环境变量移进去。虽然是独立的网络命名空间,但是因为共享了文件系统,所以虽然看不到在监听的 UNIX 套接字,但是连起来还是没有问题的。X 和 D-Bus 都可以良好工作的。

export DISPLAY=:0 LANG=zh_CN.UTF-8 LANGUAGE=zh_CN:zh_TW
export GTK_IM_MODULE=fcitx QT_IM_MODULE=fcitx XMODIFIERS=@im=fcitx
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
# 如果在 tmux 里的话
export TMUX=1

再加上 mount 命名空间吧

我这里在里边得用 IP 地址,因为我的 DNS 是 127.0.0.1,在里边当然是用不了的。怎么办呢?我不想改 DNS 服务器地址,因为里外的文件系统是共享的。那就再加上 mount 命名空间吧,这样就可以 bind mount 一个修改过的文件到 /etc/resolv.conf 上了。

其实呢,ip netns 是通过把网络命名空间(/proc/<pid>/ns/net)bind mount 到文件来实现命名空间的持久化的(不然使用这个命名空间的进程都退出,该命名空间就销毁了)。其文件位于 /run/netns 下。对于 mount 命名空间我们可以手工这么做:

mkdir -p /var/run/ns
mount --bind /var/run/ns /var/run/ns
# 命名空间只能 bind mount 到 private 挂载的文件系统上
mount --make-private /var/run/ns
# 随意找个普通文件就行。一般是用空文件;我这样可以省一个文件~
cp /etc/resolv.conf /var/run/ns

然后用 unshare 建立新的 mount 命名空间,并进入之前的 vpn 网络命名空间(当然用 nsenter 进入也是可以的):

unshare --mount=/var/run/ns/resolv.conf ip netns exec vpn zsh

创建了之后就可以用 nsenter 进去玩儿了:

nsenter --mount=/var/run/ns/resolv.conf --net=/var/run/netns/vpn zsh

可以在里边各种 bind mount,不会影响外边的哦:

# 在新的命名空间里边
mount --bind /var/run/ns/resolv.conf /etc/resolv.conf
vim /etc/resolv.conf

组合更多的命名空间

当然也可以组合更多种的命名空间的。我还试过 pid 命名空间,不过 pid 命名空间比较特殊:它在 fork 后才生效,当 init 进程(pid=1 的进程)退出之后所有位于此 pid 命名空间的进程都会被杀死,并且再也进不去了。所以不是很好玩的啦。

创建与进入的命令如下:

unshare --mount-proc -f --pid=/var/run/ns/pid --mount=/var/run/ns/resolv.conf nsenter --net=/var/run/netns/vpn su - lilydjwg
# 进入时用 -t 选项,或者重新 bind mount 文件(不然新进程会在原 pid 命名空间)
nsenter -t 9416 --mount=/var/run/mountns/resolv.conf --net=/var/run/netns/vpn --pid su - lilydjwg

后记

除了可能偶尔连接公司 VPN 会用到这个技术之外,我又给其找到了一个更好的使用场合:Wine QQ!于是本地的 nginx 日志里终于不会再有 /srv/http/cgi/reccom 找不到的提示了,CGI 服务也不会被不必要地启动了。

2016年5月13日更新:自用的脚本放在 Gist 上了。

by 依云 at April 29, 2016 09:23 AM

April 27, 2016

ヨイツの賢狼ホロ

火狐娘兼职 RSS 阅读器~

火狐娘也可以兼职做 RSS 阅读器呐~

啥? 又来问啥是 RSS ??

如果连 RSS 是啥都不知道那这篇文章就不用看了 (╯>_<)╯ ┻━┻

「自知之明者,谓之贤也。」

让火狐娘兼职 RSS 阅读器的好处和问题是啥咧?

  • 好处:又可以少开一个应用啦~ ( 不过对于用 Owncloud News 的咱来说好像没啥区别😂😂
  • 问题:好像没有大多数 RSS 阅读器那样把所有的文章安排在一个流里的功能 _(:з」∠)_

咱们来开始呗~

首先打开汝的 Firefox 😂😂 , 在右边的长条菜单里找到那个孤零零 (?) 的 "定制" 选项.

定制在这~

在左边就可以看到"订阅"按钮啦,把它拉到工具栏或者菜单里呗~ (订阅:我在这快来拉我~)

订阅:我在这快来拉我~

然后打开一个博客 ( 例如 百合仙子 lilydjwghttps://blog.lilydjwg.me )

举一个栗子~

如果这个网站有 RSS 的话 , RSS 那个图标就会亮起来,就像上面那样~


那么这个具体是咋实现的呢? 原理就在于这段 HTML 代码上~

<link href="https://blog.lilydjwg.me/posts.rss" rel="alternate" title="Blog RSS" type="application/rss+xml" />

这段链接到了一个 MIME 类型是 application/rss+xml 的文件呐~ 所以火狐娘看到这个就知道这个网站有 RSS 可以看了呢~

除了 RSS 以外火狐娘还认得 Atom Syndication Format(Atom供稿格式) 的标准哟~ ( 虽然也是 RSS 阅读器们的必修课 ~(>_<~) ), 像这样:

<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="约伊兹的萌狼乡手札 Full Atom Feed" />

如果有时 RSS 源不止一个,就挑一个呗~ ( 比如第一个 )

有时 RSS 源不止一个......

然后汝就会打开一个这样的页面呗~ 其实还可以支持其它方式 ( 例如 Owncloud 新闻阅读器 ) 订阅收取点,不过这次咱就用火狐娘的固有技能 "实时书签" 呗~

FireFox 解析的 RSS 页面~
使用

实时书签大概像这样,如果汝订阅的网站更新了的话文件夹和每篇文章旁边的 RSS 图标会亮起来的啦~

实时书签长这样~

当然如果汝习惯 RSS 那种文章流,把 RSS 页面加为书签呗~

把 RSS 页面加为书签呗~

by ホロ at April 27, 2016 04:00 PM

April 25, 2016

ヨイツの賢狼ホロ

权限的边界-关于社区的一些无关思考

权限到底有没有边界?如果有的话,又在哪里?

为了避免oo和xx,先来个前提声明呗~

  • 咱绝对没有炮轰文中提到的人 (或非人) 的意思,虽然他/她/它们之间曾经 (或是现在正在) 有过节. 但是这和咱又有啥关系呐~
  • 建议汝先读读 政治常识扫盲:澄清“言论自由”的各种误区 这篇文章来扫除一下汝内心中可能存在的几个误区呗~
  • 由于各种原因这篇文章可能写的很长?
  • ......

从一件小事开始?

前几天 #archlinux-cnfarseerfc 在 Telegram 上创建了一个日语学习群,虽然一开始加的人挺多的,但是......

请原谅咱一字不落的贴出聊天记录 ( 至少是现在,如果将来有人要求删掉又是另一回事了

Star Brilliant , [27.04.16 04:50] 刚刚是谁踢我的

Star Brilliant , [27.04.16 04:50] 某卷?

teleboto, [27.04.16 04:50] [u] 同被踢

ヨイツの賢狼ホロ 😋(🍎*), [27.04.16 04:50] 😂

Star Brilliant , [27.04.16 04:50] 搞得好像那群是他家似的

Star Brilliant , [27.04.16 04:50] 我进到群里看到他在说话都没说什么

Star Brilliant , [27.04.16 04:50] 大不了不打理得了

Star Brilliant , [27.04.16 04:51] 私事公办很不对吧

ヨイツの賢狼ホロ 😋(🍎*), [27.04.16 04:51] 😂😂😂

Henry King, [27.04.16 04:51] @m13253 他的意思是你进群之后秀水平了

Star Brilliant , [27.04.16 04:51] [In reply to Henry King] 哦?

ヨイツの賢狼ホロ 😋(🍎*), [27.04.16 04:52] [In reply to jm33_m0] 😂😂

Star Brilliant , [27.04.16 04:52] 因为我“有一点基础所以不应该学习”

Star Brilliant , [27.04.16 04:52] 如果那个群他是管理员我就不管了

farseerfc 😂 0xC13D4796, [27.04.16 04:52] 他是管理員啊,我和他一起開的……

Star Brilliant , [27.04.16 04:52] 或者说如果那个群是他办的我就无所谓了

Star Brilliant , [27.04.16 04:52] [In reply to farseerfc 😂 0xC13D4796] 那我就不管了

Star Brilliant , [27.04.16 04:53] 总之我和他有仇

ヨイツの賢狼ホロ 😋(🍎*), [27.04.16 04:53] /me 默默的围观就好了😂

Star Brilliant , [27.04.16 04:53] 而我现在出现在 #archlinux-cn 的原因,正是因为这个群不是他自己加的

Star Brilliant , [27.04.16 04:53] 自己家的

teleboto, [27.04.16 04:53] [u] 我进去似乎不到一分钟……

ヨイツの賢狼ホロ 😋(🍎*), [27.04.16 04:53] (但是话说回来咱可没秀水平啊😂

Star Brilliant , [27.04.16 04:53] “开始踢人”,砰!消失了

ヨイツの賢狼ホロ 😋(🍎*), [27.04.16 04:54] [In reply to Star Brilliant ] 和 @acgtyrant 一样 😂

Star Brilliant , [27.04.16 04:54] [In reply to ヨイツの賢狼ホロ 😋(🍎*)] 我想你不知道5年前那个盖子/opensuse事件

ヨイツの賢狼ホロ 😋(🍎*), [27.04.16 04:55] [In reply to Star Brilliant ] /me 咱就是把Telegram放在后台一会儿😂

ヨイツの賢狼ホロ 😋(🍎*), [27.04.16 04:55] [In reply to Star Brilliant ] 前一阵子翻暴君的老Arch博客来着😂

wicast C, [27.04.16 04:56] 群关了!!?

wicast C, [27.04.16 04:56] 洗个碗就不见了🌚

Henry King, [27.04.16 04:56] [In reply to Star Brilliant ] 😅 五年前啊。那个时候我还没怎么用 G+。

逐光入暗 TJM ¦ PGP 9F6B2D7D, [27.04.16 04:56] [In reply to Star Brilliant ] 求科普

teleboto, [27.04.16 04:56] [LastAvengers] u: 日语群么?

Star Brilliant , [27.04.16 04:56] [In reply to 逐光入暗 TJM ¦ PGP 9F6B2D7D] 这里不方便说

paco tacitus, [27.04.16 04:57] [In reply to Star Brilliant ] 啥事件?

ヨイツの賢狼ホロ 😋(🍎*), [27.04.16 04:57] 五年前咱还是Debian用户😂

逐光入暗 TJM ¦ PGP 9F6B2D7D, [27.04.16 04:57] [In reply to Star Brilliant ] 口以私了

Star Brilliant , [27.04.16 04:57] [In reply to 逐光入暗 TJM ¦ PGP 9F6B2D7D] 我建议你问盖子本人

paco tacitus, [27.04.16 04:57] 我私聊不了

逐光入暗 TJM ¦ PGP 9F6B2D7D, [27.04.16 04:57] [In reply to Star Brilliant ] O.O

Star Brilliant , [27.04.16 04:57] 因为我不知道事情的(完整)前因,但是知道后果

paco tacitus, [27.04.16 04:57] [In reply to Star Brilliant ] 能google吗

高坂 きりの, [27.04.16 04:58] 五年前是2011吗

Star Brilliant , [27.04.16 04:58] [In reply to paco tacitus] ない,大部分文字记录被“逼迫要求删除”了

高坂 きりの, [27.04.16 04:58] 关键字搜不到啊

Star Brilliant , [27.04.16 04:59] 大部分情况下,我会选择少一点人际关系的问题

Star Brilliant , [27.04.16 04:59] 钻研技术就好

Felix Yan, [27.04.16 04:59] 🌚 五年前……那时候盖子还很小吧(捂脸

teleboto, [27.04.16 05:01] [u] LastAvengers: tg太伤人了😢😢

teleboto, [27.04.16 05:03] [phoenixlzx] 我已經不知道该说什么好了,一个认真的学习群一群人在里面开始瞎扯,被踢了就开始自己瞎猜然后翻我旧账,翻旧帐也就罢了这么多年了也没查证过到底是谁的问题

Star Brilliant , [27.04.16 05:04] “瞎扯”

paco tacitus, [27.04.16 05:06] 就搜到了关于yum作者去世的事。。比尔盖子?

Star Brilliant , [27.04.16 05:07] [In reply to paco tacitus] 都是徒劳,该毁灭的都毁灭了

Star Brilliant , [27.04.16 05:07] 我还留存一份然而可能找不到了

Star Brilliant , [27.04.16 05:07] 没必要翻旧账了

paco tacitus, [27.04.16 05:07] 奇怪

paco tacitus, [27.04.16 05:07] 好吧

Star Brilliant , [27.04.16 05:07] 因为我不想劝说任何人改变对任何人/事物的看法

teleboto, [27.04.16 05:07] [phoenixlzx] 然而刚才你就在这么做

Star Brilliant , [27.04.16 05:08] 我不希望你们因为听说了这些事情而对中国开源社区产生什么不好的印象

teleboto, [27.04.16 05:08] [phoenixlzx] 而且五年前你也在这么做

paco tacitus, [27.04.16 05:08] 🌚👍

teleboto, [27.04.16 05:10] [phoenixlzx] 再回来说这个日语群,本来也只是我自己想学而已,死皮赖脸去找fc前辈来带路,结果突然就来了一群人在聊东聊西,还有自以为比别人优秀就在秀的,这个群还怎么学习

teleboto, [27.04.16 05:11] [phoenixlzx] 一堆呆在日本几年的人拉进来帮忙的,都还没说话呢

Star Brilliant , [27.04.16 05:11] 简直

David Huang, [27.04.16 05:11] 🌚

teleboto, [27.04.16 05:12] [phoenixlzx] 不要太把自己当大爷了

paco tacitus, [27.04.16 05:12] 好吧。。我搜到那个事了🌚

paco tacitus, [27.04.16 05:12] 有点过分

ヨイツの賢狼ホロ 😋(🍎*), [27.04.16 05:12] [ 😂 (sticker) ]

Star Brilliant , [27.04.16 05:14] [In reply to teleboto] 我想告诉你的是,因为种种原因,我B了你,然而我在群里看到你存在的时候都“宽容”(暂且这么说)地忍了,你的做法真的合适么?

Star Brilliant , [27.04.16 05:14] “聊东聊西”得说出点证据

Star Brilliant , [27.04.16 05:14] 至于某旧账,我也不想多说

Star Brilliant , [27.04.16 05:15] 本来我是想点到为止,你自己一个人知道就好

Star Brilliant , [27.04.16 05:15] 毕竟群里其他人都不知道这个事情

Star Brilliant , [27.04.16 05:15] 有人问我这个事情到底怎么回事的时候我也没说

teleboto, [27.04.16 05:15] [phoenixlzx] 首先这个群是我和fc开的,我B你的时候你还没B我呢知道伐?本来我也可以看到你进来就直接踢掉你然而还是觉得既然来学习也就算了

teleboto, [27.04.16 05:16] [phoenixlzx] 结果呢

Star Brilliant , [27.04.16 05:16] 你应该知道我b人一般不会点击“b”

Star Brilliant , [27.04.16 05:16] 而是肉眼打码

Star Brilliant , [27.04.16 05:16] 结果怎么

teleboto, [27.04.16 05:16] [phoenixlzx] 我不管你怎么样 那是你自己的权利和我无关

Star Brilliant , [27.04.16 05:16] 结果我说了什么跑题的话了么?

Star Brilliant , [27.04.16 05:17] 那就无关好了

Star Brilliant , [27.04.16 05:18] 我不想刁难你

Star Brilliant , [27.04.16 05:18] 我也不希望你刁难

Star Brilliant , [27.04.16 05:18] 我

Star Brilliant , [27.04.16 05:19] 过往的恩怨也无所谓

那么,来大致梳理一下情况呗~

  • farseerfc 在 Telegram 上创建了一个日语学习群.然后在 #archlinux-cn 邀请加入.
  • 因为 fc 的邀请有好几个人加入了 (比如咱)
  • 一开始在试着用日语交流,还挺正常. (不过咱就是一直在发表情 😂😂)
  • (然后咱把 Telegram 最小化到后台了一阵子)
  • 再打开发现咱已经被移除出群了 (当然不止咱一个)
  • 然后就是上面那些聊天记录了😂😂

一些不负责小分析 _(:з」∠)_

  • 那个群是 farseerfc 开的, 然后给了 phoenixlzx Administrator,姑且算他俩的私人空间

    因为不满足公共空间的第一个特征:"不属于任何个人,不属于任何组织/机构。"

  • 很显然,因为是私人空间,所以其他人有没有言论自由,要看管理员是否愿意给.

  • 然后,因为是学习向群组,一定不希望被无关内容打扰.(这个好像大家都默许)

  • 最后,因为太多人开始跑题于是 phoenixlzx 开始把某些她认为造成跑题的人移出群.

  • 对此创建者 farseerfc 既没有表示反对又没有采取补救措施?

    当然也是因为被移除的人都没有要求再回去的缘故,所以咱认为这不是 fc 的锅

  • 就是这样, 事实已经说明了一切

于是咱自己的结论如下:

  • 如果只发表情和 sticker 算是对消息流的干扰而导致咱被移除的话,那是咱的错.

  • 但是如果 phoenixlzx 能给个更准确的解释说不定更好?

    或者他希望通过私聊解释只是因为不是双向联系人做不到 (Telegram 一大天坑 😂😂😂 )

  • 不管怎么样,咱并没有对 phoenixlzx 的做法表示不满,毕竟:

    "在【别人的】私人空间有没有言论自由捏?这就要看那个私人空间的主人是否给你言论自由。如果空间的主人允许,你就有;反之,则没有。"

好吧下面进入自问自答环节 😂

但是仔细想想还是先把问题列出来再分开回答吧 (才不是没时间了呐~)

Q1 : 社区或群组要不要有规则,如果有的话,谁来制定,怎样制定?

Q2 : 有比一般用户更高权限的用户是否该有更高的限制?

Q3 : 在群组中防止信息流被无关信息干扰是不是共识,具体操作起来呐?

Q4 : 关于封禁或移除之类的措施要不要在事后由操作者给相关人员一个看似合理的解释?

Q5 : 曾经在某个项目有过节的两人能不能在另一个项目上重归于好?

......


暂时想到的就这么多,欢迎各位在下方的评论里给出自己的解答或是邮件联系咱呗~

by ホロ at April 25, 2016 04:00 PM

April 23, 2016

April 22, 2016

ヨイツの賢狼ホロ

闲聊技术文章的写作姿势

不过真的有一种正确的姿势么 _(:з」∠)_

其实咱为啥写这个 几乎全是瞎扯 的博客的一个主要原因就是有时找不到合适的文章或文档 😂😂

所以,技术文章怎么啦~ (╯T︿T)╯ ┻━┻

擅长前端的 老司机 卡夫 ( frantic1048 ) 推荐了一篇叫做 技术文章常见的 5 个问题 的文章. o(* ̄3 ̄)o

里面提到了撰写技术文章遇到的常见的问题:

  • 目的不明确。“所以,搞着些玩意儿是要干啥?”
  • 文章内容太过狭窄。“噢,这篇文章只面向 20 岁的见习风系魔法学徒使用,不看了”
  • 贴代码没注释。“这个野生的咒语是干啥的?”
  • 前后不一致的口吻。“我感觉快要精分了 ~(>_<~)”
  • 写到最后没有个结论。“(..•˘_˘•..)”

frantic1048 in 知乎

( ,,´・ω・)ノ"(´っω・`。)

提前注明一下 : 下面的栗子纯属虚构呐~ 如有雷同..... (放心这不会发生的😋

技术文章问题之一 : 目的不明确 <(=﹁"﹁=)>

由于深受语文教育的毒害 ,一般都会认为一篇文章都要有一个主要表达的意图或是观点呗 ( 没错就是那个众人寻他千百度却在灯火阑珊处的中心思想😂😂 ), 当然汝说的如果是一篇 形散神聚的 散文那就又是另一个怎么也解释不清的玄学了 (明明是我先的......

然而实际情况是,有时容易搞不清楚文章的主题,典型的情况就是...... ( 咱给忘了 (つд⊂)

试想一下一个希望看到某个主题的读者在看到全篇都在讲另一个主题的时候的感觉, 真的好想把浪费咱时间的作者咬死 😂😂

技术文章问题之二 : 文章内容过于狭窄 ~(>_<~)

内容过于狭窄就容易给读者 "这篇文章不适合咱" 的错觉,于是就关掉了......

有可能是因为很多时候自己的博客有点像自己的笔记,解决一个问题以后写一篇,于是整片文章都在讨论如何解决某一个具体的 问题,看着就 "内容过于狭窄" 了 | ω・`)

在这里咱要好好反省一下自己,因为咱好像一直在写像是教程一类的东西于是就没有多少深度 😂

技术文章问题之三 : 贴代码没注释 (╯>_<)╯ ┻━┻

写代码没注释就像汝拿着一本魔法书却不知道怎么使用呐~

“这个野生的咒语是干啥的?” _(:з」∠)_

比如上面那个歪果仁提的栗子:

<!-- offset 2 -->
{{ range $index, $element := .Site.Pages }}
    {{ if gt $index 1 }}
    <li>
        <span class="date">{{ .Date.Format "Jan" }}
        <strong>{{ .Date.Format "2"}}</strong></span>
        <h3><a href="link">{{ .Title }}</a></h3>
        <p>{{.Description}}</p>
    </li>
    {{ end }}
{{ end }}

尽管因为咱以前用过 Jinja2 所以知道这是 Jinja 模板的一部分,但肯定有好多人看到 HTML 就一阵惊慌失措啦 ( 更别提 HTML 里还有一堆大括号啦 (╯>▽<)╯ ┻━┻ )

在这里咱要好好反省一下自己*2,好像咱也经常忘记写注释......

顺便给 frantic1048 点个赞 ( 例如这篇 )

o(* ̄3 ̄)o

技术文章问题之四 : 前后不一致的措辞 ( ̄ε(# ̄)☆╰╮( ̄▽ ̄///)

比如前面用 "我" 后面不知道到了哪里就变成了 "我们" 这一类的问题,

读起来感觉自己都要精分啦 (╯@﹏@)╯ ┻━┻

技术文章问题之五 : 没有总结 “(..•˘_˘•..)”

......

上面就是一个绝佳的栗子 😂😂

那么啥样的姿势比较好咧? ~(>_<~)

其实上面那篇文章里也给出了四个建议 😂😂

建议之一 : 拥有个性 (σ≧∀≦)σ

要知道汝写的是文章而不是 死板的 API 文档呐~ 一个好的写作风格说不定可以帮汝拉来新读者哟~ 😋

建议之二 : 但是也不要个性过了头 <(ノ=﹁"﹁=)ノ┻━┻

既然是技术博客嘛,一定的严谨和专业性还是有必要的啦~ ( 比如不要有太多的错别字啦 (╯@_>@)╯ ┻━┻ )

建议之三 : 主线要有主线的存在感 ʃ ̂͜•̄ ̱̩ ̄͜►

不要把主线搞得像阿卡林一样没有存在感啦~

即使要插支线剧情也要以不同的形式让读者能轻易分辨,不要和主线混在一起,以及别太长。

建议之四 : 基本的排版 (・∀・)

文章分节的标题之类的可以帮助读者能够快速了解文章大体内容啦~


介于咱也不是什么写博客的菊苣,咱也就只能抛个砖引个玉.欢迎各位大触前来指教呗~

by ホロ at April 22, 2016 04:00 PM

April 19, 2016

Phoenix Nemo

公共场合请使用指纹识别器

前几天带本本去导师办公室修改论文,虽然开机启动速度快,但是还是在老师的注视之下紧张敲错了三遍密码…得,本来没在意的也记住密码了(ry

所以为啥有指纹识别器的本子偏偏要输密码(:з」∠)

检查设备

总之先来看下指纹识别器是哪家生产的好了。

1
2
Phoenix-X1-Carbon :: ~ » lsusb | grep -i 'finger'
Bus 001 Device 003: ID 138a:0017 Validity Sensors, Inc. Fingerprint Reader

搜索一下就发现 X1 Carbon Gen3 这么受欢迎的本子早已上了 ArchWiki https://wiki.archlinux.org/index.php/Lenovo_ThinkPad_X1_Carbon_(Gen_3)

安装驱动

安装 fprintd 包,这个包会依赖 libfprint,但是官方仓库中的 libfprint 目前的版本在此指纹识别器上无法正常工作,表现为 enroll 只扫描一次,并且无法验证指纹。

Note that recent versions of fprint are broken for this model : One is able to enroll a finger but recognition always fails.

GitHub 上已经有了 vfs5011 相关的 issue 和 fix,但是还没有发布新的稳定版。所以暂时安装 aur/libfprint-git 包。

配置指纹验证

Fprint - ArchWiki 上已经给出了配置方法。将 auth sufficient pam_fprintd.so 加入 /etc/pam.d/system-local-login 中的第一位置即可。同样方法可以用于 /etc/pam.d/ 下的其他文件。例如 KDE 登陆使用的 sddm

扫描指纹,以普通用户身份命令:

1
$ fprint-enroll

默认是右手食指。可以使用 -f 选项指定手指。正常的表现为成功扫描五次即可保存指纹,并且在需要验证的时候自动启动指纹识别器。不过还有个小问题,如果保存多个指纹,似乎只能识别保存指纹列表中的第一个。

然而我懒得折腾了就这样吧

前几天带本本去导师办公室修改论文,虽然开机启动速度快,但是还是在老师的注视之下紧张敲错了三遍密码…得,本来没在意的也记住密码了(ry

所以为啥有指纹识别器的本子偏偏要输密码(:з」∠)

April 19, 2016 08:48 AM