如何干掉 Windows7/8 上的“获取 Windows 10”提示

如果还没看到,可以选择关闭自动更新,选择手动或者自动下载。在安装更新的时候跳过 KB3035583 即可。

否则的话,请点击“开始”菜单,再点击“控制面板”,找到“程序”下面的“卸载程序”。在左侧点击“查看已安装的更新”,在下面的“Microsoft Windows”组里面找到 KB3035583(如果发现的早,通常排在该组最上面)。右键“卸载”。

PuTTY 和 GitLab 的中文汉化版均更新到最新

从年后开始中断了三个月,终于恢复了。
期间因为 Google Code 的关闭,PuTTY 直接转移到 GitHub,同时也开始采用 GitLab 的本地化工作流
GitLab 跳过了好几个版本,包括一个未完成的 7.8 版本。其中 7.8 升级到 7.9 安装文档增加了 nodejs 的安装。
因为版本变动大,没有去跟踪变更,也没有仔细遍历文件。所以遗漏会很多。如果发现问题可以提交到 7.11的汉化里程碑中,会一直维护到下一个分支版本发布,也就是下个月 22 号。
这也希望能形成一种惯例。😁

Laravel 5 系统架构:服务提供者、服务容器、Contracts、Facades

官方文档在一方面真的写的很糟糕,完全没描述相互之间的关系。

事实上,服务提供者(Service Provider)服务容器(Service Container)ContractsFacades 是一件东西的多个方面。其实就是 Yii 的组件(Component)。

和 Yii 一样,Laravel 的所有功能都是通过与 Yii 组件类似的服务架构来实现的。

一个最简单直接的例子是 Lavarel Hashing 服务。其自身只是一个 Bcrypt hash 的封装。

首先,Laravel 5 定义了一个 Contracts:Illuminate/Contracts/Hashing/Hasher.php

<?php namespace IlluminateContractsHashing;
interface Hasher {
    /**
     * Hash the given value.
     *
     * @param  string  $value
     * @param  array   $options
     * @return string
     */
    public function make($value, array $options = array());
    /**
     * Check the given plain value against a hash.
     *
     * @param  string  $value
     * @param  string  $hashedValue
     * @param  array   $options
     * @return bool
     */
    public function check($value, $hashedValue, array $options = array());
    /**
     * Check if the given hash has been hashed using the given options.
     *
     * @param  string  $hashedValue
     * @param  array   $options
     * @return bool
     */
    public function needsRehash($hashedValue, array $options = array());
}

Contracts 只是描述一个服务的具体方法,而不是实现该服务。Container 才是服务的具体实现,对于一个服务来说,可能会有多种不同的实现。Hash 目前只有一个,就是:Illuminate/Hashing/BcryptHasher.php

<?php namespace IlluminateHashing;
use RuntimeException;
use IlluminateContractsHashingHasher as HasherContract;
class BcryptHasher implements HasherContract {
    /**
     * Default crypt cost factor.
     *
     * @var int
     */
    protected $rounds = 10;
    /**
     * Hash the given value.
     *
     * @param  string  $value
     * @param  array   $options
     * @return string
     *
     * @throws RuntimeException
     */
    public function make($value, array $options = array())
    {
        $cost = isset($options['rounds']) ? $options['rounds'] : $this->rounds;
        $hash = password_hash($value, PASSWORD_BCRYPT, array('cost' => $cost));
        if ($hash === false)
        {
            throw new RuntimeException("Bcrypt hashing not supported.");
        }
        return $hash;
    }
    /**
     * Check the given plain value against a hash.
     *
     * @param  string  $value
     * @param  string  $hashedValue
     * @param  array   $options
     * @return bool
     */
    public function check($value, $hashedValue, array $options = array())
    {
        return password_verify($value, $hashedValue);
    }
    /**
     * Check if the given hash has been hashed using the given options.
     *
     * @param  string  $hashedValue
     * @param  array   $options
     * @return bool
     */
    public function needsRehash($hashedValue, array $options = array())
    {
        $cost = isset($options['rounds']) ? $options['rounds'] : $this->rounds;
        return password_needs_rehash($hashedValue, PASSWORD_BCRYPT, array('cost' => $cost));
    }
    /**
     * Set the default password work factor.
     *
     * @param  int  $rounds
     * @return $this
     */
    public function setRounds($rounds)
    {
        $this->rounds = (int) $rounds;
        return $this;
    }
}

除了实现 Contracts 中定义的三个方法外,还实现了一个额外 setRounds() 方法。

下一步就是注册为服务提供者了:Illuminate/Hashing/HashServiceProvider.php

<?php namespace IlluminateHashing;
use IlluminateSupportServiceProvider;
class HashServiceProvider extends ServiceProvider {
    /**
     * Indicates if loading of the provider is deferred.
     *
     * @var bool
     */
    protected $defer = true;
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('hash', function() { return new BcryptHasher; });
    }
    /**
     * Get the services provided by the provider.
     *
     * @return array
     */
    public function provides()
    {
        return array('hash');
    }
}

很明显的 register 了服务,具体做的就是 new 了一个 Container。如果容器有多种实现,这时建议使用 Config 来配置服务了。

$this->app->singleton('hash', function($app) { return new Hasher($app['config']['hash']); });

这时候 Hasher 实际上一个工厂类(Factory),使用配置来确定具体的,如 new Hasher('bcrypt') 来实例化。

如果服务要延迟载入,也就是按需载入。需要有一个激活标志,也就是 provides() 方法。

当然,HashServiceProvider.php 必须在 config/app.phpproviders 中定义 'IlluminateHashingHashServiceProvider' 行。

这时,就可以使用:

$this->app->make('hash')->make('password');
$this->app['hash']->make('password');

最后,声明一个 Facade:Illuminate/Support/Facades/Hash.php

<?php namespace IlluminateSupportFacades;
/**
 * @see IlluminateHashingBcryptHasher
 */
class Hash extends Facade {
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'hash';
    }
}

config/app.phpaliases 中定义 'Hash' => 'IlluminateSupportFacadesHash' 行。

那么,就不用上面长长的 $this->app->make('hash'),直接:

Hash::make('password');

清除 chrome 的 HSTS 307 缓存

现代浏览器和网页服务器都开始支持 HSTS 功能,即自动将不安全的 HTTP 请求使用 307 Internal Redirect 跳转到 HTTPS 请求。

但是,用户的第一次访问还是不安全的。简单的说,在发生 307 的时候,用户可能就已经将用户名和密码暴露了。因为此时还是 HTTP 请求。

而且,这个第一次还可能是每次浏览器启动的时候,也就是说,可能每天都会发生,甚至多次。

所以,chrome 会自动记住每个域的 HSTS 设置。使得 HSTS 只是理论上的第一次暴露,后来就不经网页服务器返回,浏览器查询本地数据,直接伪造 HSTS 307 跳转到安全的 HTTPS,避免敏感数据的暴露。

很遗憾的说,这个很贴心的功能有时会造成麻烦。也就是说,一旦网页服务器设置了 HSTS,浏览器记住了。那么,将不会再访问该域的 HTTP 了。即使是网页服务器端已经修改了相关配置。原因当然是,这个记住是浏览器本地的。

还好,chrome 有暴露一些内部信息。不然就只有彻底删除浏览器才能清除。。。

在地址栏打开 chrome://net-internals/#hsts 下方的 Query domain 可以查询指定的域是否有 HSTS 记录,存在的话,在 Delete domain 删除即可。

GitLab 汉化工作流

首先,GitLab 汉化是针对 release 分支,而不是 master 分支。GitLab 的开发工作流是采用自身推荐的 GitLab Flow 开发工作流;简单的说,就是 master 分支用于开发新功能,发布版本到 release 分支(即 major-stable 分支);修补版本直接在 release 上迭代。

所以,GitLab 每个 release 版本的汉化在 git 树上独立的、不交叉的。即,7.1 分支上的汉化提交不会直接合并到 7.2 分支上,每个汉化 release 分支来源都是纯净的(pure)。

翻译的继承采用的是前一个 release 分支的 diff 然后 patch 到下一个版本的汉化 release 分支。

大致工作流程如下:

1、开始翻译项目

1
2
3
4
5
6
7
8
9
10
11
# 克隆源代码
git clone https://gitlab.com/gitlab-org/gitlab-ce.git
cd gitlab-ce
# 检出 7.1 版本分支
git checkout 7-1-stable
# 创建 7.1 版本汉化分支并切换工作区
git checkout -b 7-1-zh
# 开始翻译
nano app/views/layouts/_head.html.haml
git add app/views/layouts/_head.html.haml
git commit -m "translate layout head"

2、小版本更新,从 7.1.0 升级到 7.1.1

1
2
3
4
5
6
7
8
9
# 检出当前的 7.1 版本分支
git checkout 7-1-stable
# 拉取最新版本
git pull
# 然后切回当前翻译的 7.1 版本汉化分支
git checkout 7-1-zh
# 合并最新的版本
git merge 7-1-stable
# 如果发生冲突,手工处理合并冲突后再提交

3、大版本更新,从 7.1.x 升级到 7.2.x

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 导出前一版本 7.1 分支的差异文件
git diff 7-1-stable..7-1-zh &gt; ../7-1.diff
# 获取新分支
git fetch origin
# 检出新的 7.2 版本分支
git checkout 7-2-stable
# 创建 7.2 版本汉化分支并切换工作区
git checkout -b 7-2-zh
# 应用差异文件
git apply ../7-1.diff
# 将成功的修改提交
git add app/views/layouts/_head.html.haml
git commit -m "import 7.1 translate"
# 如果 patch 产生了 .rej 文件,作为 todo 处理未成功 patch 的 diff 差异
nano app/views/layouts/_head.html.haml
git add app/views/layouts/_head.html.haml
git commit -m "translate layout head"
# 处理完所有 .rej 并删除,并检视相关代码继续翻译

步骤 2 和 3 可交替进行互不影响。原则上,新的大版本工作开始之后就不再维护旧版本分支的翻译;即,只翻译最新的内容。

优点:

  1. git 版本树干净;确保翻译分支会污染原有分支和其他的翻译分支
  2. 每个 release 版本只要源分支出现就有可用的翻译,并开始新版本翻译工作
  3. 官方的原生修改无需 review 代码审查,避免合并多个分支造成代码审查必须处理官方正常的变更
  4. 应用上一版本的翻译提交可以简单审查;因为只是“正确”的提交,而不是可能有人工参与的合并(隐含冲突处理)
  5. 应用上一版本的翻译的冲突 .rej 实际上是当前版本翻译的 todo,可以多人协作处理,而不用等待某次冲突处理合并完成再开始
  6. 如果资源足够,多个大版本的翻译可以并行;并且仍然可以通过 patch 在各分支中共享

缺点:

  1. patch 会丢掉原始的提交信息;新版本分支的 blame 审查将找不到原始的作者

GitLab 汉化版升级到 7.2.1

晚了一个多星期,期间 gitlab 还做了一个小版本修复。

7.2 比 7.1 多了 Star 功能,暂时翻译成“标记”了。另外,还发现 git 的 tag 和 issue 和 label 都是“标签”,这种翻译好头痛。

除了 github 外,现在还推送到国内的 gitcafe 做镜像。

Ubuntu Server 14.04 使用 Ruby 2.0

官方源已经提供了 ruby2.0 但是因为 debian 源处理 bug 删除了 ruby-switch 包,就无法使用 update-alternatives 来切换 ruby 版本了。

目前就只有手工切换一下,命令如下:

1
2
3
4
5
6
7
8
9
10
sudo rm /usr/bin/ruby /usr/bin/gem /usr/bin/irb /usr/bin/rdoc /usr/bin/erb
sudo ln -s /usr/bin/ruby2.0 /usr/bin/ruby
sudo ln -s /usr/bin/gem2.0 /usr/bin/gem
sudo ln -s /usr/bin/irb2.0 /usr/bin/irb
sudo ln -s /usr/bin/rdoc2.0 /usr/bin/rdoc
sudo ln -s /usr/bin/erb2.0 /usr/bin/erb
sudo gem sources --remove https://rubygems.org/
sudo gem sources -a https://ruby.taobao.org/
sudo gem update --system
sudo gem pristine --all

嗯,顺便把 rubygems 切换到淘宝镜像。不知道什么时候 packagist 也有国内镜像啊;每次本地 composer update 都是在消耗时间。

为什么要选择 Ubuntu Server?

首先,我所参与的技术团队都是这样的:

  1. 没有自己的底层系统开发/定制团队;比如,自己定制特别的文件系统
  2. 也没有对特定的服务端做修改;嗯,就是维护自己的 nginx、php、mysql 这一套玩意
  3. 对安全有关注,但没有能力去主动寻找和解决安全问题;是的,团队很小
  4. 我们只采用主流的、成熟的新技术;应该说就是最近一两年开始兴起,然后被业内主流所接受的稳定技术
  5. 我们的很多项目会使用一些这样那样的小东西;虽说折腾是一个好习惯、好体验,但谁经不住折腾
  6. 只有兼职的系统维护工程师;很多情况下就是我自己

其实,这差不多就是为什么要采用 Ubuntu Server 的理由了。

对于服务器版本来说,可选的大约就是 FreeBSD、CentOS、Debian、Ubuntu Server、OpenSuse、Fedora 少数几个。除开 FreeBSD,大约就是 CentOS 与 Debian/Ubuntu Server 的选择。

大多数推崇 CentOS(也包括 FreeBSD)的理由就是稳定、可定制、硬件支持广泛,而实际上隐含的是,他们不更新,对系统也没有灾难处置。

是的。大部分人就是选择一个所谓稳定的系统、安装特定的服务端,然后就不再理会了。希望这台服务器可以省事的运行五年甚至七年。

实际上,对于服务器,我们需要:

  1. 及时的安全应对和更新
  2. 较新的服务端应用版本以便实施新技术,而不用自行定制

是的,我只是一个系统维护工程师,不是系统开发工程师。我需要关注的是安全、稳定、可用。但我不是系统开发,我无法独立去自行同时解决服务端应用软件的安全、稳定、可用。

虽然我可以为了解决可用,选择一个较新版本的开源服务端软件自行编译安装。但是,我需要去关注这个开源项目,订阅相关安全通知,并且在第一时间自行解决问题。

同样我也可以为了解决稳定,事先通过测试比较选取相应软件的最稳定版本,然后不再更新任何东西。但是,安全呢。

服务器不是孤立的。粗放的管理方式存在极大的隐患。而解决隐患,要耗费大量的精力,也包括我的能力。我不是系统开发工程师。

如果你不相信 Ubuntu 官方源的系统开发工程师不能为你提供最新、最安全、最稳定的服务端应用,我们还有 PPA 可用。

一般由专业厂商和团队乃至应用开发团队提供的 Personal Package Archives 源比你自行去解决要专业的多。嗯,除非你本身就是应用的开发工程师,那你更专业~