<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Hi, there👋 on arjenzhou</title><link>/feed.xml</link><description>Recent content in Hi, there👋 on arjenzhou</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Mon, 16 Mar 2026 00:00:00 +0000</lastBuildDate><atom:link href="/feed.xml" rel="self" type="application/rss+xml"/><item><title>科学养虾的第一步：把它关到笼子里</title><link>/article/2026/scientific-shrimp-keeping-macos-user-isolation/</link><pubDate>Mon, 16 Mar 2026 00:00:00 +0000</pubDate><guid>/article/2026/scientific-shrimp-keeping-macos-user-isolation/</guid><description>&lt;p>&lt;img src="https://i.imgur.com/OA7hbkY.png" alt="赛博机械虾">&lt;/p>
&lt;h1 id="01-引言mac-mini-成了大虾缸">01. 引言：Mac mini 成了“大虾缸”&lt;/h1>
&lt;p>最近 OpenClaw 的火爆程度堪比当年的酱香拿铁，圈内玩家人手一台 Mac mini，主打一个 24 小时在线“养虾”。&lt;/p>
&lt;p>但随着热度上升，安全风险也浮出水面。很多玩家为了图省事，直接在自己的主账户下顺手一敲 sudo 运行。你要知道，OpenClaw 作为一个高度联网、且支持第三方插件的程序，直接给它主账号权限，等同于把家里的保险箱钥匙挂在路边电线杆上。万一代码里有个“回声”，你的私有照片、工作文档、浏览器缓存可就全成了“虾粮”。&lt;/p>
&lt;p>科学养虾的第一法则：权限隔离。 既然要养，就得给它焊个结实的笼子。&lt;/p>
&lt;h1 id="02-笼子的构造创建隔离用户">02. 笼子的构造：创建隔离用户&lt;/h1>
&lt;p>在 macOS 上，最简单有效的“笼子”就是创建一个独立的系统用户。&lt;/p>
&lt;ol>
&lt;li>创建隔离组 (Group)&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>打开 “系统设置” -&amp;gt; “用户与群组”。&lt;/p>
&lt;p>点击下方的 “添加群组&amp;hellip;” (Add Group)。&lt;/p>
&lt;p>将组名设置为 agents。这个组将作为你所有隔离程序的统一“安保边界”。&lt;/p>&lt;/blockquote>
&lt;ol start="2">
&lt;li>创建隔离用户 (User)&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>在同一页面，点击 “添加用户&amp;hellip;” (Add User)。&lt;/p>
&lt;p>关键： 在“新用户”类型下拉框中选择 “标准”，千万不要选“管理员”。&lt;/p>
&lt;p>帐户名填 openclaw。&lt;/p>
&lt;p>创建完成后，你会发现系统已自动为它准备了一个干净的家目录 /Users/openclaw。&lt;/p>&lt;/blockquote>
&lt;ol start="3">
&lt;li>将用户归类&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>在列表里找到刚才创建的 agents 组，点击“i”图标（详情）。&lt;/p>
&lt;p>在成员列表中，勾选上 openclaw。&lt;/p>
&lt;p>物理隔离：这个用户拥有独立的家目录 /Users/openclaw。你的主目录（如 /Users/&amp;lt;YourUsername&amp;gt;/）对它来说默认是禁区。&lt;/p>&lt;/blockquote>
&lt;p>&lt;img src="https://i.imgur.com/EdYrzcI.png" alt="">&lt;/p>
&lt;p>在终端里，我们不需要切换 GUI 界面，直接通过 su 优雅地“跳”进笼子：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 使用管理员身份切换到 openclaw 环境&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo su - openclaw
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h1 id="03-喂虾流程部署中的深水区">03. 喂虾流程：部署中的“深水区”&lt;/h1>
&lt;p>在隔离环境里，我们依然追求极致的系统洁癖。&lt;/p></description></item><item><title>将 Gradle 构建的 Java 产物发布到 Maven 中央仓库和 GitHub Packages</title><link>/article/2023/07/how-to-release-a-gradle-project/</link><pubDate>Thu, 20 Jul 2023 00:00:00 +0000</pubDate><guid>/article/2023/07/how-to-release-a-gradle-project/</guid><description>&lt;p>日常开发中经常会抽象出一些常用的工具代码，这些代码可以作为三方包发布到中央仓库，在开一个新项目的时候直接引进来使用。&lt;br>
除中央仓库之外，GitHub 也为开源项目提供了免费的 GitHub Packages 作为托管这些产物的平台。&lt;/p>
&lt;p>所以本文会介绍一个将使用 Gradle 构建的 Java 项目产物，托管到 Maven 中央仓库和 GitHub Packages 的方案。&lt;/p>
&lt;p>撰写本文时的环境如下：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>依赖&lt;/th>
 &lt;th>版本&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Gradle&lt;/td>
 &lt;td>8.2.1&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Java&lt;/td>
 &lt;td>java version &amp;ldquo;17.0.7&amp;rdquo; 2023-04-18 LTS&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>commit&lt;/td>
 &lt;td>&lt;a href="https://github.com/arjenzhou/bm-kit/tree/35256125ba7f3b0ba131b8721775576c0936c3a0">35256125ba7f3b0ba131b8721775576c0936c3a0&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h1 id="更严格的-maven-central">更严格的 Maven Central&lt;/h1>
&lt;p>对于 Release 发布来说，Maven 中央仓库对发布产物有着更严苛的要求。&lt;/p>
&lt;ul>
&lt;li>需要对每个产物进行合法性校验
&lt;ul>
&lt;li>每个产物需要上传 PGP 加密文件 *.asc&lt;/li>
&lt;li>GPG 的公钥需要公网可见&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>POM 中需要包含项目的名称、描述、地址、协议、开发者信息、仓库信息等&lt;/li>
&lt;li>Maven Central 区分 snapshot 和 release 的发布地址&lt;/li>
&lt;li>Maven Central 需要在 Nexus Repository Manager 上管理 release 产物&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>这里的 GPG 和 PGP 并不是 typo&lt;/p>&lt;/blockquote>
&lt;p>所以，想要将代码发布到中央仓库的前提就清楚了（GitHub Packages 的前提更少）：&lt;/p></description></item><item><title>国庆节</title><link>/article/2022/10/after-national-day/</link><pubDate>Sat, 08 Oct 2022 00:00:00 +0000</pubDate><guid>/article/2022/10/after-national-day/</guid><description>&lt;blockquote>
&lt;p>于 2022.10.6&lt;/p>&lt;/blockquote>
&lt;p>明天一早就要回杭州，深夜胡言乱语。&lt;/p>
&lt;p>终于迎来了同龄人的第一批婚礼邀请：一个是高中的好兄弟订婚，新娘也是我的高中同学；另一个是大学亦师亦友的学长。我真心地为他们感到高兴。
自从2020年毕业工作以来，一直没机会回东北。和久违的亲人朋友再次团聚让我暂时释去了工作和生活的压力，只是长辈一句很正确的话让我略感压抑：“该是什么时候，就干什么事”。像其他同龄人一样，只是我面对的催婚方式不那么直接罢了。&lt;/p>
&lt;p>回首人生经历过的短短二十四年，似乎每一步都是按照正确的路线成长着：考上重点高中、到一个还算说得过去的大学里读书、毕业后找到一份体面的工作。按照这样的规划，下一步也许就像我的同学和学长一样，和一个合适的人结婚，这是可以预见的。&lt;/p>
&lt;p>我没有埋怨任何人的意思。即使这样的生活是为了自己，但也真切地背叛了自己。按照这样的规划来看：未来明确，质量也说得过去，循规蹈矩下去应该能够安稳度过一生。但每到静下来时总会审视自己的内心：这真的是想要的生活吗？&lt;/p>
&lt;p>我深知不是的。我也想每天呆在家里，和亲人在一起聚会聊天；我也想拿赚来的第一桶金买一辆自己喜欢的车，和好朋友跑到全世界玩；我也想将无聊的业务需求置之不顾，只钻研自己感兴趣的那一亩三分地；我也想把一切抛开，只顾自己的感受……但囿于对“生活”的责任，只能亲手把沉重的枷锁穿戴在自己身上，像一头勤恳的黄牛。&lt;/p>
&lt;p>我不知道其他同龄人是否也有这种压力，但我知道这决不是普世价值。世界上有那么多的人在追求自己的追求，也有那么多人在享受自己的享受。而父辈为下一代的责任在我这一代又陷入了轮回，只能用屈指可数的业务爱好来尝试消解这种无力的感受。&lt;/p>
&lt;p>也许每个小孩都不想要这样的生活吧，当大人真累。&lt;/p></description></item><item><title>我的网络环境</title><link>/article/2022/08/network-topology/</link><pubDate>Tue, 30 Aug 2022 00:00:00 +0000</pubDate><guid>/article/2022/08/network-topology/</guid><description>&lt;h1 id="背景">背景&lt;/h1>
&lt;p>故事发生在今年的2月。PS5到手没两天诞生了搞直播的想法，在摸索的过程中发现了《&lt;a href="https://homulilly.com/post/play-ps4-live-stream-at-local.html">搭建 PS4 本地直播服务器&lt;/a>》这篇帖子，于是就冒出了折腾的心思。毕竟花钱买采集卡有点冤大头的感觉。&lt;/p>
&lt;p>之前家里的网络环境比较简单，只需要在 Openwrt 上装一些插件，所以一台在上学时候收的一个矿渣 K2P 就够了。&lt;/p>
&lt;figure>&lt;img src="https://s2.loli.net/2022/08/30/7dJkU4iIrhueqpW.png">&lt;figcaption>
 &lt;h4>矿渣 K2P&lt;/h4>
 &lt;/figcaption>
&lt;/figure>

&lt;p>后来因为 UU 的插件不够稳定，又搞了一个 UU 加速盒。
&lt;figure>&lt;img src="https://s2.loli.net/2022/08/30/XnFu6aRpCyS5Uvk.jpg">&lt;figcaption>
 &lt;h4>垃圾 UU 加速盒&lt;/h4>
 &lt;/figcaption>
&lt;/figure>
&lt;/p>
&lt;p>但是如果想搞直播，就得每天在工作电脑上跑一个 docker，太麻烦了。&lt;/p>
&lt;p>于是，我便斥巨资购入了一款 J4125
&lt;figure>&lt;img src="https://s2.loli.net/2022/08/30/u3Ca5fFdVrGUO78.jpg">&lt;figcaption>
 &lt;h4>J4125&lt;/h4>
 &lt;/figcaption>
&lt;/figure>
&lt;/p>
&lt;p>遗憾的是，尽管这款主机内置了 MSATA 和 SATA3.0 两款接口，但是没有能力容纳下一个 SATA3.0 的硬盘，所以在我手里变成了这样：
&lt;figure>&lt;img src="https://s2.loli.net/2022/08/30/ekSHDZqGURTJFwY.jpg">&lt;figcaption>
 &lt;h4>外挂式硬盘，蚌埠住了&lt;/h4>
 &lt;/figcaption>
&lt;/figure>
&lt;/p>
&lt;h1 id="软路由">软路由&lt;/h1>
&lt;blockquote>
&lt;p>过了半年回过头来看，其实根本没必要来搞一个性能远远溢出的 J4125，因为实际上只会跑几个性能开销很小的虚拟机。&lt;/p>&lt;/blockquote>
&lt;p>搞这台小主机的目的是为了装一个 debian 来跑 nginx 拦截 PS5 的流量，而裸装 debian 有点不够划算，于是干脆个装 PVE 来个 all in one。
&lt;figure>&lt;img src="https://s2.loli.net/2022/08/30/8IH6F3QqbtMxs49.png">&lt;figcaption>
 &lt;h4>All in PVE&lt;/h4>
 &lt;/figcaption>
&lt;/figure>
&lt;/p>
&lt;p>第一步，先把 ROS 和作为 AC 的 Openwrt 搞好，参考《&lt;a href="https://www.cnblogs.com/Pyrokine/p/14526662.html">基于PVE+ROS+LEDE的软路由配置流程&lt;/a>》，其中需要注意的是，Openwrt 的安装比较麻烦，需要后挂载。在设备联入网络时，根据网关设置为 ROS 或者 Openwrt，可以区分不同的网络环境实现按需科学上网。&lt;/p>
&lt;h1 id="ap">AP&lt;/h1>
&lt;p>按照上面引用的文章操作完成后，网络设备可以通过插网线的模式来上网了。但是现在都什么年代了还在用传统上网？所以把 K2P 设置成 AP，参考《&lt;a href="https://www.wyr.me/post/676">OpenWRT 设置桥接交换机模式（AP模式）&lt;/a>》，注意设置为交换机模式后就可以当 AP 使用，如果想通过无线连接到 AP 上需要设置客户端。&lt;/p></description></item><item><title>Bitcoin, Blockchain, Ethereum</title><link>/article/2022/06/bitcoin-blockchain-ethereum/</link><pubDate>Tue, 21 Jun 2022 00:00:00 +0000</pubDate><guid>/article/2022/06/bitcoin-blockchain-ethereum/</guid><description>&lt;h1 id="中本聪的愿望">中本聪的愿望&lt;/h1>
&lt;blockquote>
&lt;p>“传统货币最根本的问题在于信任。中央银行必须让人信任它不会让货币贬值，但历史上这种可信度从来都不存在。银行必须让人信任它能管理好钱财，并让这些财富以电子货币形式流通，但银行却用货币来制造信贷泡沫，使得私人财富缩水。”&lt;/p>&lt;/blockquote>
&lt;p>1933年4月5日，为了使政府能够再印制更多现金注入市场，罗斯福总统签署了6102号行政命令，要求美国公民以每金衡盎司20.67美元的价格上交黄金，否则可处以10,000美元的罚款，甚至还可判处入狱服刑5至10年，同时也禁止黄金出口海外，以确保美国拥有的黄金不会外流。
&lt;figure>&lt;img src="https://s2.loli.net/2022/06/21/jV6NfbAmLZOs2RB.png">&lt;figcaption>
 &lt;h4>Executive Order 6102&lt;/h4>
 &lt;/figcaption>
&lt;/figure>
&lt;/p>
&lt;p>罗斯福没收充公美国人的黄金，并以美元交换，然后让美元贬值了40%，强制推高黄金价，目的是让美国的债务贬值，从而对抗大萧条，造成的后果是美国人的财富被洗劫了40%。&lt;/p>
&lt;p>1974 年，福特总统签署了 Public Law 93-373 即“黄金合法化法案”，1975年美国人可以再一次合法拥有黄金。
&lt;figure>&lt;img src="https://s2.loli.net/2022/06/21/on7U1KjtDR8kgxc.png">&lt;figcaption>
 &lt;h4>Satoshi Nakamoto&amp;#39;s Profile&lt;/h4>
 &lt;/figcaption>
&lt;/figure>
&lt;/p>
&lt;p>P2PFoundation 是中本聪发布比特币白皮书的网站，在这注册必须提供出生日期，中本聪填写的是1975年4月5日。&lt;/p>
&lt;h1 id="电子支付的问题">电子支付的问题&lt;/h1>
&lt;p>互联网上的贸易，几乎都需要借助金融机构作为可资信赖的第三方来处理电子支付信息。是这类系统仍然内生性地受制于“基于信用的模式”的弱点：&lt;/p>
&lt;ul>
&lt;li>无法实现完全不可逆的交易，因为金融机构总是不可避免地会出面协调争端。&lt;/li>
&lt;li>金融中介的存在增加交易的成本，并且限制了实际可行的最小交易规模，也限制了日常的小额支付交易。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>这些问题在物理现金交易中是不存在的。&lt;/strong>&lt;/p>
&lt;p>所以需要这样一种电子支付系统，它基于密码学原理而不基于信用，使得任何达成一致的双方，能够直接进行支付，从而不需要第三方中介的参与。&lt;/p>
&lt;h2 id="雅浦岛的故事">雅浦岛的故事&lt;/h2>
&lt;p>雅浦岛是一个金属资源比较匮乏的岛，就算是石灰岩也要去400英里以外的帕劳岛开采。雅浦岛部落里的探险家们开采这些石灰岩，打制成内部中空呈环形的石轮，然后用木筏运回雅浦岛作为货币使用。这些石轮小的直径30多厘米，大的直径有3米多。为了便于运输，有时会往中间插一根粗壮的木柱。开采难度越高，越漂亮，越大的石币价值越高。
&lt;figure>&lt;img src="https://s2.loli.net/2022/06/21/zFaCbefmlY1Hod9.png">&lt;figcaption>
 &lt;h4>雅浦岛的石币&lt;/h4>
 &lt;/figcaption>
&lt;/figure>
&lt;/p>
&lt;p>雅浦石币有个很有趣的特点。交易双方在决定了使用多大的石币付费后，如果那个石头太大了，不方便运输，那么卖家只要在买家的石头上做个标记就可以了，这样就付费了。那个标记就说明这个石头已经属于卖家了，而石头仍然躺在买家屋里。
&lt;figure>&lt;img src="https://s2.loli.net/2022/06/21/KuiDO8UY426qXyH.png">&lt;figcaption>
 &lt;h4>雅浦岛的石币&lt;/h4>
 &lt;/figcaption>
&lt;/figure>
&lt;/p>
&lt;p>岛上有一户首富，但没有人见过他家里的石币。他们家拥有的财产是一个巨大的石币，大小只有上上辈人才知道，因为这个石币一直沉睡在海底。这户人家的祖辈和其他人外出开采石灰岩并制成石币，在用木筏拉回家的归途中遭遇了强烈的暴风雨，为了逃命，探险队只好砍掉拉筏的绳子，于是那块巨大的石币沉入了大海。回村后探险队的成员都替他作证，虽然已掉落大海，但大伙都见证了这块石头的去处，所以不会影响它的价值，它的主人仍然可以用它去买东西，就跟把石币运回家存放起来的效果一样。&lt;/p>
&lt;h2 id="比特币和石币">比特币和石币&lt;/h2>
&lt;p>如果雅浦岛首富想要私下使用这笔巨款，比如偷偷跟自己的情人说：我那块大石头送给你了。这次交易是无效的，因为交易没有广播，并没有其他岛民在旁边作证。但如果首富临死前，当着全岛人民的面说，这块大石头就作为遗产给我的大儿子了。那么这笔交易就是有效的，因为其他岛民都做了见证，并集体更新了头脑里的“账簿”。&lt;/p>
&lt;p>假如雅浦岛上的交易越来越多，大家根本记不住这么多交易，所以打算使用比特币：&lt;/p>
&lt;blockquote>
&lt;p>石币：大家都知道这个石币的所有人是村民1，那么他可以将其转账给村民2&lt;br>
比特币：大家都知道这个比特币的所有人是村民1，那么他可以将其转账给村民2&lt;/p>&lt;/blockquote>
&lt;p>在传统的交易中，采取的是&lt;strong>账户/余额模型&lt;/strong>。比如银行账户、微信账户，都是基于账户/余额模型。
&lt;strong>账户内的余额是作为一个整体存在的。&lt;/strong>&lt;/p>
&lt;p>而比特币采用的是 &lt;strong>UTXO (Unspent Transaction Output) 模型&lt;/strong>
&lt;figure>&lt;img src="https://s2.loli.net/2022/06/21/qAb2Dczn8wNpI1f.png">&lt;figcaption>
 &lt;h4>BTC Transaction&lt;/h4>
 &lt;/figcaption>
&lt;/figure>
&lt;/p>
&lt;p>在比特币中，一笔交易的每一条输入和输出实际上都是 UTXO，输入 UTXO 就是以前交易剩下的， 更准确的说是以前交易的输出 UTXO。除了 coinbase 交易（挖矿奖励）没有输入 UTXO 之外，其它交易都有输入和输出，都可以为多个。在比特币中没有余额概念，只有分散到区块链里的 UTXO。&lt;/p>
&lt;h3 id="谁拥有-utxo">谁拥有 UTXO&lt;/h3>
&lt;p>在雅浦岛上，村民之间可以确定这个石币的所有者是谁。而比特币转账实际上是从一个地址被移动到另一个地址，当村民1想花费0.15个比特币时，如何证明自己拥有这个 UTXO，并且其他人无法假冒村民1来花费这个 UTXO 呢？&lt;/p>
&lt;p>比特币的交易创建的输出其实并非一个简单的公钥地址，而是一个脚本。每一个比特币节点会通过同时执行这解锁和锁定脚本（&lt;strong>不是当前的锁定脚本，是指上一个交易的锁定脚本&lt;/strong>）来验证一笔交易，脚本组合结果为真，则为有效交易。
&lt;figure>&lt;img src="https://s2.loli.net/2022/06/21/6crY1BlWwi4zD7q.png">&lt;figcaption>
 &lt;h4>BTC 交易脚本&lt;/h4>
 &lt;/figcaption>
&lt;/figure>
&lt;/p></description></item><item><title>游戏主机对比： Nintendo Switch, Xbox Series S, PlayStation 5</title><link>/article/2022/05/console-review/</link><pubDate>Mon, 16 May 2022 00:00:00 +0000</pubDate><guid>/article/2022/05/console-review/</guid><description>&lt;blockquote>
&lt;p>其实这篇文章在22年2月的时候就应该写了，由于各种原因一直拖到现在，所以本文叙述的时间点为2月。&lt;/p>&lt;/blockquote>
&lt;h2 id="我的-windows-游戏时代">我的 Windows 游戏时代&lt;/h2>
&lt;p>大概在07年小学三、四年级的时候，我到小学同学家第一次玩到了 GTA: VC，这是我第一次正始接触单机游戏（打字游戏除外）。后来又在他家接触了流星蝴蝶剑，和跑跑卡丁车、天龙八部这些网游。同年，也在堂哥那里玩到了 PSP 版的真三国无双。过了一年家里买了电脑之后，便开始了我自己的游戏之路。各种主流游戏都浅尝辄止，但电脑没少折腾：试过各种游戏外挂，也自己做过游戏补丁；那时我的输入和检索能力、“修电脑的能力”就已经呈现了出来，我一直认为这是我走上程序员之路的契机。直到有一天我发现部分境外网站无法登录之前，那是中文互联网的黄金年代，我很怀念它。&lt;/p>
&lt;p>我不是一个资深的主机玩家，工作前我一直用我的“黑金刚”玩游戏，所以我没有资格来评价各个主机，只能凭借自己的体验简单介绍下我的主观感受。初中时，家里的电脑玩英雄联盟最高只能到30帧，注册了一个 Steam 账号却连 DotA2 都进不去，回想当初肯定是被电脑城的人宰了。大学时游戏没少玩，但只是随便玩玩而已。&lt;/p>
&lt;figure>&lt;img src="https://s2.loli.net/2022/05/16/3fIpK7yxYbTcsla.png">&lt;figcaption>
 &lt;h4>我的黑金刚 MSI GE62。GTX965M 的显卡，配上2GB 的显存属实有点拉胯&lt;/h4>
 &lt;/figcaption>
&lt;/figure>

&lt;h2 id="nintendo-switch">Nintendo Switch&lt;/h2>
&lt;p>等到工作第一年，我入手了 NS。到现在也才只有塞尔达传说：旷野之息算是完全通关了。&lt;/p>
&lt;p>我认为 NS 是一个优秀的游戏机，便携性是它最突出的优势，独占/聚会/家庭游戏是它的特长，主机模式下性能略显尴尬。我没有买过 Switch Pro Controller，其自带的 Joy Controller 仅仅能用而已。任天堂第一方的游戏，绝对是 NS 的核心优势。&lt;/p>
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/PAh90-Ggr14?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="打倒盖侬多夫">&lt;/iframe>
 &lt;/div>

&lt;h2 id="xbox-series-s">Xbox Series S&lt;/h2>
&lt;p>这一代微软发售了 Xbox Series X (XSX) 和 Xbox Series S (XSS)。XSX 是这一代的旗舰机，理论性能此世代最强；XSS 相对轻便，不过性能好像只有 XSX 的1/4，而且只有数字版。
微软在 PC 和 Console 上推出的 Xbox Game Pass (XGP) 订阅制以周期的形式上架/下架一批游戏，凡是订阅的玩家都可以下载游玩。&lt;/p></description></item><item><title>ZeroTier 实现内网穿透——入门篇</title><link>/article/2022/02/zerotier/</link><pubDate>Wed, 16 Feb 2022 00:00:00 +0000</pubDate><guid>/article/2022/02/zerotier/</guid><description>&lt;p>上周末逛 v2 看到评论区提到了 ZeroTier, 想起来家里路由器上 Openwrt 带了这个插件，虽然目前没有内网穿透的需求，但是趁着周末还是稍微研究了下。&lt;/p>
&lt;h2 id="应用场景">应用场景&lt;/h2>
&lt;p>从标题中可以看出，ZeroTier 是实现内网穿透的一个手段。简单来说就是能够通过它来实现不同局域网之间的互相访问：在公司局域网能连到家里的网络（不要这么做）&lt;/p>
&lt;h2 id="原理">原理&lt;/h2>
&lt;p>大致简单了解了一下，局域网中各设备通过互联网与 Zeroier 的“行星服务器”建立 P2P VPN 连接，如果两个设备能够通过 VPN 直连那么就直连，否则通过 ZeroTier 中继。&lt;/p>
&lt;h2 id="简单使用">简单使用&lt;/h2>
&lt;p>登录并创建一个 Network 之后，使用 ZeroTier 客户端依据 Network ID 连接到该 Network 并认证后。为该网络分配一个网段，给设备分配 IP 并设置路由规则后就可以使用分配的 IP 互相访问了，是不是很简单？&lt;/p>
&lt;blockquote>
&lt;p>注意，将路由器加入 ZeroTier 需要配置防火墙。&lt;/p>&lt;/blockquote>
&lt;p>截图举个例子：&lt;/p>
&lt;ul>
&lt;li>在 IPv4 Auto-Assign 部分，为网络设置 IP 段。&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://s2.loli.net/2022/02/16/Se2K4MIFPdnLjJy.png" alt="">&lt;/p>
&lt;p>这里我将这个网络设置了 &lt;code>10.242.100.0/24&lt;/code> IP 段。&lt;/p>
&lt;ul>
&lt;li>设置路由规则&lt;/li>
&lt;/ul>
&lt;p>分配 IP 段后要为局域网设置路由规则。&lt;/p>
&lt;p>&lt;img src="https://s2.loli.net/2022/02/16/wGz2SEV4iDQcTLa.png" alt="">&lt;/p>
&lt;p>图中 &lt;code>192.168.6.0/24&lt;/code> 是我家里的局域网 IP 段，&lt;code>10.242.100.0/24&lt;/code> 是上面 ZeroTier 分配的 IP 段。&lt;/p>
&lt;ul>
&lt;li>设备连入并点击认证后，为其分配 IP&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://s2.loli.net/2022/02/16/Ls6mo3xUg5KWYSp.png" alt="">&lt;/p></description></item><item><title>键盘对比：NIZ Plum, FILCO 圣手2代, HHKB Professional Hybrid</title><link>/article/2022/02/keyboard-review/</link><pubDate>Thu, 10 Feb 2022 00:00:00 +0000</pubDate><guid>/article/2022/02/keyboard-review/</guid><description>&lt;p>之前用的一直是大一刚入学200块买的达尔优的机械键盘，作为刚入学的经常在宿舍打游戏的大学生，这是一款很常见的键盘：RGB，茶轴，104键，要素齐全。&lt;/p>
&lt;h2 id="niz-plum-mini-84-pro-35g">NIZ Plum mini 84 Pro (35g)&lt;/h2>
&lt;p>2019年2月，我入手了一副 NIZ Plum mini 84 Pro 35g。&lt;/p>
&lt;p>&lt;img src="https://s2.loli.net/2022/02/10/4FtuDqZI1VxjyHn.jpg" alt="">&lt;/p>
&lt;p>这款键盘当初是打算在 Mac 上用的，经网友推荐我仔细挑选后选中了这款。上手的第一感受就是&lt;code>软&lt;/code>，打字手感特别黏稠、松垮的感觉。“也许这就是静电容”，我心想。用过一段时间发现尤其在789附近的数字区，由于35g实在是太轻了，经常出现&lt;code>误触&lt;/code>的情况，一按下去一片数字上屏。后来用附送的增重弹簧给核心区域的键增到45g，这时才刚刚好。让人不得不吐槽的是竟然没有送84个弹簧，而且大键装起来很麻烦。这款键盘的布局还是很合理的，有F区，方向键很紧凑，只是右面一列有点多余，导致经常不好定位回车键。&lt;/p>
&lt;p>用了两年多，这款键盘的缺点逐渐暴露出来了：按键经常&lt;code>失灵&lt;/code>且打字&lt;code>卡顿&lt;/code>，只不过不是必现。考虑到这款键盘当时是发烧友制作，并不是成熟的产品，质量问题还勉强说的过去。只是现在摸起来还是比较粗糙的，不过最近的产品看评价不错，多半是从手感上来打的分。&lt;/p>
&lt;h2 id="filco-majestouch-convertible-2-tenkeyless-cherry-mx-red">FILCO Majestouch Convertible 2 Tenkeyless (Cherry MX Red)&lt;/h2>
&lt;p>这款键盘是我在工作之后买的，对它的第一印象就是：&lt;code>好看&lt;/code>。奶绿色给人一种草原、牧场、奶牛的感觉。&lt;/p>
&lt;p>&lt;img src="https://s2.loli.net/2022/02/10/wcXYTaNUCyHMfqr.jpg" alt="">&lt;/p>
&lt;p>这款键盘本不是为 Mac 设计的，这一点从其自带的 Windows 键就能看得出来。不过得益于 Karabiner-Elements, 我们能很方便的在将 Command 和 Option 对掉 (图中 Alt 键和 Windows 键盘对换了)&lt;/p>
&lt;p>我手中的这把是红轴的，理论上是樱桃轴体中比较轻的一款。但是在尝试过静电容之后，红轴对我来说在长时间的编码之后还是相对&lt;code>重&lt;/code>了一些。F区以及方向键的隔离能够避免误触的情况，也让它显得&lt;code>大&lt;/code>了一些。但是随着我入了一个 Magic Trackpad 之后，我变得越来越懒了。我在工作时两只手腕完全不想动，写代码时能用 Vim 的地方用 Vim，不行就各种快捷键，最坏的情况才把手向下移去用 Magic Trackpad. 而且用 Vim 时左小指频繁地去按 Control 键，时间久了越来越累。这让我转向它处另寻键盘。&lt;/p>
&lt;blockquote>
&lt;p>这款键盘本身带了 Caps Lock 和 Control 的替换键帽，并且能够通过背面的 DIP 设置将其两者交换来达到 HHKB 的键位效果。&lt;br>
2022.2.16 注&lt;/p></description></item><item><title>谈谈我理解的 Raft</title><link>/article/2021/11/raft-talk/</link><pubDate>Mon, 08 Nov 2021 00:00:00 +0000</pubDate><guid>/article/2021/11/raft-talk/</guid><description>&lt;p>自几年前偶然得知 Raft 之后，便粗略了解了 Raft, Paxos, 共识（一致性）这些概念。当时的想法是：这些算法听起来就挺装逼的，赶紧去看看咋回事。等到认真一看 Raft 论文，20页，太多了还是算了吧。
等到过了几天，又发现了 Raft 官网有个动画，还挺易懂的，又简单看了看，明白了，可以出去装逼了。
再过几天一回忆，好像啥也没记住呢？虽然张无忌学太极拳也啥也没记住，但至少人家打出来了，咱也得找机会练练。这会儿又找到了 MIT 6.824, 正好赶上新学期开课了，跟着学吧。
没等学两天，一到 lab 就懒得做，Go 看不懂啊，又学了几天 Go。学完了感觉啥都会了，但是又啥也不会。还是先去找实习吧。&lt;/p>
&lt;p>前年快写毕业论文的时候，附带个翻译英文文献的任务，又到了装逼的时候了，我就直接在 arXiv 上找了篇 &lt;a href="../../../../translation/2020/11/21/paxos-vs-raft-have-we-reached-consensus-on-distributed-consensus/">Raft 和 Paxos 对比&lt;/a> 的论文翻译了下，由于当时懒得排版，等到去年年底才扔到博客上。&lt;/p>
&lt;p>论文翻译完，又感觉啥也没记住。但是快要去上班了，又没时间研究了，上了一年班之后又找来了 Martin Kleppmann 的&lt;a href="https://www.youtube.com/playlist?list=PLeKd45zvjcDFUEv_ohr_HdUFe97RItdiB">公开课&lt;/a>来看，没几天就看完了，当时看完觉得啥都懂了，现在回忆起来只记住了拜占庭那些东西，又联想到凯撒、庞贝&amp;hellip;又联想远了&amp;hellip;&lt;/p>
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/UEAMfLPZZhE?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video">&lt;/iframe>
 &lt;/div>

&lt;p>从去年7月入职以来，搞了本影印的 DDIA 来看。看书么，必须得英文原文，不然咋装逼啊是不。按照每天一页的进度终于把这书看完了（其实一周200页，然后歇半年）。看到后面又提到共识机制，觉得有必要再重新捡起来 Raft 论文再读一下了。&lt;/p>
&lt;p>手中的 Raft 这篇&lt;a href="https://raft.github.io/raft.pdf">论文&lt;/a>实际上时几个月之前在公司的打印机上打印的，并且当时详细地做了注解，但随后没有好好整理。这次又根据上次遗留的问题来作笔记，最后写下了这篇文章表达一下自己的见解。&lt;/p>
&lt;h2 id="前提">前提&lt;/h2>
&lt;p>Raft 据说是性能相当于 Paxos, 效果相当于 Multi-Paxos 的一个一致性算法，但它更容易理解。&lt;/p></description></item><item><title>Paxos vs Raft: Have we reached consensus on distributed consensus?</title><link>/translation/2020/11/21/paxos-vs-raft-have-we-reached-consensus-on-distributed-consensus/</link><pubDate>Sat, 21 Nov 2020 00:00:00 +0000</pubDate><guid>/translation/2020/11/21/paxos-vs-raft-have-we-reached-consensus-on-distributed-consensus/</guid><description>&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>分布式一致性是构建具有容错、强一致性特点的分布式系统的重要原语。在众多分布式公式算法中，其中有两个统治着生产系统：经典、也是以晦涩难懂著称的 Paxos；较新的、与 Paxos 相比更易理解的 Raft。&lt;/p>
&lt;p>本文主要研究 Paxos 和 Raft 那个是更好的分布式一致性解决方案。我们通过使用 Raft 的术语和语用抽象来描述简化的 Paxos 算法，从而对两者进行精确分析，以确定它们之间的区别。&lt;/p>
&lt;p>我们发现 Paxos 和 Raft 都采用相似的方式来达成分布式一致性，它们之间的区别只在于 leader 选举。最值得注意的是，Raft 只允许有最新日志的节点成为 leader，而 Paxos 允许任何节点成为 leader，前提是之后更新其日志来保证为最新。对于这样的简单性来时，Raft 的方法出奇的高效，因为与 Paxos 不同，它在 leader 选举时不需要日志条目的交换。我们推测，Raft 的可理解性大多来自于论文的清楚陈述，而不是展现出的基本算法的基础。&lt;/p>
&lt;p>&lt;strong>&lt;em>CCS 概念&lt;/em>：计算机系统管理→可靠性；软件及其工程→云计算；计算理论→分布式算法&lt;/strong>&lt;/p>
&lt;p>&lt;em>&lt;strong>关键词&lt;/strong>&lt;/em>：状态机复制，分布式一致性，Paxos，Raft&lt;/p>
&lt;h2 id="1-简介">1 简介&lt;/h2>
&lt;p>状态机复制[32]广泛用于将一群不可靠的主机组成一个可靠的能够提供强一致性保证包括线性化[13]的服务。据此，程序员能够通过复制状态机将服务看作一个单点系统，从而轻松推断出预期的表现。状态机复制需要每个状态机以相同的顺序接受相同的操作，这可以通过分布式一致性实现。&lt;/p>
&lt;p>Paxos 算法[16]与分布式一致性关系密切。虽然它很成功，但是 Paxos 晦涩难懂，造成了其难以推理、正确实现和安全优化。这已经在无数次用更简单的术语解释算法的尝试[4, 17, 22, 23, 25, 29, 35]中得到明显体现了，而且这也是 Raft[28] 的目的。&lt;/p>
&lt;p>Raft 的作者声称 Raft 与 Paxos 同样高效而更易懂，因此为实现具体系统提供了更好的基础。Raft 以这三种不同的方式来寻求实现这点：&lt;/p>
&lt;p>&lt;strong>演示&lt;/strong> 首先，Raft 论文引入了一个描述在状态机复制上下文中基于 leader 选举的一致性的新抽象。 事实证明，这种务实的演示在工程师中非常受欢迎。&lt;/p>
&lt;p>&lt;strong>简单&lt;/strong> 其次，Raft 算法的优先考虑简洁性而不是性能。例如，Raft 按顺序决定日志条目而 Paxos 允许乱序决定，但需要额外的协议来填充可能出现的日志空隙。&lt;/p></description></item><item><title>Spark Papers</title><link>/article/2020/11/spark-papers/</link><pubDate>Fri, 13 Nov 2020 00:00:00 +0000</pubDate><guid>/article/2020/11/spark-papers/</guid><description>&lt;h2 id="spark-cluster-computing-with-working-sets">Spark: Cluster Computing with Working Sets&lt;/h2>
&lt;p>MapReduce （下称 MR）任务包含主要&lt;del>五&lt;/del>两个步骤：Map、&lt;del>Sort、Combine、Shuffle、&lt;/del> Reduce，每个 MR 任务在 Map 将数据阶段将数据转换成 K-V 的形式；Reduce 在不同的机器上作聚合运算。Shuffle 更是涉及到巨大的 I/O 操作（主要是网络 I/O）。每个 MR 任务最终会将计算结果写回存储系统。&lt;/p>
&lt;p>由于 MR 任务的最终结果会写回存储，那么有两种经典场景对于它来说是低效的：&lt;/p>
&lt;ol>
&lt;li>迭代任务（迭代机器学习算法）&lt;/li>
&lt;li>交互式数据分析工具&lt;/li>
&lt;/ol>
&lt;p>Spark 提出了 RDD (Resilient Distributed Dataset) 模型来处理此类问题。RDD 是一个被分布在一组机器上的只读的对象集，当一个分区丢失时 RDD 能够很快通过重新计算的方式来重建。RDD 能够被保存在内存中，并以类似 MR 的 &lt;em>并行&lt;/em>操作方式 得到重用。RDD 通过一种叫做 &lt;em>血统（lineage）&lt;/em> 的概念实现容错：如果 RDD 的一部分丢失了，那么 RDD 有足够的信息（该 RDD 是怎么从其他 RDD 计算出来的）来重建该部分。&lt;/p>
&lt;p>在 Spark 中，RDD 以 Scala 对象的形式存在。并且 RDD 能够通过以下几种形式构造出来：&lt;/p>
&lt;ol>
&lt;li>来自共享文件系统（如 HDFS）中的一个&lt;em>文件&lt;/em>&lt;/li>
&lt;li>&lt;em>并行化（parallelizing）&lt;/em> 一个 Scala 集合&lt;/li>
&lt;li>&lt;em>转化（transforming&lt;/em>）于一个已经存在的 RDD&lt;/li>
&lt;li>改变一个已存在 RDD 的&lt;em>持久性（persistence）&lt;/em>
&lt;ul>
&lt;li>&lt;em>cache&lt;/em>：将 RDD 暂存于内存以便稍后重用&lt;/li>
&lt;li>&lt;em>save&lt;/em>：将 RDD 存于类似 HDFS 的分布式文件系统&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>对于 &lt;em>cache&lt;/em> 这种情况来说，如果集群中没有足够的内存来缓存一个数据集（dataset）的所有部分，那么 Spark 会在使用它们时重新计算。&lt;/p></description></item><item><title>Week 20, 2020</title><link>/weekly/2020/05/17/week-20-2020/</link><pubDate>Sun, 17 May 2020 00:00:00 +0000</pubDate><guid>/weekly/2020/05/17/week-20-2020/</guid><description>&lt;p>删了一些无意义的周报，大量的空白意味着一周没有做任何有意义的事，也许这会让我感到一些焦虑。&lt;/p>
&lt;p>毕业论文写了5,000字左右，要求要达到15,000字。除此之外，还要求翻译一篇近五年的文献，想来近一个月没有翻译文章了，找时间把这篇&lt;a href="https://arxiv.org/abs/2004.05074">Paxos vs Raft: Have we reached consensus on distributed consensus?
&lt;/a>翻译一下。&lt;/p>
&lt;hr>
&lt;p>听相声熬死同行那一段，似乎在行业内资历/年龄大便是绝对正确。同时联想起在一个表演节目上陈道明与同为评委的青年人对集体主义和个人主义的的不同观点，支持集体主义的陈道明获得了许多人支持，另一个青年人“无力反驳”。当然，抛开立场和观点来说，任何人在行业巨擎之前，哪怕是有独立的相反观点，谁又能与其客观争论下去呢？这样的辩论仿佛变得毫无意义。&lt;/p>
&lt;p>到微博上看，支持LGBT的人仿佛正义的使者，对所有持相反观点的人恶语相向。“把无知当个性，把嘴臭当幽默。”凡事在政治正确的面前，一切理性和道德早已抛开。就事论事变成了满地打滚，自知理亏便撒娇打泼。“后浪们”在互联网上的素质展现的淋漓尽致，纵观整个中文互联网环境，凡是符合其利益，哪怕是违法行为也要被其包装称“英雄”。这一件事在之前在v2ex上就百度网盘事件上的讨论便能够看出。没等说两句话，小粉红、走资派、美分、公知的帽子便扣得飞起。&lt;/p>
&lt;p>如果非要给我贴标签的话，大概会给我贴一个歪屁股的奋斗逼。但谁又能想到我有多讨厌华为就有多喜欢战狼呢？&lt;/p></description></item><item><title>アジアに目を凝らす：もしも中国が大航海時代を制していたら</title><link>/reproduction/2020/04/if-china-had-commanded-the-age-of-discovery/</link><pubDate>Sun, 10 May 2020 00:00:00 +0000</pubDate><guid>/reproduction/2020/04/if-china-had-commanded-the-age-of-discovery/</guid><description>&lt;p>歴史に「もしも」はないという。確かに歴史は事実を重んじる学問であり、軽率な仮定は持ち込めないからだろう。しかし、僕は歴史学者ではない。未来を考える上で、歴史を糧にするなら、ふんだんに「もしも」を設定し、素朴な問いを発していくことでむしろ史実のリアリティをつかんでみたいと思う。また、そこから未来のストーリーを構想してみたいとも思うのだ。&lt;br>
だからここで仮説をひとつ。もしも、アジアあるいは中国が大航海時代を制し、西洋に先んじて産業革命をなしとげていたとしたら、世界の様相はどんな風に変わっていただろうか。&lt;/p>
&lt;p>&lt;img src="https://tei-ku.com/blog/asset/5/1.jpg" alt=""> &lt;br>
&lt;em>写真：akg-images/アフロ&lt;/em>&lt;br>
&lt;em>大航海時代の海図。欧州からインドへの航海の情熱が偲ばれる。『カンティーノ天面天球図』（1502）&lt;/em>&lt;/p>
&lt;p>たとえば、宋代の中国は、あらゆる意味において文明の先端にあった。紙の発明は漢の時代、紀元の前後の話であるが、書物として蓄えられた知を整理・体系化し、厳密な管理体制のもとでこれを刊行・流通させ、血筋や家柄によらず、知にアクセスできる環境を整えていたという点で、宋代の中国は抜きん出ていた。校閲や彫版印刷も緻密に組織化されて行われており、書物の印刷と流布に関しては世界のどこよりも質・量ともに充実していた。こうした状況を背景として科挙という試験制度に磨きをかけることで、抜きん出た頭脳や才能を官僚として登用することができたわけである。当時の国力とは、合理的な行・財政管理能力と武力を総合したものであるから、この時代の中国を凌駕する文明が簡単に出現するとは思われないほどに、制度の洗練度が突出していた。欧州はまだ印刷も書物の流通もない暗黒の中世であった。この時代に、もしも中国が海洋進出に興味を持っていたらどうだっただろう。羅針盤すなわち方位磁石はすでに中国で発明されており、宋代では航海にも用いられていたはずだ。&lt;br>
しかしながら、宋王朝は、北方の金に、そして蒙古にあっけなく滅ぼされてしまうのである。かわって中国の地をおさめた元王朝の時代には、日本にも二度、大船団を派遣している。またベトナムやジャワにも軍事遠征を行っており、勢力の拡大に意欲があったことをうかがわせるが、いずれも成功していない。元代にあっては、中国は属国の一つに過ぎず、制度は維持されたが大きな発展はなかった。ユーラシアははてしなく大きな大陸であり、ここに巨大な版図を得た元王朝は、内憂外患も数知れず、そこを守っていくのが精一杯だったのかもしれない。元は百年を待たないで力を失っていく。&lt;br>
ところが次の明代、特に永楽帝の時代には、海洋進出にとても熱が入るのである。皇帝の命によって、鄭和という武将が、大艦隊を率いて1405年から1433年まで、実に７回にわたって大航海を果たしている。鄭和という人物は、艦隊の統率者としてほぼその人生の全てを航海に投じている。艦隊の編成は240隻、2万７千人もの規模で、『明史』には、最大の船は全長137m、幅56m、重量8000t（ウィキペディア『鄭和』より）という巨大なものであったと記録されている。&lt;/p>
&lt;p>&lt;img src="https://tei-ku.com/blog/asset/5/2.jpg" alt="">&lt;br>
&lt;em>提供：Science Photo Library/アフロ&lt;/em>&lt;br>
&lt;em>明代、中国艦隊の図。鄭和に率いられた大艦隊は1405-1433年の間に、インド洋及び東南アジア沿岸を７回にわたって訪れ、一部はアフリカ東岸に達していた。&lt;/em>&lt;/p>
&lt;p>コロンブスの船団が約100人、船の大きさも６分の１程度であることを考えると、明の船団の規模は凄まじい。この船団はインド洋やアラビア海の諸国を訪れ、インドのカリカットへの到達は1498年のバスコ・ダ・ガマの到達よりも90年以上早い。そして４度目の航海では船団の一部はアフリカ東岸、現在のケニヤあたりまで到達したという。&lt;br>
ただ、明王朝の航海は、王朝の威光を遠方の国々にまで知らしめ、明に朝貢させるのが目的だったようで、略奪や直接統治を目指してはいなかった。この場合の朝貢とは、王朝の徳を敬い、貢物を捧げる国交関係をいう。植民地化や内政干渉を行うのではなく、そこにある体制のままに、宗主国に礼を尽くす序列関係を構築しようとする中華思想の現れである。朝貢によって貢物がもたらされた場合、宗主国である明は、回賜すなわち返礼品を、貢物の数倍から数十倍、持たせて帰したと言われている。したがって貿易で利を得るための航海ではなかったようだ。むしろ、回賜が追いつかず、朝貢制限を行ったというから微笑ましい。中華の面目を保つのも大変だったのだろう。したがって、明代の鄭和の大航海は、威厳と節度をもった海洋進出だったと言えるかもしれない。持ち帰ったものも、諸国の珍宝や「麒麟」「ライオン」「ダチョウ」「シマウマ」などの珍獣が記録されているそうで、その成果も微笑ましい。&lt;/p>
&lt;p>&lt;img src="https://tei-ku.com/blog/asset/5/3.jpg" alt="">&lt;br>
&lt;em>漢籍からの写しと言われている麒麟の図（19世紀）。EXPO 2005 AICHIカレンダー『高木春山／本草圖説』（2000）より部分。撮影：藤井保&lt;/em>&lt;/p>
&lt;p>大航海時代をリードしたポルトガルやスペインの場合は、オスマン・トルコによって地中海の交易を支配・制限され、海洋交易を他の海に求めざるを得なくなった両国が、王命で荒くれ者たちに一攫千金を奨励し、命がけの航海と引き換えに富と名声の獲得を許容した海洋進出であった。つまり国益を得るための大胆不敵なギャンブルであった。寄港先や食料補給地の確保など、進出への準備も、未知なる航路の開拓も、真剣勝負である。いきおいその方法は乱暴であることをまぬがれなかったと想像される。&lt;br>
もしも中国が、鄭和の跡を継ぐように、大船団による航海を重ねて、ついにはアフリカ最南端の喜望峰を越えるようなことがあったとしたら、どうだっただろう。そして明の大船団が、コロンブスよりも先にアメリカ大陸を発見し、マゼランの船団より先に、世界一周の航海を果たし、地球が丸いことを証明したとしたら、どんな世界になっていただろうか。&lt;br>
中華思想は基本的に居丈高であるが、必ずしも破壊的ではなかった。したがってインカ帝国も、マヤ文明も、アステカ王国も、中国に朝貢は求められただろうが、滅ぼされることはなかったかもしれないのである。&lt;br>
そしてもしも、明あるいは清王朝の時代に、産業革命が中国にもたらされていたとしたら、どうであっただろうか。世界のワインは、中国が欧州に展開する専売会社のもとで、おびただしい漢字がラベルに躍っている状況すらあったかもしれない。&lt;/p></description></item><item><title>Week 16, 2020</title><link>/weekly/2020/04/19/week-16-2020/</link><pubDate>Sun, 19 Apr 2020 00:00:00 +0000</pubDate><guid>/weekly/2020/04/19/week-16-2020/</guid><description>&lt;p>中文在计算机上的缺陷太大了，但是又不能完全舍弃中文输入法，所以我一直在寻找合适的输入法方式。非拉丁语系中，韩语的写法、读法及其相似：&lt;/p>
&lt;pre tabindex="0">&lt;code>곤란	골란	kollan	困難
&lt;/code>&lt;/pre>&lt;p>而且重码率低。&lt;/p>
&lt;p>日韩两国在输入汉语时会使用郑码，因此也作为国际通用码。台湾使用注音输入法，是因为在台湾注音符号得到很大推广，就像在大陆的拼音一样。此外还有仓颉、双拼的输入形式。&lt;/p>
&lt;p>而常用的全拼输入法，重码率最高，输入字母数最多。但因为拼音在大陆的推广程度最高，使用人数最多（我爷爷还是后来自学的）。程序员群体有一部分选择了双拼的输入形式，但重码率达不到最低。我想要的是重码率最低，不需要选词，接近于英文输入的输入形式。但是郑码在平台兼容性上不如五笔，所以暂时选择五笔输入。多数字词不用选择直接上屏，爽！&lt;/p></description></item><item><title>Is Redlock safe?</title><link>/translation/2020/04/04/is-redlock-safe/</link><pubDate>Sat, 04 Apr 2020 00:00:00 +0000</pubDate><guid>/translation/2020/04/04/is-redlock-safe/</guid><description>&lt;p>分布式系统研究者 Martin Kleppmann 昨天发布了一篇 Redlock[1]的分析文章[2]。&lt;/p>
&lt;p>Redlock 是我设计用于 Redis 的客户端分布式锁定算法。该算法编排了一组客户端节点，这些节点实现了具有特定功能的数据存储，以便创建一个多主容错的、安全的、具有自动释放功能的分布式锁。
你可以使用 MySQL 而非 Redis 来实现 Redlock。&lt;/p>
&lt;p>该算法的目的是将那些还在使用单点 Redis 还有带有故障转移的主从设置的人员转移到更可靠、更安全的方法上来实现分布式锁。该方法具有非常低的复杂性和良好的性能。&lt;/p>
&lt;p>自从我发布 Redlock 以来，人们就以多种语言实现了该功能并将其用于不同的目的。&lt;/p>
&lt;p>Martin 对这个算法的分析结论是 Redlock 不安全。我在最初的 Redis 规范[3]中请求帮助分析，很高兴 Martin 发布了一个分析文章。非常感谢 Martin，尽管我不同意他的观点。好处是，与其他编程领域不同，分布式系统在数学上是非黑即白的。因此，某种算法要么可以保证给定的属性集，要么在某些假设下算法可能会无法保证它们。在此分析中，我将分析 Martin 的分析，以便该领域的其他专家可以检查这两个文档（分析和反分析），最终我们可以了解 Redlock 是否被认为是安全的。&lt;/p>
&lt;h2 id="为什么-martin-认为-redlock-不安全">为什么 Martin 认为 Redlock 不安全&lt;/h2>
&lt;p>分析中的论点主要有两个：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>具有自动释放特性的分布式锁（互斥锁属性只在锁被获取后的固定时间内有效）需要一种方法来避免客户端在过期时间后使用锁时引发的问题，这违反了访问共享资源时的互斥性。Martin 说 Redlock 没有这样的机制。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Martin 说，不管问题1如何，这个算法本质上是不安全的，因为它对系统模型做出的假设在实际系统中无法得到保证。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>为了清楚起见，我将从第一个问题开始，分别讨论这两个问题。&lt;/p>
&lt;h2 id="分布式锁自动释放和令牌">分布式锁、自动释放和令牌&lt;/h2>
&lt;p>没有自动释放机制（锁的拥有者将无限期地持有它）的分布式锁基本上是没用的。如果持有锁的客户端崩溃，并且在短时间内无法恢复到完全状态，就会导致死锁，因为分布式锁试图保护的共享资源永远无法访问。这就产生了一个在大多数情况下都无法接受的活性问题，所以一个正常的分布式锁必须能够自动释放自己。&lt;/p>
&lt;p>实际上锁提供给客户端最长的生存时间。在过期时间之后，互斥保证（锁的&lt;em>主要&lt;/em>属性）就没有了：另一个客户端可能已经有了锁。如果两个客户端在两个不同的时间获得锁，但第一个因为 GC 暂停或其他调度问题非常慢，会尝试与获得锁第二个客户端在共享资源的情况下同时工作吗？&lt;/p>
&lt;p>Martin 说，通过让分布式锁服务器为每个锁提供令牌可以避免此问题。在他的示例中，令牌只是保证始终递增的数字。Martin 使用令牌的理由是：当两个不同的客户端同时访问锁定的资源时，我们可以在数据库写入事务时使用令牌（假定可以实现客户端所做的工作）：只有具有最大锁号的客户端才可以写入数据库。&lt;/p>
&lt;p>用 Martin 的话来说：&lt;/p>
&lt;p>“这种问题的解决方案非常简单：你需要在每个对存储服务的请求中携带一个 fencing token。在此情况下，一个 fencing token 只是一个客户端获得一次锁时递增的数字（如被锁服务递增）。”&lt;/p>
&lt;p>&amp;hellip;&lt;/p>
&lt;p>“这需要存储服务在检查 token 中扮演一个重要的角色，并且拒绝任何旧 token 的所有写请求。”&lt;/p></description></item><item><title>Google File System</title><link>/article/2020/03/google-file-system/</link><pubDate>Sun, 29 Mar 2020 00:00:00 +0000</pubDate><guid>/article/2020/03/google-file-system/</guid><description>&lt;p>GFS 是谷歌开发的分布式文件系统，也是上一篇 &lt;a href="../google-map-reduce/">MapReduce&lt;/a> 最终输出文件的存放位置。&lt;/p>
&lt;h2 id="设计概述">设计概述&lt;/h2>
&lt;p>以下内容简述了 GFS 的设计架构。包括系统的的细节，以及如此设计的原因。&lt;/p>
&lt;h3 id="假设">假设&lt;/h3>
&lt;p>该系统在以下前提设计实现：&lt;/p>
&lt;ul>
&lt;li>该系统由许多机器组成，这些机器经常会出错。所以系统必须持续检测以便能够检查、容忍错误，并且能够恢复回来。&lt;/li>
&lt;li>该系统支持小型文件，但是不会对其作出优化。&lt;/li>
&lt;li>关注性能的应用经常对一批读操作进行排序，以便提高性能。&lt;/li>
&lt;li>在文件写入之后，很少会再次修改。&lt;/li>
&lt;li>系统必须高效地处理好并发问题。&lt;/li>
&lt;li>高且平稳的带宽比低延迟重要。&lt;/li>
&lt;/ul>
&lt;h3 id="接口">接口&lt;/h3>
&lt;p>GFS 提供了和文件系统类似的接口。文件以文件路径名严格组织。除了传统的 CRUD 之外，GFS 还提供了快照和 record append。快照能高效地复制一个文件或目录，record append 用来解决多个客户端的并发问题。&lt;/p>
&lt;h3 id="架构">架构&lt;/h3>
&lt;p>一个 GFS 集群包括一个 master 和多个 chunkserver，同时 master 可以被多个 client 访问到。如图一。
文件通常被分为固定大小的 &lt;em>chunk&lt;/em> 。在 chunk 被创建时，master 分配给它一个64位全局常量 &lt;em>chunk handle&lt;/em> 。
chunkserver 将 chunk 作为 linux 文件存储在本地磁盘，并且根据 chunk handle 和字节区间进行读写。每个 chunk 在多个 chunkserver 上都有冗余。&lt;/p>
&lt;p>&lt;img src="/pic/post/2020/03/google-file-system-1.png" alt="architecture">&lt;/p>
&lt;p>master 上保存了所有文件系统的元数据。包括命名空间，访问控制信息，文件到 chunk 的映射和 chunk 的位置。也控制像 chunk 租约，孤儿 chunk 的 GC，chunkserver 之间的 chunk 迁移等系统活动。master 还定期向 chunkserver 发送心跳包收集其状态。
client 与 master 交互来操作元数据，而对数据的操作直接与 chunkserver 通信。
client 和 chunkserver 都不缓存文件数据。一般对客户端来说，文件都太大了。而得益于 linux buffer cache，chunkserver 也不用再做缓存了（linux 会将访问的磁盘文件缓存在内存里）。&lt;/p></description></item><item><title>Google MapReduce</title><link>/article/2020/03/google-map-reduce/</link><pubDate>Fri, 20 Mar 2020 00:00:00 +0000</pubDate><guid>/article/2020/03/google-map-reduce/</guid><description>&lt;p>无论是出于对分布式系统的兴趣，还是对一个未来的 Hadooper 来说，这篇论文都值得一读。号称为 Google “三驾马车”之一，同时也作为6.824 LEC 1的 preparation, 其重要性也随之体现。趁着时间充裕，抓紧读了读并尝试着手进行后面的 lab。&lt;/p>
&lt;h2 id="概念">概念&lt;/h2>
&lt;p>Google 提出了一种 Map-Reduce 的模型。&lt;strong>map 将一对键值对处理成另外一组中间键值对， reduce 将这些中间键值对中 key 相同的合并起来。&lt;/strong> 系统关注的除了处理数据本身之外，还有调度机器之间程序的运行、处理机器故障以及管理机器之间的通信。&lt;/p>
&lt;h2 id="编程模型">编程模型&lt;/h2>
&lt;p>就如前面提到的，用户编写的 Map 将所有的输入处理成中间状态的键值对，MapReduce 根据中间状态的 Key 将其整理到一起（因为数据在不同的机器上），并将其交给 Reduce。&lt;/p>
&lt;p>之后，同样是用户编写的 Reduce 将 Key 相同的中间键值对合并到一起。合并的数据集可能只是一小部分。&lt;/p>
&lt;p>下面是一个单词计数的例子：&lt;/p>
&lt;pre tabindex="0">&lt;code>map (String key, String value)
 // key document name
 // value document content
 for each word w int value:
 EmitIntermediate (w, &amp;#34;1&amp;#34;);

reduce (String key, Iterator value)
 // key a word
 // values a list of counts
 int result = 0;
 for each v in values:
 result += ParseInt (v);
 Emit(AsString (result));
&lt;/code>&lt;/pre>&lt;p>map 函数将出现过的单词与其出现过的次数相关联，这里是1。 reduce 函数将相同单词出现的次数求和。&lt;/p></description></item><item><title>Week 10, 2020</title><link>/weekly/2020/03/08/week-10-2020/</link><pubDate>Sun, 08 Mar 2020 00:00:00 +0000</pubDate><guid>/weekly/2020/03/08/week-10-2020/</guid><description>&lt;p>I am in a dilemma at learning rust or golang, which I know a litte for the sake of labs. Matering in a specific language or, broading my skill stack is an equivalent puzzle. I have too little vigor to dig into much knowledge, like what Chuang Tzu said,&lt;/p>
&lt;blockquote>
&lt;p>&amp;ldquo;吾生也有涯，而知也无涯。以有涯隨无涯，殆已；已而為知者，殆而已矣。為善无近名，為惡無近刑。緣督以為經，可以保身，可以全生，可以養親，可以盡年^[/reproduction/2020/03/the-fundamentals-for-the-cultivation-of-life/]。&amp;rdquo;&lt;/p>&lt;/blockquote>
&lt;p>Though do not agree with part of the view of Chuang Tzu, I must admit no one can gain all knowledge in the world. What I can do is just keep learning, which brings me pleasure.&lt;/p></description></item><item><title>莊子/內篇/養生主第三</title><link>/reproduction/2020/03/the-fundamentals-for-the-cultivation-of-life/</link><pubDate>Fri, 06 Mar 2020 00:00:00 +0000</pubDate><guid>/reproduction/2020/03/the-fundamentals-for-the-cultivation-of-life/</guid><description>&lt;p>　　吾生也有涯，而知也无涯。以有涯隨无涯，殆已；已而為知者，殆而已矣。為善无近名，為惡無近刑。緣督以為經，可以保身，可以全生，可以養親，可以盡年。&lt;/p>
&lt;p>　　庖丁為文惠君解牛，手之所觸，肩之所倚，足之所履，膝之所踦，砉然嚮然，奏刀騞然，莫不中音。合於桑林之舞，乃中經首之會。&lt;/p>
&lt;p>　　文惠君曰：「嘻，善哉！技蓋至此乎？」&lt;/p>
&lt;p>　　庖丁釋刀對曰：「臣之所好者，道也，進乎技矣。始臣之解牛之時，所見无非全牛者。三年之後，未嘗見全牛也。方今之時，臣以神遇而不以目視，官知止而神欲行。依乎天理，批大郤，導大窾，因其固然。技經肯綮之未嘗，而況大軱乎！良庖歲更刀，割也；族庖月更刀，折也。今臣之刀十九年矣，所解數千牛矣，而刀刃若新發於硎。彼節者有間，而刀刃者无厚；以无厚入有間，恢恢乎其於遊刃必有餘地矣，是以十九年而刀刃若新發於硎。雖然，每至於族，吾見其難為，怵然為戒，視為止，行為遲。動刀甚微，謋然以解，如土委地。提刀而立，為之四顧，為之躊躇滿志，善刀而藏之。」&lt;/p>
&lt;p>　　文惠君曰：「善哉！吾聞庖丁之言，得養生焉。」&lt;/p>
&lt;p>　　公文軒見右師而驚曰：「是何人也？惡乎介也？天與，其人與？」曰：「天也，非人也。天之生是使獨也，人之貌有與也。以是知其天也，非人也。」&lt;/p>
&lt;p>　　澤雉十步一啄，百步一飲，不蘄畜乎樊中。神雖王，不善也。&lt;/p>
&lt;p>　　老聃死，秦失弔之，三號而出。&lt;/p>
&lt;p>　　弟子曰：「非夫子之友邪？」&lt;/p>
&lt;p>　　曰：「然。」&lt;/p>
&lt;p>　　「然則弔焉若此，可乎？」&lt;/p>
&lt;p>　　曰：「然。始也吾以為其人也，而今非也。向吾入而弔焉，有老者哭之，如哭其子；少者哭之，如哭其母。彼其所以會之，必有不蘄言而言，不蘄哭而哭者，是遁天倍情，忘其所受，古者謂之遁天之刑。適來，夫子時也；適去，夫子順也。安時而處順，哀樂不能入也，古者謂是帝之縣解。」&lt;/p>
&lt;p>　　指窮於為薪，火傳也，不知其盡也。&lt;/p></description></item><item><title>Week 9, 2020</title><link>/weekly/2020/03/01/week-9-2020/</link><pubDate>Sun, 01 Mar 2020 00:00:00 +0000</pubDate><guid>/weekly/2020/03/01/week-9-2020/</guid><description>&lt;p>I&amp;rsquo;m thinking about pausing the daily algorithms but starting the weekly contest&amp;hellip;just thinking.&lt;/p>
&lt;p>I sware it is my last time to shut down my process on android development, spending time on meaningful aspects is my future task.&lt;/p>
&lt;p>It was my first practice on TDD and got a lot of improvement in programming skills. This can help me write robust code and prevent myself from waterfall-like midification. Later days from now, though dislike but must write some front-end code to complete my task distributed by my company.&lt;/p></description></item><item><title>Week 8, 2020</title><link>/weekly/2020/02/23/week-8-2020/</link><pubDate>Sun, 23 Feb 2020 00:00:00 +0000</pubDate><guid>/weekly/2020/02/23/week-8-2020/</guid><description>&lt;p>Approached to 100 solutions in this phase, I feel a bit bored with the leetcode problems. As what I want to handle with is the project something like infrastructure, platform&amp;hellip;With the ending up the development of service for a Android application, a conclusion was drawed: I hate monotonous crud bussiness. It is always a good symbol to find ones ambiton like what the motto in the homepage goes:&lt;/p>
&lt;blockquote>
&lt;p>Adhere to the technological belief, be pragmatic, self-motivated, take responsibility to the end and fulfill others.&lt;/p></description></item><item><title>Week 7, 2020</title><link>/weekly/2020/02/16/week-7-2020/</link><pubDate>Sun, 16 Feb 2020 00:00:00 +0000</pubDate><guid>/weekly/2020/02/16/week-7-2020/</guid><description>&lt;p>Till now 89 problems in leetcode were sloved in this phase, 7 in this week as usual.&lt;/p>
&lt;p>MIT 6.824: Distributed Systems requires a precondition that reading through the Google MapReduce paper. I finished it and ready to start this course. The CMU 15-213 course was put on hold because I have some basic related and now former is an emphasis.&lt;/p>
&lt;p>These days I wrote some bussiness code that makes me collapse. Cumbersome unit tests are meaningful but I really don&amp;rsquo;t want to deal with them.&lt;/p></description></item><item><title>Solution for switching between lowercase and Chinese pinyin with Caps Lock in Jetbrains IDEs</title><link>/article/2020/02/solution-for-switching-pinyin-ime-state-in-jbs/</link><pubDate>Wed, 12 Feb 2020 00:00:00 +0000</pubDate><guid>/article/2020/02/solution-for-switching-pinyin-ime-state-in-jbs/</guid><description>&lt;p>TL;DR:&lt;/p>
&lt;p>Add &lt;code>TICapsLockLanguageSwitchCapable - true&lt;/code> to your input method&amp;rsquo;s Info.plist[1]&lt;/p>
&lt;h2 id="background">Background&lt;/h2>
&lt;p>Last month I encountered a problem with Chinese input method (Rime, Baidu, Sogou, etc), the symptoms is that I couldn&amp;rsquo;t switch between pinyin and lowercase letters with the Caps Lock which can pressed by my little finger in Jetbrains IDEs, which has been my habit since I used macOS.&lt;/p>
&lt;p>Before using third-party input methods, it works well with apple pinyin method. But the restriction of it drives me to seek any other IMEs. Rime is a good choice which fits the need of programmers but something of cloud is one of the shortcomings. But none of these is a obstacle except the defect that switching between English and Chinese. My Rime&amp;rsquo;s configuration is something like:&lt;/p></description></item><item><title>Week 6, 2020</title><link>/weekly/2020/02/09/week-6-2020/</link><pubDate>Sun, 09 Feb 2020 00:00:00 +0000</pubDate><guid>/weekly/2020/02/09/week-6-2020/</guid><description>&lt;p>It is a milestone for me to build my site with English, which inspires me to improve my level at this language. Ever after now, I write articles in English, twitte in English and read original professional articles (what I have done, in fact).&lt;/p>
&lt;p>This week, I&lt;/p>
&lt;ul>
&lt;li>sloved 7 algorithm questions in leetcode, 81 questions totally this phase.&lt;/li>
&lt;li>translated 2 articles, one for distributed systems, one for experience of learning english.&lt;/li>
&lt;li>released my first public application for Douban FM, which only had 2 downloads till now.
&lt;ul>
&lt;li>it was a tough work to build Windows app on macOS, a electron-builder docker image helps me a lot.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>totally modified my blog&amp;rsquo;s theme, made it seem like an english blog.&lt;/li>
&lt;li>discussed with other developers at Hacker News or other sites.&lt;/li>
&lt;li>migrated from Chrome to Edge with chromium kernel.&lt;/li>
&lt;/ul>
&lt;p>I am thinking about whether translating my posts before into english or not. The faith of writing brilliant articles was insisted in my heart but, more articles and publications should be absorbed.&lt;/p></description></item><item><title>English has been my pain for 15 years</title><link>/translation/2020/02/04/english-has-been-my-pain-for-15-years/</link><pubDate>Tue, 04 Feb 2020 00:00:00 +0000</pubDate><guid>/translation/2020/02/04/english-has-been-my-pain-for-15-years/</guid><description>&lt;p>Paul Graham 提出了一个很重要的问题：英语作为 IT 工作者的必备语言之一，始终受新闻站点和软件开发者的关注[1]。当他提到“外国口音”时引起了很大的争议，因为互联网上到处都是看热闹不嫌事大的人，但这是问题中最无聊的部分，因此我将跳过这一部分。重要的是，通常没有人会谈论“英语问题”，而一想到这点我总是感到有点孤独，就像是这是一个只影响我一个人的问题似的，所以我想在这篇文章中分享我有关学习英语的经历。&lt;/p>
&lt;h2 id="一个长故事">一个长故事&lt;/h2>
&lt;p>回到1998年，我一直记得当时我们正在研究一个网络攻击，我和 &lt;a href="http://www.isg.rhul.ac.uk/sullivan/">sullivan&lt;/a> 在我米兰的家中喝醉了之后，把我们得到的可怜的结果发布在了 &lt;a href="http://seclists.org/bugtraq/1998/Dec/79">BUGTRAQ 用户能够理解的帖子&lt;/a>中。&lt;/p>
&lt;p>请注意第二句中的 “Instead all others”。虽然现在我的英语水平也不高，但是我确实在15年中有所进步，而且 sullivan 现在在美国和英国的大学任教，所以我认为他有一口非常流利的英语（剧透警告：我并没有）。但是重点是：我们正在进行研究新的 TCP/IP 攻击，但是我们无法用英语撰写关于这个技术的文章。在1998年，我无法沟通这一事实就已经使我感到举步维艰，如果我不花很多精力的话就无法阅读用英语撰写的技术文档，所以我用了大脑50％的精力的单纯用来读，而剩下的精力用来理解我正在读什么。&lt;/p>
&lt;p>但是我一直认为英语是个好东西。我总建议人们不要翻译技术的主题，因为我认为有一个通用的语言来注释源码会更好，并且实际上对于大多数人来说，理解用英语写的技术文档非常简单。&lt;/p>
&lt;p>因此，从1998年开始，我逐渐学会了流利地阅读英语，与阅读意大利语相比无需付出更多的努力。
我甚至能够用意大利语写东西的速度来写英语，虽然这只达到了最低的标准，就如你在阅读这篇文章时所看到的：基本上，我学会了非常快地写一小段英语，虽然通常不足以表达我在编程领域的想法，但是写一般的主题已经足够了。我不知道大多数厨房里的物件对应的单词，也不会表达复杂句子、假设结构的语法。但是现在，我可以轻松地就自己最关心的主题进行交流，并且其他人可以或多或少地理解我写的内容，因此需要提高英语的压力大大减轻了……但是，我最近发现，这只是我遇到的次要问题。&lt;/p>
&lt;h2 id="欧式英语有趣的语言">欧式英语，有趣的语言&lt;/h2>
&lt;p>尽管我最终能够在写作和阅读方面达到自己的要求，但是我几乎从未在一个讲英语的国家体验过真正的交流。在此之前，我总是与其他欧洲（除了英国）人一起使用英语交流，例如法国，德国和西班牙人。&lt;/p>
&lt;p>现在这些国家/地区使用的英语是在英语学校上课时使用的英语&amp;hellip;从语音上讲，它几乎与美国或英国英语无关。他们说这是“BBC英语”，但实际上不是。这是使用英国英语语法而在语音上大大简化的英语。&lt;/p>
&lt;p>&lt;strong>那个&lt;/strong>版本的英语，实际上能让世界各地的人们都可以轻松交流。基本语法很容易掌握，几个月的练习后就可以进行交谈。在欧洲所有非英语国家中，单词的发音几乎相同，因此效果很好。&lt;/p>
&lt;p>只有一个问题，它与在英国，美国，加拿大和其他以英语为母语的国家/地区所说的英语一点关系也没有。&lt;/p>
&lt;h2 id="毕竟英语有点蹩脚">毕竟，英语有点蹩脚&lt;/h2>
&lt;p>现在我要告诉你们一个秘密，除了没有人在英语与世界对比的语境中说：从语音上讲，英语是一种支离破碎的语言，其他的都不是秘密[2]。在意大利，我们历史悠久，但政治统一很晚。不同地区使用不同的方言，人们的口音非常重。在1950年“电视语言统一”之前，每个人都在说“方言”，而意大利语只被一小部分人掌握。&lt;a href="http://en.wikipedia.org/wiki/Sicilian_language">西西里语&lt;/a>是我们家族说得最多的语言，它比意大利语要早几个世纪。&lt;/p>
&lt;p>尽管如此，所有人都能听得懂另一个地区甚至是瑞士人说的话。意大利语在语音上是世界上最简单的语言之一，而且充满了冗余。事实上，它的信息熵很低，通常单词很长，每个单词中都有辅音和声母的很好的混合。一个单词的发音没有特别的规则，如果你知道每个字母的发音和一些特殊的字母组合的声音，比如“gl&lt;vocal>”，“sc&lt;vocal>”，你第一次读它们基本上就可以99.9%地正确发音。&lt;/p>
&lt;p>来自不同英语国家的人在交流方面存在问题，这一点已经充分说明了英语语音有多么奇怪。例如，对我和其他许多非英语母语人士来说，很难理解一个英国人到底在说些什么，而听懂北美人通常要简单得多。&lt;/p>
&lt;p>对我来说，正是由于英语的这种“特点”，我的问题不仅仅在于我的口音，而是能够理解人们在说什么。如果我付出足够的努力，口音根本不算是个问题。恕我直言，Paul Graham 提到的“口音”问题是英美人在这方面的一种消极态度，嗨，伙计们，你不了解我们，我们也听不懂你说的话，很难找到“只要你的理解力很有限，就会试图减慢对话的速度”这样的人。即使我说我听不懂，他们也会以光速的重复同样的话。&lt;/p>
&lt;h2 id="第一次接触书面英语是致命的">第一次接触书面英语是致命的&lt;/h2>
&lt;p>在我看来，学习英语如此缓慢的一个原因是从未听过英语就开始阅读英语。我的大脑充满了文字和有趣的声音之间的关联，而这些关联在实际语言中是不存在的。我的建议是，如果你现在正在学习英语，尽快开始听英语口语。&lt;/p>
&lt;p>osx 的 “say” 程序是一个很好的助手，它能够以一种合适的方式说出大多数英语单词。学习一个新单词一定要先学习它的发音。&lt;/p>
&lt;h2 id="内向还是外向">内向还是外向？&lt;/h2>
&lt;p>在我的英语学习经历中，最令我震惊的一件事是，不精通一门语言会让你变成一个内向的人。我是一个性格外向的人，在意大利那里大多数人都是性格外向的，在西西里岛那里有更多的性格外向的人，在我的家庭里大部分人都是性格外向的人。我认为我是一个有点惹人注意的人（我希望我不是，但是实际上我是一个非常外向的人）。现在由于沟通障碍，当我必须用英语交谈时，我就不是一个外向的人了，每次我去开会或被介绍给别人时，我都会感到后悔。这是一场噩梦。&lt;/p>
&lt;h2 id="为时已晚让我们学习英语吧">为时已晚，让我们学习英语吧&lt;/h2>
&lt;p>我认为英语只是语法上简单，但作为通用语言不是好的选择。但是事实是它已经赢了，已经改变不了了，更好地讲英语是一个好主意，即使这意味着要付出很多努力。这就是我自己在做的事，我正在努力改变。&lt;/p>
&lt;p>我发现自己确实需要提高英语水平的另一个原因是，十年后，我可能不再会专业编写代码，而合理的选择是转换到 IT 的管理方面，或者去掌管不用写很多代码的大型项目。如果你认为作为开发人员需要会英语的话，那么即使在传统的 IT 公司的其他部门工作，也需要会更多的英语，即使“只是”要管理许多程序员。&lt;/p>
&lt;p>但是以英语为母语的人应该真正意识到，很多人正在认真学习一种难学的语言：这不是一种爱好，掌握英语是很多人为简化沟通作出的很大努力。只要停止交谈/聆听几周英语，就要重新学了。&lt;/p>
&lt;p>我的长期愿望是，不同的口音迟早会融合成一种标准的、易于理解的口音，让说英语的人可以把它作为一种通用语言。&lt;/p>
&lt;hr>
&lt;p>[1] &lt;a href="http://paulgraham.com/accents.html">http://paulgraham.com/accents.html&lt;/a>&lt;br>
[2] Now I&amp;rsquo;ve a secret for you, that is everything but a secret except nobody says it in the context of English VS The World: English is a broken language, phonetically.&lt;/p></description></item><item><title>How to do distributed locking</title><link>/translation/2020/02/03/how-to-do-distributed-locking/</link><pubDate>Mon, 03 Feb 2020 00:00:00 +0000</pubDate><guid>/translation/2020/02/03/how-to-do-distributed-locking/</guid><description>&lt;p>我在 &lt;a href="http://redis.io/">Redis&lt;/a> 的官网上偶然发现了一个叫做 &lt;a href="http://redis.io/topics/distlock%5D">Redlock&lt;/a> 的算法，恰好与&lt;a href="http://dataintensive.net/">我的书&lt;/a>研究的一部分相关。这个算法自称能在 Redis 上实现容错的分布式锁（准确地说是&lt;a href="https://www.semanticscholar.org/paper/Leases%3A-an-efficient-fault-tolerant-mechanism-for-Gray-Cheriton/8965057405c1de742346eba16f20eaca2612f576">租约&lt;/a>[1]），并向研究分布式系统的人征求意见。看见这个算法，我出于本能地在脑海里敲响了警钟，所以我花了些时间来思考并且写下了这些笔记。&lt;/p>
&lt;p>因为&lt;a href="https://redis.io/topics/distlock">已经有十多个 Redlock 的实现&lt;/a>了，并且我们不知道谁已经使用这个算法了。所以我认为值得把我的笔记公开分享出来。我不会深入探讨 Redis 的其他部分，因为那些已经在&lt;a href="https://aphyr.com/tags/Redis">其他地方&lt;/a>讨论过了。&lt;/p>
&lt;p>在我深入 Redlock 的细节之前，首先要声明我十分喜欢 Redis，并且已经在生产环境中成功地使用过它了。我认为它非常适合在服务器之间共享一些频繁变化的数据，而且偶尔丢失部分数据也无关紧要。例如，维护每个 IP 地址的请求计数器（出于限制的目的）和每个用户 ID 的不同 IP 地址集（用于滥用的检测）。&lt;/p>
&lt;p>然而，Redis 已经逐渐进入有强一致性和持久性特点的数据管理领域，这让我很担心，因为这不是 Redis 设计的初衷。有争议的是，分布式锁也属于这一领域。让我们更详细地研究一下。&lt;/p>
&lt;h2 id="你用锁来干什么">你用锁来干什么&lt;/h2>
&lt;p>锁的目的是用来保证当多个节点尝试做相同的工作时，实际上只有一个节点能够完成（至少在同一时刻只有一个）。这个工作可能是将一些数据写入一个共享的存储系统、完成一些计算、调用一些外部的 API 或者其他类似的工作。宏观上来看，有两个原因来说明为什么在一个分布式应用中需要一个锁：&lt;a href="http://research.google.com/archive/chubby.html">效率和正确性&lt;/a>[2]。为了区别这些情况，可以继续往下看当锁失效的时候会发生什么：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>效率&lt;/strong>：使用锁可以避免做不必要的重复工作（例如一些代价昂贵的计算）。如果锁失效时两个节点做相同的工作，结果会是成本略有增加（最后要比其他方式多给 AWS 支付5美分）或带来小小的不便（用户可能会收到两个相同的邮件通知）。&lt;/li>
&lt;li>&lt;strong>正确性&lt;/strong>：使用锁可以避免并发进程相互影响最终搞乱系统的状态。如果锁失效时两个节点同时处理同一部分数据，结果可能造成文件损坏、数据丢失、永久的不一致性、给病人服用了错误剂量的药物或其他严重的问题。&lt;/li>
&lt;/ul>
&lt;p>以上两点都是需要锁的有效情况，但是你需要十分明确你是在处理哪一种情况。&lt;/p>
&lt;p>我的观点是：如果只是出于提高效率的目的，那么没有必要承担 Redlock 的成本和复杂的逻辑，你没必要运行5台 Redis 实例来检查是否有大多数都获得了锁。你最好只启动一个 Redis 实例，或是当主节点崩溃时异步复制到从节点。&lt;/p>
&lt;p>如果你使用单个 Redis 实例，在 Redis 节点断电时当然会丢失一些锁，同时可能会出现一些问题。但是如果你使用这些锁来优化效率的话，其实节点的崩溃不会频繁发生，这也没什么大不了。这个“没什么大不了”的正是 Redis 的特点。至少当你依赖于一个 Redis 实例的时候，每个查看系统的人都心知肚明这些锁不太严谨，仅用于不太关键的目的。&lt;/p>
&lt;p>另一方面，具有5个副本和多数投票的 Redis 算法乍一看似乎适用于对&lt;strong>正确性&lt;/strong>要求很高的情况。在接下来的几个章节中我将论证它&lt;strong>不&lt;/strong>适用于这个目的。文章的其余部分假定你的锁对保障系统的正确性至关重要，并且两个节点持有同一个锁是严重的错误。&lt;/p>
&lt;h2 id="使用锁来保护资源">使用锁来保护资源&lt;/h2>
&lt;p>先把 Redlock 的具体应用放在一边，讨论一下通常一个分布式锁是如何使用的（不依赖于某个加锁算法）。要牢记住分布式系统中的锁和多线程应用中的互斥量不一样，这一点很重要。由于不同的节点和网络都能以各种奇葩的方式发生故障，所以它更让人觉得可怕。&lt;/p>
&lt;p>假如你有一个应用，其中客户端需要更新共享存储中的文件（如 HDFS 或 S3）。一个客户端首先获得一个锁，然后读取这个文件，作出一个修改，将改动写回，最终释放这个锁。这个锁避免两个客户端并发执行读-修改-写这一系列动作以防丢失更新。代码可能像下面这样：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// THIS CODE IS BROKEN
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>function writeData(filename, &lt;span style="color:#66d9ef">data&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> lock = lockService.acquireLock(filename);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (!lock) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">throw&lt;/span> &lt;span style="color:#e6db74">&amp;#34;Failed to acquire lock&amp;#34;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> file = storage.readFile(filename);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> updated = updateContents(&lt;span style="color:#66d9ef">file&lt;/span>, &lt;span style="color:#66d9ef">data&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> storage.writeFile(filename, updated);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#66d9ef">finally&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> lock.release();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>不幸的是，即使你写的锁看起来非常完美，上面的代码也不是安全的。下面的图展示了数据是怎么被破坏的：&lt;/p></description></item><item><title>A note of android reverse engineering</title><link>/article/2020/02/reverse-engineering/</link><pubDate>Sat, 01 Feb 2020 00:00:00 +0000</pubDate><guid>/article/2020/02/reverse-engineering/</guid><description>&lt;h2 id="起因">起因&lt;/h2>
&lt;p>凌晨在 QQ 空间看到一个同校同学发布了一款 App，正在邀请别人参加内测。正巧最近我也在帮朋友写一个小应用，便下载来研究一下。应用的主题很常见，主打校内论坛、交友功能，大概猜到是怎么回事，还是先抓包看看吧。&lt;/p>
&lt;h2 id="抓包">抓包&lt;/h2>
&lt;p>Charles 这个工具就不用说了，基本抓过包的朋友都用过。不过想要抓手机应用，前提要求手机和电脑在一个局域网络中。设置代理和安装证书这两个步骤很容易找到教程，这里不再赘述。需要注意的是 Android 7 以后按谷歌要求需要额外修改 APP 的网络安全性配置，我这里参考这篇文章 [1] 得以解决。&lt;/p>
&lt;p>抓到包之后看了一眼 Request 和 Response 格式，看上去不太规范。而且虽然加入了 token，但是很多接口没有鉴权，拿到接口直接请求就能修改所有用户的资料。由于是内测，我将开发者的昵称修改以提示其漏洞，同时也在内测群里反馈了，截止目前接口还没有修改。除此之外，修改密码等接口中的密码竟然是明文传输的，这让我不能不担心是否在数据库中也是明文存储密码？于是诞生了 hack 进数据库的想法。&lt;/p>
&lt;h2 id="调研">调研&lt;/h2>
&lt;p>在处理数据库相关问题之前，先判断出其应用的技术栈。后端是拿 php 写的，而据我所知 php 框架经常爆出漏洞，在此基础之上发现是 thinkphp v5.0.24，而此版本已将漏洞修复了。此外又发现服务器上安装了宝塔面板，开发者开启了安全登录入口，默认的后台地址被修改了，这条路径也只能放弃了。&lt;/p>
&lt;h2 id="撞库">撞库&lt;/h2>
&lt;p>我之前没有接触过安全方面的技术，但是最简单的撞库的思想还是有的。在网上找了一些密码字典，一共包括5000多个常用的密码，用 hydra[2] 暴力撞库，但是失败了。&lt;/p>
&lt;h2 id="sql-注入">SQL 注入&lt;/h2>
&lt;p>撞库失败后联想到 SQL 注入的方式，找到了 sqlmap[3] 这个工具。拿几个接口都测了一下，没有发现注入点这条路也只能放弃。&lt;/p>
&lt;h2 id="逆向工程">逆向工程&lt;/h2>
&lt;p>既然服务端没有收获，那么就尝试从客户端入手。拿来 apk 解压得到 dex 文件，果然没有加壳。用 dex2jar[4]将其转成 jar。这里遇到一个问题[5]，在 GitHub 上最新的 release(2.1 or later) 已经解决。之后用 Java Decompiler[6] 打开 jar 查看源码。仔细查找后，奇怪地发现所有包都是导入的依赖，没有域名对应的包，也没有开发者编写的代码。这明显不合理。后来想到用 adb 来找当前栈顶 Activity 的方法。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>adb shell dumpsys activity activities | sed -En -e &lt;span style="color:#e6db74">&amp;#39;/Running activities/,/Run #0/p&amp;#39;&lt;/span> 
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>结果竟然是 &lt;code>uni.UNIC0381B1.io.dcloud.PandoraEntryActivity&lt;/code>。前面的 uni 是 apk 的签名，这在我安装时还在猜测他的具体含义。后面的 dcloud 我在抓包时候看到过，是用来统计数据的。但是用来统计数据怎么会单独开一个 Activity?&lt;/p></description></item><item><title>Week 49, 2019</title><link>/weekly/2019/12/01/week-49-2019/</link><pubDate>Sun, 01 Dec 2019 00:00:00 +0000</pubDate><guid>/weekly/2019/12/01/week-49-2019/</guid><description>&lt;ol>
&lt;li>
&lt;p>挑了一本上周下载的 Operating Systems: Three easy pieces ^[http://pages.cs.wisc.edu/~remzi/OSTEP/]. 来读，这次尝试不用翻译阅读，起初看地比较吃力，后来觉得越来越顺畅了。这本书从虚拟化、并发和持久化三个方面介绍，这种结构更容易把知识打穿，也是我选择这本书的原因。读了7个 chapter 也发现了几个问题，和群里的朋友们探讨了一下：&lt;/p>
&lt;h3 id="q1-获取系统时间gettimeofday是否会进行系统调用">Q1: 获取系统时间(gettimeofday())是否会进行系统调用？&lt;/h3>
&lt;ul>
&lt;li>Switching Between Processes
&lt;ul>
&lt;li>A Non-Cooperative Approach: The OS Takes Control
&lt;ul>
&lt;li>A timer device can be programmed to raise an interrupt every so many milliseconds; when the interrupt is raised, the currently running process is halted, and a pre-conﬁgured interrupt handler in the OS runs. At this point, the OS has regained control of the CPU, and thus can do what it pleases: stop the current process, and start a different one.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>思考：
Timer 用于进程切换，此外系统的时间也由它进行维护，那么每次获取系统时间是否会进行系统调用？&lt;/p></description></item><item><title>Week 48, 2019</title><link>/weekly/2019/11/24/week-48-2019/</link><pubDate>Sun, 24 Nov 2019 00:00:00 +0000</pubDate><guid>/weekly/2019/11/24/week-48-2019/</guid><description>&lt;blockquote>
&lt;p>之前实习的时候写过一段时间的周报，最近觉得需要记录一下自己的生活和学习的过程，避免过地无所事事。所以在今天专门在博客上开了一个周报的 tab，这便是我个人的第一个周报，或者说是周记。&lt;/p>&lt;/blockquote>
&lt;ol>
&lt;li>
&lt;p>电脑终于到了，是19款13&amp;quot; 16+512的，新出的16&amp;quot;低配也是16+512套餐，看了看钱包只能安慰自己是为了便携度放弃了16&amp;quot;。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>折腾了三年多，最后还是迁回 Hugo^[https://gohugo.io/] 搭建博客，之前一直使用 Travis CI^[http://travis-ci.org/] 做 CD，但是很久没用遇到了 Travis 中 Hugo 下载失败的问题。联想 GitHub Actions 上线不久，调研了相关的静态博客方案后选择了 Hugo + GitHub Pages + GitHub Actions 的方案。参照 hugo-xmin^[https://github.com/yihui/hugo-xmin] 主题加入代码高亮^[https://highlightjs.org]和 disqus^[https://disqus.com/] 评论，修改了一些样式，最后完成了你现在所在的这个站点^[https://arjenzhou.github.io]。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>完成了一家公司的二面，起初电话没有听清是哪家公司，后来询问业务才想起只有一家投递了这个部门。有两个多月没有面试过了，一些常见的面试题也忘得差不多。平时能展开滔滔不绝的问题也被面试官问：“你面试别的公司说话也这么简短吗”？其实这些问题根本算不上难，背一些面经也可以回答上来。对我来说合理的面试内容应该是深入挖掘底层基础，一些依靠背诵或阅读几篇文章就能达到同样效果的问题确实让人头疼。身边有相当一部分朋友后悔学习计算机相关专业，我深切地理解这种做着不感兴趣的事的无力感，同时也庆幸自己对计算机科学及行业的热爱。四年间接触过一些能力极强的朋友，不得让感慨：真正的大神还是兴趣驱动，而没有任何功利的想法。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;center>![](/pic/weekly/2019/11/2019-11-24-weekly/图像.jpeg)&lt;/center>
&lt;center>图1，本科期间的一部分计算机相关书籍&lt;/center>
&lt;ol start="4">
&lt;li>
&lt;p>在网上^[https://www.pdfdrive.com]下了不少的英文原版 pdf，起初是为了看 DDIA^[https://www.amazon.com/gp/product/1449373321/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=dataintensive-20&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;linkCode=as2&amp;amp;creativeASIN=1449373321&amp;amp;linkId=7b365b768a6f6c8e5e397e48e30d435e] 这本书，后来由于收集癖好将所有计算机方面的经典书籍都下了一遍放在 icloud 上。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>胸口不舒服有一周了，周日去医院看了看，片子拍出来后大夫告知是熬夜导致的。以后不能熬夜了，待恢复几天后也要加强锻炼。&lt;/p>
&lt;/li>
&lt;/ol></description></item><item><title>Open Source and I - After Alibaba Summer of Code</title><link>/article/2019/08/29/summer-of-code/</link><pubDate>Thu, 29 Aug 2019 00:00:00 +0000</pubDate><guid>/article/2019/08/29/summer-of-code/</guid><description>&lt;blockquote>
&lt;p>关于阿里巴巴编程之夏的介绍可以参考 AliOS-things 同学的文章
&lt;a href="https://zhuanlan.zhihu.com/p/79863308">https://zhuanlan.zhihu.com/p/79863308&lt;/a>&lt;/p>&lt;/blockquote>
&lt;p>借秋招的一个间歇期，记录一下我的开源历程。算是对自己的人生阶段的一个记录。&lt;/p>
&lt;p>从小学时使用开源软件成为受益者，到第一次到开源社区中成为贡献者，我用了十年。不求回报地默默贡献，得到他人的肯定便觉得欢欣雀跃，也许这就是开源的魅力所在。&lt;/p>
&lt;p>&lt;img src="/pic/post/2019/08/2019-08-29-SOC/481648656.jpeg" alt="">&lt;/p>
&lt;p>&lt;em>图1，赵老师在 Jenkins 中文社区的发言&lt;/em>&lt;/p>
&lt;p>我第一次正式参与到开源项目中，是在去年的九月。&lt;/p>
&lt;p>去年四月的时候，在上海有幸认识了家辉，我们当时便成为了朋友。也是通过他，我了解到了 GSoC。半年之后，觉得是开始套瓷的时间了，便想挑选几个社区来有针对性的交流。第一个关注的是 Apache 的 Kylin 社区，虽然主要开发者是中国人，但是方向和我期望的不太一样，所以后来没有选择它。后来在 GSoC-CN 中根据往年的申请情况，选择了 Jenkins 社区，巧合的是 Jenkins 中文社区刚刚成立，而 Jenkins 社区中活跃的参与者赵老师 @Rick 又是中国人，所以从九月到第二年的三月我便一直在 Jenkins 社区中做贡献，期间成为了 Jenkins-infra member。&lt;/p>
&lt;p>&lt;img src="/pic/post/2019/08/2019-08-29-SOC/374153865.jpeg" alt="">&lt;/p>
&lt;p>&lt;em>图2，赵老师由 KK 宣布为最有价值参与者&lt;/em>&lt;/p>
&lt;p>转折发生在二月和三月。在年前我和赵老师提到过想申请他的 multibranch plugin，他也提醒过我多次要提早准备。但是我期间一直没有在其 gitter channel 中发言，二月的时候有一个印度的同学也参与到其中。同时在三月时春招受挫，和在蚂蚁的家纯学长聊了聊，决定放弃 GSoC，参与到 Kafka 中去。&lt;/p>
&lt;p>&lt;img src="/pic/post/2019/08/2019-08-29-SOC/399295576.jpeg" alt="">&lt;/p>
&lt;p>&lt;em>图3，和学长的交流&lt;/em>&lt;/p>
&lt;p>四月的一个偶然机会，了解到 ASoC 的举办，而其中恰好有我想要深入学习的 Dubbo 社区，于是便在 issue 中留言。我没有马上得到回复，而我又不想错过这次机会，于是在 Jira 中留言、给社区发邮件、给导师发邮件、给 aliopensource 发邮件。久久没有得到回复的我有点绝望，当时又去接触了 Spring Cloud Alibaba 社区。后来乎兴老师在 Jira 中回复了我，@cvictory 也在 issue 中回复了我，aliopensource 和社区也都回复了我邮件，让我先写 proposal。有 GSoC 的经历，其实我的提案早就写完了，但是 ASoC 的提案描述相对来说不够具体，很难有针对性的给出解决方案，就这样踏上了漫长的交流之路&amp;hellip;&lt;/p></description></item><item><title>The analysis and modification of rules of ESLint</title><link>/article/2019/07/the-analysis-and-modification-of-eslint-rules/</link><pubDate>Wed, 03 Jul 2019 00:00:00 +0000</pubDate><guid>/article/2019/07/the-analysis-and-modification-of-eslint-rules/</guid><description>&lt;blockquote>
&lt;p>每个互联网大厂都有自己的编码规范，而对规范审查需要有代码扫描平台来对工程师的能力进行评估。在实习的两个月中，我负责的工作的一部分包括代码规范扫描方向，其中对 ESLint 以及 fecs 规则的修改及调整也包括在内。ESLint 在内部保留了一个仓库用于 JS 的规范检查，由于内部代码规范的问题，不可能直接将外部的拿来直接使用。对很少接触 JS 的我来说，npm 的包管理方式冗杂而烦乱，同时该模块是被集成在整个扫描平台中的，所以很少有有效的文档用来参考，通过不断地测试最后终于解决了该部分问题。&lt;/p>&lt;/blockquote>
&lt;p>规则 &lt;strong>no-new&lt;/strong> 要求 使用 &lt;strong>new&lt;/strong> 关键字必须将其赋值给一个变量，如:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-JS" data-lang="JS">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> &lt;span style="color:#a6e22e">Vue&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> &lt;span style="color:#a6e22e">Vue&lt;/span>({})
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>而内部规范在 &lt;strong>Vue&lt;/strong> 中可以不赋值&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-JS" data-lang="JS">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">new&lt;/span> &lt;span style="color:#a6e22e">Vue&lt;/span>({})
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>所以考虑对 &lt;strong>ESLint&lt;/strong> 进行一些定制化配置。&lt;/p>
&lt;p>查看官方文档无果之后，考虑找到开发人员，以下为交流过程：&lt;/p>
&lt;blockquote>
&lt;p>arjenzhou:
Hi, because I customized the rules, so I want to build and run eslint locally, what should I do?&lt;/p>
&lt;p>platinumazure:
@arjenzhou You should be able to install ESLint locally with npm install &amp;ndash;save-dev eslint, and then run with ./node_modules/.bin/eslint. Am I missing something?&lt;/p></description></item></channel></rss>