善意提醒

如果您打开本站很慢,布局排版混乱,并且看不到图片,那么可能是因为您还没有掌握用科学的方法上网的本领。

2017-05-19

美团那个 HR,不是歧视,只是蠢

最近有个「美团招聘」事件在网上发酵。孤陋寡闻的我今天才知道。众说纷纭,我也来发表一下意见。

------------------------------------------分隔线------------------------------------------

这位据说来自美团的 HR 抛出了一个「五不要」的招聘原则,被人发在了网上:
  1. 不要简历丑的;
  2. 不要研究生博士生;
  3. 不要开大众的;
  4. 不要信中医的;
  5. 不要黄泛区及东北人士。
美团说已经把这个人辞退了。简单关注了一下,不少评论意见很简单:要不说这人说得有道理,要不说这人脑残搞歧视。互联网信息快餐时代,简单的意见的确比较容易表述,也比较容易挑口水,所以我觉得我还是写个 Blog 说一下自己的意见。

HR 的招聘原则,脑子能想,但不能说或写出来。一旦别人知道了,那就是「歧视」。我觉得这个没啥大问题,不过我不关注这个层面。如果原则正确合理,即使是写了出来,我也觉得没啥问题。但是这「五不要」到底有没有道理,我觉得一定要分开来一条一条地看。如果你要么全盘接受,要么全盘否定,那么有可能脑子不太好使,请去医院挂号。

不要简历丑的
「丑」这个词,很主观。所以这个 HR 这样写出来,脑子不会太好使。主观的形容词你只能自己用,给别人讲了也无意义。你心中的「丑」跟别人心中的「丑」肯定不是同一回事。
那么,这一条有没有道理呢?当然有道理。招聘的考察因素当然可以包括被招聘者的审美和美术功底,包括排版能力。就算不是相关岗位要求的技能,但「审美观」作为对一个人综合素质的要求是并没有什么问题的。这一条,道理上没问题,只是不能写出来,因为写了也没意义。

不要研究生博士生
首先这一条写得有点问题,如果写成「不要研究生及其以上学历者」或「只要本科(含)以下学历者」可能更合适。不过我也不想抠这种文字上的细节。单看这一条表述的意思,一点问题也没有。招聘条件中对于学历的要求,这个能有什么问题?也许其他人觉得 HR 是歧视高学历者,但也可能是岗位不需要,或简单的「雇不起」。你要是看出来里面有「歧视」,那其实只说明你心里才有「歧视」。

不要开大众的
我初看到这一条时感觉简直是「这人神经病」。「开大众的」怎么着你了?撞你了还是蹭你车了?上网一搜才知道所谓「神车」是啥意思。
那么我们现在知道 HR 是什么意思了。不过,这一条问题很大。HR 不想要具备某种价值观的人,这个很容易理解。但是开个大众车就一定具有某种价值观吗?可以举出反例的情况太多了。后面的分析会告诉我们,这个 HR 一定不是一个好的理科生,他的逻辑学连基础都没有。

不要信中医的
这一条没有问题。信中医的会有什么价值观,我们还是很清楚的。HR 不想要有这种价值观的人,那是他的自由,一点问题也没有。

不要黄泛区及东北人士
看到这一条我又糊涂了。什么是「黄泛区」?黄皮肤泛滥?三藩还是雪梨?查了一下才知道说的是河南那片儿。不过总之「地图炮」仨字跑不掉。
这一题也跟第三条一样,问题很大。你一个 HR 招个白领而已,要考察的无非主要就是能力和性格。这两样哪个跟地区有必然的关系?

------------------------------------------分隔线------------------------------------------

好了,现在我们来看看这位 HR 犯了什么毛病?
他的问题不是「歧视」。他是脑残,是逻辑没学好。他不知道什么是充分条件,什么是必要条件。我估计他中学时平面几何的分数一定很低。

招人的时候,你若是 HR,一定会提一堆的条件。这些条件里面,有一些是你要求应聘者必须满足的,不具备的话就别来了,来了也没用。这种叫做「必要条件」:若要应聘我司,必须如何如何。通常这类条件都会是「白名单」形式,符合这类条件,你只是有了资格,但并不保证一定会被聘用,也不保证不会被其它条件给刷掉。
还有一类条件,如果你符合了,你就别来了,不会考虑你的。排除性的,也就是上面提到的「XX 不要」。这类条件,叫做「充分条件」:你只要如何如何,我就一定不要你。注意,这里一定是「黑名单」性质。除了骗子公司,没有 HR 会说「只要你符合 XX 条件,我就一定要你」。全世界都没有,不然这家公司早倒闭了。

黑名单有效的前提,是该条件可以充分覆盖 HR 希望避免的区域。换句话说,你排除掉的,一定是你不想要的。你的条件和你要的结果,中间要有逻辑关联性。举个例子:你不喜欢染头发的员工,你就列一条「不得染发」。你要列一条「必须是黑发」,那就有问题了。因为你这个条件涉及到了那些天然非黑发者,却并没有排除掉「染成黑发」者。结果就是,从正反两个方面,你想要的效果都没有达到。我们就会说你这个条件订得有点脑残。
美团这个 HR 的第三条和第五条就是如此。开大众的也许有价值观不符的,但也有跟价值观无关的。价值观不符合你要求的人,自然也有开其它品牌车的。「黄泛区」和东北人士可能有很多人你不喜欢,但这么多人你能确定所有人都不对你胃口?其它地区的人就都对你胃口?
所以啊,列出了这两条惹口水的条件,却既不能完全排除你不想要的人,还可能「误伤」本来符合你条件的人。站在公司立场看来,这种HR完全就是在瞎鸡巴搞,本职工作显然不合格,被辞退掉完全是活该。站在我们旁观者的立场,歧视归歧视,要是歧视得有道理,比如「不招共产党员」,我们都会点头称是。你要是说「不招关注过郭文贵者」,我们都会骂你脑残欠抽。

少年们,无论将来干什么工作,请先学好逻辑!

2017-05-18

当 Win7 Windows Update 遭遇 0x80073712

Windows Update 一直以来都以会遇到各种 Error 代码而闻名。今天又遇到一例,记录一下。

起因是 WannaCry。我有一堆各种 OS 版本的虚拟机,其中一台 Windows7 SP1 x86 使用得很不频繁,昨天打开一看,上次 Windows Update 已经是 2016 年 09 月的事情了。虽然 NAT 挡在宿主机后面其实不会有啥问题,但是按照我的习惯,下班前还是让它去打了补丁。曾经在上一家公司的遭遇一直在提醒我:有人的虚拟机中了震荡波,然后不知情的时候被做了快照,于是每隔一段时间测试机房就会忙活一阵子(测试机为了测试程序的补丁管理功能是不打补丁的)。

今天早上一来,红色儿的,4 个成功 2 个失败。我也没太放在心上,公司网络有时候会断,说不定是下载失败。再来了一次,在下载到 11% 的时候又失败了。我把 VPN 开起来(曾经有不开 VPN 打补丁会下载失败的经历),上了个厕所回来,然而这次还是失败,我看了下 ErrorCode:80073712。每次都是这个。好吧,开始 Google

官方网页 推荐的做法大概是这样的:对于 Win7 而言,首先请先尝试用 SFC 修复一下。如果还不行,那么请下载工具 System Update Readiness tool 进行修复。

SFC 这货其实没啥鸟用,反正我每次用都没啥好结果。这次也不例外,扫描到 44% 时告诉我:虽然我们发现有错,但是无法修复,你去看日志吧。

试了下再次 Windows Update,还是报 0x80073712。好吧,只好试试看那个修复工具了。下载下来两百多 MB,安装了老半天。再次 Windows Update,这回进度开始超过 11% 了,我长舒一口气。终于 OK 了。

顺便瞄了一眼同页面上对 WinXP 的问题处理建议,仅仅提到 SFC。看来真的是该放弃这破烂了。

2017-03-29

对 VS2013 下 C++11 的精准转发与通用引用的一点研究

在 C++11 中,允许用以下方式编写模板函数:
#include <iostream>
#include <string>
class A
{
public:
    template <typename T>
    void foo(T&& t)
    {
        T _t = std::forward<T>(t);
    }
};
int main()
{
    std::string s1 = "test";
    A a;
    a.foo(s1);
    std::cout << "1:" << s1 << std::endl;
    a.foo(std::move(s1));
    std::cout << "2:" << s1 << std::endl;
    a.foo("ok");
}
以上代码在 Visual Studio 2013 上测试通过。输出是:
1:test
2:
可以看到,模板函数 A.foo 只有一个声明和实现,但既可以接受左值,也可以接受右值。并且当 S1 被当作右值引用传入的时候,其值是确确实实被「丢弃」了。这就是所谓的精准转发(把 T 的类型准确地传递到使用者),以及通用引用(用一个 T&& 就可以表示所有的情况)。对于要写库的程序员来说,可谓是一个福音了。
然而,对于模板类,下面的写法看上去很好,但是编译会报错的:
template <typename T>
class A
{
    T _t;
    public:
    void foo(T&& t)
    {
        _t = std::forward<T>(t);
    }
};
int main()
{
    std::string s1 = "test";
    A<std::string> a;
    a.foo(s1);
    std::cout << "1:" << s1 << std::endl;
    a.foo(std::move(s1));
    std::cout << "2:" << s1 << std::endl;
    a.foo("ok");
}
编译后报错:
error C2664: “void A<std::string>::foo(T&&)”: 无法将参数 1 从“std::string”转换为“std::string&&”
with
[
    T=std::string
]
无法将左值绑定到右值引用
这大概是因为,T 的类型在 A<std::string> 的时候就确定了,因此编译器无法进行更多的类型推导。
那么怎么办呢?其实也不难,foo  函数像下面这样写就可以了:
template <typename T>
class A
{
    T _t;
    public:
    template <typename X>
    void foo(X&& t)
    {
        _t = std::forward<X>(t);
    }
};
在函数模板中用一个新类型就可以了。如果 T 跟 X 不一致,那么编译器反正会检查出来的。不用担心。
还有一个问题:有的时候我们会把 foo 的实现写在 class 的外面。那这个时候怎么办呢?
我本来想抛题目给大家去做。不过都到最后了卖关子也没什么意思,还是直说吧:
template <typename T>
class A
{
    T _t;
    public:
    template <typename X>
    void foo(X&& t);
};
template <typename T>
template <typename X>
void A<T>::foo(X&& t)
{
    _t = std::forward<X>(t);
}
标红的两行,只能是这个顺序。类的模板定义在上面,函数的模板定义在下面。颠倒过来,报错。要写在一行也可以,先左后右就行。但是要想把尖括号打开强行并成一句,报错。

2017-03-06

作死的 TerminateThread

有一天早上,我收到了一个来自同事的 Dump 文件。打开一调试,报错信息如下:
0x77B16BB9 (ntdll.dll) (XXX.dmp 中)处有未经处理的异常:  0xC0000005:  读取位置 0x1C7695E8 时发生访问冲突。
我一般首先会去看 CallStack,因为 PDB 都有,所以得到的情况很清晰:
ntdll.dll!RtlpWakeByAddress()
ntdll.dll!RtlpUnWaitCriticalSection()
ntdll.dll!_RtlLeaveCriticalSection@4()
XXX.dll!RecMutex::unlock()
XXX.dll!LockT<RecMutex>::~LockT<RecMutex>()
……
这个调用栈看得我有点糊涂。这个 RecMutex 来自 ICE 的最新版本,我从 1.3.0 版就开始用 ICE,用到现在的 3.6.3。这种基础的代码我有信心不会有问题,也不会用出问题来。何况 RecMutex 只是对 CRITICAL_SECTION 的一个简单封装,代码并不多,也并不复杂。我这次在自己项目代码中用之前恰好看过一遍,也认为这里面不会有什么问题。
具体到 RecMutex::unlock(),其实也就是干了这个事情:
void RecMutex::unlock() const
{
if (--_count == 0)
{
LeaveCriticalSection(&_mutex);
}
}
这个问题并不是每次都能重现。于是可以肯定跟「多线程」有关系。很显然,LeaveCriticalSection() 这种级别的 Win32 API 调用绝对不会存在着会导致 Crash 的 Bug,否则微软早就死翘翘了,所以问题肯定出在那个 _mutex 上。然而,既然 if 语句能进来,那么 this 指针一般来说是对的。因为是 Release 版本,优化导致了 LocalVar 的显示不是那么可靠,不过跟踪 ESP 的情况最终验证了我的猜测是对的——至少到这个时候,栈还没有坏掉。

这个 _mutex 就是一个 CRITICAL_SECTION。那么我就很头大了。多线程出问题,一般是临界区被搞坏了。然而 CRITICAL_SECTION 本身就是用来保护临界区的。它什么情况下会被搞坏掉呢?

接下来的汇编代码,Debug 起来就很有些难度了。我只能大致确认,在 _RtlLeaveCriticalSection()中,_mutex 还没有坏掉。但在 RtlpWakeByAddress() 中就肯定坏了。至于 RtlpUnWaitCriticalSection() 的情况就不是很清楚了。

到此时,三个小时已经过去了。正面 Debug 似乎走入了泥沼,现在只剩下「程序不会闹鬼,一定要查个水落石出」的精神还在支撑着我。起来上了个厕所,我换了条思路:问 Google。
Google 果然厉害,哪怕只是简单的 关键词搜索,第一条搜素结果就 直指要害

其实第二条搜素结果也很正确,不过 Reddit 毕竟还是没有 StackOverflow 专业。这个问题所描述的现象,跟我遇到的是一模一样。而且给我 Dump 文件的那个同事用的 OS 的确是 Win10
。我最感激的是这哥们问题的开头一段几乎直接就回答了我的疑惑:TerminateThread。该死的!肯定有人在做这种事情。

我当然是知道的。TerminateThread 会造成各种各样千奇百怪的问题。正常的应用层操作的确不太可能造成 CRITICAL_SECTION 本身被搞坏(除了把栈写坏),然而 TerminateThread 这种东西是一定会干得出来的。大多数程序员都知道 TerminateThread 不靠谱,所以都不会去用,这个已经几乎成为常识了。于是有一个坑爹的后果就是:一旦有人真的这样干了,正常人全部懵圈,因为没人想到会是这个原因。多谢这哥们把这种问题给问了出来,否则我可能还要花更多的时间在它上面。

接下来的事情就很简单,找出谁在用 TerminateThread。其实也没那么简单,因为我找了一圈,都没发现相关的代码。我都有点开始怀疑自己是不是碰到了别的情况。这个时候我突然想到:会不会是别人的库里面有问题呢?

我当然用到了一些开源第三方库,不过我相信它们不会犯这种错误。它们就算要用到 TerminateThread,也肯定是作为程序退出之前的强制性措施来使用,正常运行情况下是绝对不会这样用的。

相比较而言,我比较不信任其它组同事写出来的「中间件」。一问之下,那个写「中间件」的同事,也用了另外一个组提供给他的一些开发库。再追着问,果然,那个开发库里面对线程的封装,在退出「超时」的情况下调用了 TerminateThread。

至此,水落石出了。这个 Dump 文件的确就是在调用了那个中间件的关闭接口之后不远的地方产生的,并且产生之前确实很明显地出现了「超时」的现象——界面卡住了约 5 秒没有动。可想而知,由于停线程超时,于是就去调用了 TerminateThread。那个开发库的编写者大概以为,这样就可以让程序继续跑下去。然而这只是他的一厢情愿。用过 TerminateThread 之后,系统的行为就会是 undefined 的了。现在可能不会 Hang,但是接下来会出现各种莫名其妙的错误,到那个时候必然将会更难调试。这种「保证线程可以被停掉」的代码我宁可不要。浪费时间,不就是在浪费生命么?

在最后,再次警告大家:珍爱生命,远离 TerminateThread。

2017-02-03

折腾 boost::python 的一些收获

最近从事了一些通过 boost 在 C++ 中调用 Python 脚本的工作。折腾下来有一些收获,记录一下,也许也可以帮到有些人。

一、关于万能变量类型


对于习惯了 Python 的 C++ 程序员而言,boost::python::object 这个东西是一个巨大的诱惑。它让你几乎可以像在 Python 里面那样使用弱类型的变量,同时还支持数组和字典之类的复杂变量类型,并且还支持嵌套。这简直就是一个万能变量类型,有了它,常见的需求几乎都可以满足了。

而且它还快,还容易用。它其实是 PyObject* 的一个封装,也就是说 PyObject* 其实功能也一样,但是没它容易使用。JsonCPP 里面的 Json::Value 也可以「万能」,但性能与 boost::python::object 相差颇多。这真的是一个巨大的诱惑。

但是在这里,我要给大多数 C++ 程序员泼一盆冷水。在单线程下,这个梦想可能真的是事实:但是在多线程下,boost::python::object 就是一个

boost::python::object 为什么快?因为它基于 PyObject*,具有引用计数,所以赋值才飞快,浅拷贝嘛。但是引用计数的问题就是线程不安全。

当然,光是引用计数本身不会导致线程安全性问题,导致问题的是引用计数带来的临界区对象引用问题,而归根结底,是 Python C API 的「并发问题不归我管」的思路。boost::python 的封装机制使得对象引用不好控制,也不太可见。想法是好的:使用者不需要关心这些。但现实就很无奈了。

所以,尽管很不甘心,关于万能变量类型的实现,我还是老老实实地用回了 Json::Value。

二、类型转换与判断


要从 boost::python::object 转换成 C/C++ 原生变量类型,一般用 boost::python::extract<T>。转出来的对象调 check() 就可以确定是不是正确的类型。转 boost::python::list 或 boost::python::dict 也是一样。

有一点需要特别注意的是:用 boost::python::extract<bool> 的时候,很可能得不到你预想的结果。你会发现,int 也被转成 bool 了(check() 返回 true),反过来也一样。这个不是 Bug,是 boost::python 故意这样搞的。BOOST_PYTHON_BOOL_INT_STRICT 宏可以解决这个问题(必须改动 boost::python 源代码并重新编译,因为相关代码在 cpp 里面不在头文件里面),它使得 int 和 bool 将被严格区分。

但是 boost::python 之所以把 int 和 bool 混起来用也不是没有道理的。这样使得 MFC 里面的那些 BOOL(不是 bool)类型的函数形参(和返回值)可以直通 Python,封装起控件来尤其方便。如果你设了 BOOST_PYTHON_BOOL_INT_STRICT,就不能这样干了,必须显式转换。左是一刀,右也是一刀。你们自己掂量吧。

反正我是没有去加 BOOST_PYTHON_BOOL_INT_STRICT,而是自己通过 _stricmp(value.ptr()->ob_type->tp_name, "bool") 搞定的。

三、清空 boost::python::list


用惯 STL 刚开始用 boost::python 的人可能会头大——怎么 dict 有 clear() 但 list 没有?
答案很简单,因为 Python C API 没提供,所以 boost::python 就没有。

说到底,boost::python 就是对 Python C API 的一个封装而已。你如果去看 boost::python 的源代码,甚至会发现里面不少的「成员函数」其实是跑去执行了一句 Python 脚本。不了解细节的 C++ 程序员很容易在这种地方栽跟头,所以我觉得 boost::python 绝对不会是一个终极形态。

要想清空数组,并不是完全没有办法。我找到的一个办法是 boost::python::delitem(list, boost::python::slice())。并发调用时记得用本文最后一节的办法加锁。但是我是真的不建议在多线程环境下用 boost::python,太多坑了。如果实在要用,在完成了 Python 脚本调用,把数据转换好之后,就赶紧离开 boost::python 区域吧。

四、boost::python::object 深拷贝


boost::python::object 默认的赋值操作都是作浅拷贝,极快。然而,有的时候需要深拷贝怎么办呢?

简单数据类型直接 extract 出来就是深拷贝(传值)了。会有问题的仅仅是复杂数据结构,具体地说,list 和 dict。

dict 又是有提供 copy(),理由还是——Python 里面的 dict 有 copy(),而 list 就没有。我尝试过最简单的办法,就是把一个 list 放到一个 dict 里面去 copy() 完再拿出来用。这样肯定可以达到目的。至于有没有更好的办法呢?我反正是自那之后就弃坑了,你们去研究吧。

五、多线程并发加锁


C++ 调 Python 的时候的加锁是一个不小的话题。不过这方面中文资料也算不少,有兴趣可以去搜来研究。我这里就简单地说一下跟 boost::python 相关的部分。

加锁是用 PyGILState_STATE,像这样:
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
……    // 调用Python脚本
PyGILState_Release(gstate);
这种例子网上很多,就不细说了。
关键在于,我前面也提到了,boost::python 里面很多看起来是 object 的成员函数的东西,其实都是对 Python 脚本的调用,所以都得加锁。

事实上,只要你用到了 boost::python 的地方,都得加锁。不管是 module 和 call 这种看起来就跟「调用」二字相关的,还是在对 boost::python::object 作数据处理,看起来人畜无害的,都得加锁,无论读 / 写,否则你就等着 Crash 吧,特别是服务端程序。

这也就是我一再警告避免在多线程下使用 boost::python 的原因。当然,我这边是不得不用,只能小心翼翼,如履薄冰,然后尽量控制不要让菜鸟程序员去写这种代码。由此可见,隐藏了实现细节并非全是好事,也并非全是对新手有益。

2016-12-04

记一次恶劣的淘宝购物经历

我现在已经基本不用淘宝了,不过老婆还是喜欢在上面逛,也因此有了这次很恶劣的购物经历。
东西是一个小孩子用的书包。很便宜,29 元 RMB。我其实一直跟老婆在说「便宜没好货」,但是便宜的诱惑的确很大。买到手的过程很顺利,2016 年 11 月 05 日下单,11 月 07 日就物流签收。
东西是帮别人买的,所以一开始没有怎么放在心上。过了几天,老婆问对方书包怎么样,别人明说:「质量不好,第一天背带就开线了。」这怎么行?于是赶紧联系卖家要退货。
看到图片我其实并不奇怪。29 块钱的东西质量能好到哪里去?卖家还说去修,然而这种质量我觉得还是直接退掉麻烦比较少。在我看来其实当初就不应该买这个东西。卖家倒也爽快,因为是质量问题,图片显示得也很清楚,退就退吧。


到这里都还好,不过两个麻烦事情已经露出端倪了:
  1. 卖家要求买家「包装好」,这个本身不算不正常,但我知道会有后招。
  2. 卖家言明退货只负担 10 元运费。
这两件事情,注定会导致买家的不快。
「脏了就拒收」,这种话大概也只有淘宝卖家讲得出来。如果你这个产品有严重的质量问题,一用就碎成渣了,那是不是就不能退货了呢?
事实上,卖家想要让商品能够二次销售,对于买家而言这是个可以理解的事情。但是用这种方式讲出来,买家会有什么感受大家都很清楚。之前只是觉得你东西不好,现在就觉得你人不好了。
对于退货的时候产生的运费问题,淘宝的政策是「建议卖家和买家协商解决」。也许有的人觉得这很合理,毕竟每个个案的情况都各不相同嘛。然而,我对淘宝最大的厌恶之处,就在于这个「在淘宝上买点什么都要开『汪汪』协商」。明知退货运费这种事情卖家和买家是一定会有矛盾,还要他们「协商解决」,其实就是自己不想解决嘛。
按照淘宝的说法,以及一般人的常识理解,因为质量问题导致的退货,运费肯定是应该由卖家负担的。我也不太清楚这个卖家理直气壮的原因,也许是「业界潜规则」,也许是「小本经营」。具体原因也许都可以商量讨论,但是买家会有什么感受,大家仍然会很清楚。


然后高潮就来了,卖家开始耍流氓了。自从淘宝上的退货流程走完之后,直接不理睬买家。也不拖黑,也不对骂,就是不出声。这个时候淘宝的另一个坑跳出来了。
对不起,你不能投诉卖家,因为已经过了时间。
淘宝规定,「交易成功」15 天以后,就不能再投诉卖家了。我也搞不清楚这个 15 天到底合理不合理,但是显然,卖家只要把时间拖过这 15 天,谁都拿它没办法了。偏偏我和我太太之前都不知道这个「15 天」的事情。
而且,我太太之前刚收到货时已经手快把好评先给了。

事情呢,我大概已经说完了。淘宝既然不提供渠道,我个人要救济自然是很困难。除了去追加一个评论,上传几张图片,以及写这篇部落格,我还能做的最多是去工商局闹腾。这方面我完全不抱什么希望。
至于这个淘宝卖家呢?情感上我当然希望它倒闭关张大吉。不过,淘宝上也有好卖家,这个也是事实。林子大了什么鸟都有,不可能人人都是垃圾。我自然是不会忍气吞声。该做的事情,我已经做了,这也是为什么我不会对图片打码的原因。该付的代价,我们也已经付了。至于剩下的事情,就让它顺其自然吧。15 块钱差不多够买一盒感冒药的。

2016-09-13

自定义域名又回来啦

本来以为,自定义域名以后就跟我的 Blog 没什么关系了。但今天想起来,GoDaddy 不是 west263。共产党可以不准国内的 ISP 提供 URL 转发功能,但毕竟还奈何不了 GoDaddy。自定义域名的事情,用 URL 转发就可以解决嘛。

于是,本来的自定义域名,从 CNAME + VirtualHost 变成了 URL Forward。虽然据说在搜索引擎的打分上会有「惩罚」,但这些不是我关心的。有总比没有好。而且,URL Forward 可以把 HTTP 的流量导到 HTTPS 上。这对于目前这个全局 SSL 的时代本来就是必然的趋势。这样一来,反倒是比之前的效果还要好了。

反正都要翻墙,对吧?这年头干啥不得翻墙?

2016-08-24

与自定义域名说再见了

很长一段时间以内,我都把我托管在 Blogger 上的这个 blog,绑定上了自定义域名 blog.superliufa.com。这样做的好处很明显——可以实现免翻墙。通过非官方的 GHS,即使用 HTTP 也不会被 GFW 阻挡。
只可惜我上一个 blog「歇业」太久,所以即使绑上了自定义域名,也已经不能为我带来多少「老」的流量。并且,随着时间的推移,自定义域名的缺点越来越明显:用了自定义域名,就不能享受 Google 提供的 HTTPS 待遇。
而所谓的「免翻墙」好处,对于有一些来自 Blogger / Google 的公用资源还是无能为力。比如有的读者就反映,说页面要等好久才能打开,而且布局有问题。这些其实都是 GFW 捣的鬼。

我现在也不想去跟 GFW 玩「捉猫猫」的游戏了。反正不翻墙的人我一不指望二也不希望他们看到我的 blog,索性就扔掉自定义域名,用 blogspot.com 的域名直接来访问我的托管 blog 吧。愿意装睡的,就算你扇它耳光也不会醒,愿意当个人的,你拿枪指着他还是不会征服他的心。

那么,就让一切都回归它的本来面目吧。

2015-12-13

最近看过的书,简评几则


  • 《战争史》(基根):没有想象中的宏大,是更为学术性的书。主要针对战争本身进行研究,阅读起来略微有一些无趣。作者跟克劳塞维茨算是杠上了。
  • 《毛毛星球》(约翰.斯卡尔齐):一本小品式的「科幻」。介绍上说是硬科幻,但里面的法律内容比科学和幻想加起来还要多。就像很多读者说的那样,作者的确「很会讲故事」,是很「温情」的故事,我喜欢。只可惜有「毛毛」死去,看到最后虽然正义感得到了满足,但还是轻松不起来。
  • 《锁定目标》(汤姆.克兰西):一开篇就是火爆的动作场面,后面也是高潮不断。人基本上还是那班人,但比《虎牙》刺激多了。一本不错的克兰西作品。
  • 《悖论:破解科学史上最复杂的 9 大谜团》(吉姆.艾尔.哈利利):还算不错的入门级科普,看过之后应该能对物理学上的一些重难点有所了解,而且又不至于被吓倒。留给儿子以后看吧。
  • 《羊毛战记》(休.豪伊):不错的反乌托邦科幻,和 Fallout 系列的感觉很接近。我觉得用Fallout1 / 2 的引擎很容易就能根据这书的剧情改编出一个游戏来。144 层的 Vault,想想也很大。不过从后期透露的信息看来,虽然深度很大,但每层的面积并不是很大。作者用了一种舞台剧一样的写法,情节冲突也是一波一波地。这种写法我不是太喜欢,不过还是很期待下一部的续集《尘埃记》。
  • 《虎牙》(汤姆.克兰西):比起《锁定目标》来,这本的节奏就太过平稳了。个人认为唯一称得上动作戏的,就只有 Mall 里面那场枪战而已。不过这本书主要是为了交待「校园」的来历,大概是过渡性的作品吧。
  • 《虚无的十字架》(东野圭吾):本以为是本格派的作品,结果读完却几乎以为是松本清张写的。我对他了解还不是太深。据说是 2014 年的作品,难道东野圭吾在转型成社会派?作为日式推理小说并不是太好看,看起来被亚马逊放进特价书目里面并不是毫无理由。线索太散乱,布局感又太明显,立意很高,但显然对这个话题又无力下定论。何况是个很沉重的故事,看起来实在是太不轻松了。

2015-12-02

完了完了,今年又要完了

数了数,从去年的年末座谈会到现在,今年(2015 年)一共只写了八篇 Blog。平均一个月还不到一篇,我真的是太过于懒惰了。

其实,因为不见得全是懒惰。一方面,今年公司上马新项目,我是主程,工作时间特别忙,已经很难再抽出空来写 Blog 了。另外一方面,今年家里出的状况也特别的多,私人时间也很难抽得出来。曾经寄希望于搬家之后每天上下班时间能够在公共交通上完成这个任务,但现在看起来也不太适合。总之吧,客观原因还是挺多的。

争取这个月多写写吧。眼下貌似没有那么忙了。不然月底竜堂家四兄弟又要来找我的麻烦了。