扇贝单词的一些缺点

最近一段时间,我成为了扇贝单词的重度用户。过去的60天,我给扇贝提了20条建议。

但,客观来讲扇贝还是有很多缺点,所以记在这儿,供各位参考。

  1. Web和app功能不一致
    1. 比如app有听词模式,web没有
    2. 比如web可以编辑释义,app不能
    3. 比如web可以添加例句,app不能
  2. Web的释义和app释义不一致,官方回复是app是新版,而web正在改版
  3. 释义不准确,比如有的缺少释义、有的没有释义(我很好奇,没有释义的单词是怎么录入的?)
  4. 单词读音展示问题
    1. 有的单词是美音和英音读音不一致,然后我点击美音,它把两个读音都读出来了……
    2. 有的单词是,不同读音对应不同含义,扇贝根本没有标记出来读音和含义的对应关系
  5. 网页背单词,在Firefox上,快捷键没法使用

我当前在背考研单词。等当前词本结束之后,我会尝试下其他背单词软件的。

阅读更多

Firefox不应该管理DNS(和证书库)

Firefox已经越俎代庖,开始管理证书了,而且还想染指DNS。

最近Firefox在nightly版本中添加了DNS overt HTTPS的支持,第一眼就觉得这个事情不是系统来做吗?比如Android支持DNS overt HTTPS才是比较合理的事情嘛。

看了Reddit上面的评论,发现其他人也有类似的感觉,不止一个人觉得这事应该由系统来做。

另外,这也可能会导致hosts文件配置失效;而在web开发中,修改hosts文件是常用的操作。

而且,Firefox中没有清除DNS缓存的地方,所以很多时候,对于hosts的修改,不能立即在Firefox中看到结果。

总而言之,让浏览器(比如Firefox和Chrome)来管理DNS,不是一个好主意。

说到这儿,Firefox之前也做过类似的事情:

Firefox不知道什么时候,开始自己搞了一套独立的证书信任系统,和系统内置的证书系统是独立的(至少在Android上是这样的)。

比如,我要使用charles抓https的包,需要将charles的tls证书倒入到Andorid系统的证书库中,但是回头一看,Firefox还是不认,所以还得自己将证书添加到Firefox的证书库中。

另外一个更加智障的问题是,我在charles抓包结束后,需要删除这个证书,我可以在Android系统的证书库中删除掉。但是对于添加到Firefox中的那一份,我是没有办法删除的,只能卸载并重新安装Firefox

阅读更多

cherry-pick到底应该怎么翻译?

git当中的cherry-pick命令,翻译成中文叫什么名字呢? GitLab给出了答案

// gitlab.po
msgid “ChangeTypeAction|Cherry-pick”
msgstr “优选”

这个是不是听起来怪怪的? cherry-pick的中文意思是“择优挑选”,比如

They seem to cherry-pick the loss leaders and discount items in the supermarkets and discount stores, relying on smaller retailers for everything else. 因为他们会选择超市和打折店里的特价商品和和打折商品,而其他所有的东西都是从小商贩那里获得。

当然,也要注意的是,写作论文的时候,只挑选那些好的数据写在文章中,这种行为也可以叫cherry-pick,比如:

Be careful not to ‘cherry-pick‘ data: don’t choose just what you like, or what supports your objective. 注意别“优选”数据:别选择一些只是您喜欢的,或者支持您的目标的。

所以从常用语义上来讲,优选这个翻译也不算太差。 但由于“优选”这个词在中国被用烂了,多用在电商等领域,如果我们开发的时候来一句“请将aaa提交优选到B分支”,完全不能理解啊。 个人觉得,翻译成“拾取”会比较好,比如“请将aaa提交拾取到B分支”就顺口好多。


另外,也可以看看GitLab对其他git术语的翻译: Revert 还原,Issue 议题等。

阅读更多

PHP/Composer是如何加载一个类的

PHP/composer开发中,我们只需要require 'vendor/autoload.php',然后就可以直接使用各种类了。那么这些类是如何加载的呢?其中有没有什么可以优化的点呢?

概览

PHP/composer下,类的加载主要到如下部分(还没有包括各个部分的初始化逻辑):

1
2
3
4
5
6
7
8
PHP中zend_lookup_class_ex
|-> EG(class_table)
|-> spl_autoload_call
|-> ComposerAutoloadClassLoader::loadClass
|-> findFile
|-> class map lookup
|-> PSR-4 lookup
|-> PSR-0 lookup

PHP的类加载

首先,PHP在运行的时候,需要一个类,是通过zend_lookup_class_ex来找到这个类的相关信息的。

zend_lookup_class_ex查找类的主要逻辑如下(假设类名字放到变量lc_name中):

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
ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *key, int use_autoload) /* {{{ */
{
// 1. 类名字转化为小写
if (ZSTR_VAL(name)[0] == '') {
lc_name = zend_string_alloc(ZSTR_LEN(name) - 1, 0);
zend_str_tolower_copy(ZSTR_VAL(lc_name), ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1);
} else {
lc_name = zend_string_tolower(name);
}

// 2. 直接在class_table中查找
ce = zend_hash_find_ptr(EG(class_table), lc_name);
if (ce) {
if (!key) {
zend_string_release(lc_name);
}
return ce;
}
// 3. 如果没有autoload_func,则注册默认的__autoload
if (!EG(autoload_func)) {
zend_function *func = zend_hash_str_find_ptr(EG(function_table), ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1);
if (func) {
EG(autoload_func) = func;
} else {
if (!key) {
zend_string_release(lc_name);
}
return NULL;
}

}

// 4. 加载ACLASS的过程中,又加载ACLASS,递归加载,直接找不到类
if (zend_hash_add_empty_element(EG(in_autoload), lc_name) == NULL) {
if (!key) {
zend_string_release(lc_name);
}
return NULL;
}

// 5. 调用autoload_func
ZVAL_STR_COPY(&fcall_info.function_name, EG(autoload_func)->common.function_name);
fcall_info.symbol_table = NULL;

zend_exception_save();
if ((zend_call_function(&fcall_info, &fcall_cache) == SUCCESS) && !EG(exception)) {
ce = zend_hash_find_ptr(EG(class_table), lc_name);
}
zend_exception_restore();

if (!key) {
zend_string_release(lc_name);
}
return ce;
}
  1. lc_name转化成小写(这说明PHP中类名字不区分大小写)
  2. 然后在EG(class_table)找,如果找到,直接返回(我们自己注册的类,扩展注册的类都是这样找到的)
  3. 然后查看EG(autoload_func),如果没有则将__autoload注册上(值得注意的是,如果注册了EG(autoload_func),则不会走__autoload)
  4. 通过EG(in_autoload)判断是否递归加载了(EG(in_autoload)是一个栈,记载了那些类正在被autoload加载)
  5. 然后调用EG(autoload_func),并返回类信息

SPL扩展注册

阅读更多

Docker for Mac with Kubernetes初次尝试

首先,2018-01-09日Docker公司宣布了Docker for Mac支持Kubernetes。 后来陆续尝试了几次,今天终于成功了,所以记录下。

安装Docker for Mac with Kubernetes

首先,安装Docker for Mac Edge版本:

brew cask install docker-edge

设置代理(我用的是https://github.com/netheril96/MEOW): 开启Kubernetes:   等待安装: OK了: kubectl version也能看到客户端版本和服务端版本了:

$ kubectl version
Client Version: version.Info{Major:”1”, Minor:”9”, GitVersion:”v1.9.2”, GitCommit:”5fa2db2bd46ac79e5e00a4e6ed24191080aa463b”, GitTreeState:”clean”, BuildDate:”2018-01-18T10:09:24Z”, GoVersion:”go1.9.2”, Compiler:”gc”, Platform:”darwin/amd64”}
Server Version: version.Info{Major:”1”, Minor:”9”, GitVersion:”v1.9.2”, GitCommit:”5fa2db2bd46ac79e5e00a4e6ed24191080aa463b”, GitTreeState:”clean”, BuildDate:”2018-01-18T09:42:01Z”, GoVersion:”go1.9.2”, Compiler:”gc”, Platform:”linux/amd64”}

创建kubernetes-dashboard 服务

$ kubectl create -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml
secret “kubernetes-dashboard-certs” created
serviceaccount “kubernetes-dashboard” created
role “kubernetes-dashboard-minimal” created
rolebinding “kubernetes-dashboard-minimal” created
deployment “kubernetes-dashboard” created
service “kubernetes-dashboard” created

等一会就可以看到创建好了:

$ kubectl get pods –namespace kube-system
NAME READY STATUS RESTARTS AGE
etcd-docker-for-desktop 1/1 Running 0 6m
kube-apiserver-docker-for-desktop 1/1 Running 2 6m
kube-controller-manager-docker-for-desktop 1/1 Running 0 6m
kube-dns-6f4fd4bdf-zl9dh 3/3 Running 0 7m
kube-proxy-xsx8n 1/1 Running 0 7m
kube-scheduler-docker-for-desktop 1/1 Running 0 5m
kubernetes-dashboard-5bd6f767c7-6szsl 1/1 Running 0 1m
$ kubectl get deployments –namespace kube-system
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
kube-dns 1 1 1 1 7m
kubernetes-dashboard 1 1 1 1 1m

阅读更多

如何在macOS上运行GTK 3(hello, world)

首先,安装 Homebrew

然后,brew install gtk+3 随后,查阅GTK的官方文档,写Hello, world:

hello.c
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
#include <gtk/gtk.h>

static void
activate (GtkApplication* app,
gpointer user_data)
{
GtkWidget *window;

window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
gtk_widget_show_all (window);
}

int
main (int argc,
char **argv)
{
GtkApplication *app;
int status;

app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);

return status;
}

然后编译:

1
gcc `pkg-config --cflags gtk+-3.0` -o hello hello.c `pkg-config --libs gtk+-3.0`

当前目录下就有了hello二进制可执行文件,执行即可:

阅读更多

Use pty as ansible connection

Well, sometimes, we can only use pty to access machines. For example, Jump Server only allowed use ssh pty to type command, get the result. But, how can I deploy application via ansible?


There are two good news:

  1. pexpect can interactive with the ssh session.
  2. ansible can use custom connection plugin.

Let’s try it

Let’s start at directory ansible-pty Firstly, we should create a connection plugin. Put those code to ansible-pty/plugins/pty.:

import base64
import re

import pexpect
from ansible.plugins.connection import ConnectionBase
from ansible.utils.display import Display

display = Display()

class Connection(ConnectionBase):
transport = ‘pty’
_mark = “=” * 10

阅读更多

[评论]systemd @ Facebook — a year later[All Systems Go! 2017]

今天看了All Systems Go! 2017上,systemd @ Facebook — a year later这个talk。记录下自己的感想。

首先,Facebook软件更新还是比较及时的,CentOS 7 和 systemd 都上了:

可怜我司还在Ubuntu 14.04上 另外,很多基础组件都是和上游有良好的沟通的:

长远来看,紧跟上游对公司的技术实力、技术影响力都有好处。当然,短期来看,我的系统工作的很好,不跟进上游没毛病啊。国内,大部分是后者吧……

当然,大公司都有自己的repo:

Facebook居然都已经接入了Meson,很让我吃惊。

资源管理

阅读更多

如何退出无响应的 SSH 连接

经常出现ssh连接由于网络问题,“卡住”了。不能进行任何操作,也不能退出。 ssh文档里面也有写通过~.来断开ssh连接:

$ man ssh

ESCAPE CHARACTERS

 The supported escapes (assuming the default \`~') are:

 ~.      Disconnect.

 ~?      Display a list of escape characters.

但是,实际使用过程中发现,按了没有反应。 后来看了其他人的做法,发现两个技巧:

  1. ssh转义字符,只有在新行生效。所以最保险的按键方式是:回车 -> Shift+` -> .
  2. 由于输入两个~会导致ssh直接发送~。比如我们按~``~``~``. 会关闭第二层ssh,而不是当前失去响应的ssh会话。

所以为了保险起见,我的操作是这样子的: 回车``~``?,直到出现ssh的转义字符帮助(没有出现就继续按回车``~``? 然后按 ~``. 退出ssh


~``~``~``. 会关闭第二层ssh,对吗?

  1. ~``~是给第一层ssh会话发送~字符
  2. ~``~``~是给第二层ssh会话发送~字符
  3. ~``~``~``.是给第二层ssh会话发送~``.字符,即关闭第二层ssh会话

阅读更多

如何调试iptables [CentOS 7]

首先,来一张非常有用的图:

基础知识

iptables可以jump到TRACE目标,开启_包追踪_(packet tracing)选项。 iptables有一个raw表,基本上是iptables最先处理包的地方。

开始调试

在最入口的位置给符合条件的包开启包追踪,比如对所有进入的icmp包:

1
iptables -t raw -I PREROUTING -p icmp -j TRACE

有的时候,还需要加载需要的模块(CentOS 7下):

1
modprobe nf_log_ipv4

然后你就可以在/var/log/messages日志中看到包追踪信息了。

阅读更多