<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.7.4">Jekyll</generator><link href="http://mazhuang.org/feed.xml" rel="self" type="application/atom+xml" /><link href="http://mazhuang.org/" rel="alternate" type="text/html" /><updated>2019-02-17T08:16:09+00:00</updated><id>http://mazhuang.org/feed.xml</id><title type="html">半吊子码农</title><subtitle>半吊子码农的github之家</subtitle><author><name>JiuJiuShu</name></author><entry><title type="html">读书：追风筝的人</title><link href="http://mazhuang.org/2017/02/19/the-kite-runner/" rel="alternate" type="text/html" title="读书：追风筝的人" /><published>2017-02-19T00:00:00+00:00</published><updated>2017-02-19T00:00:00+00:00</updated><id>http://mazhuang.org/2017/02/19/the-kite-runner</id><content type="html" xml:base="http://mazhuang.org/2017/02/19/the-kite-runner/">&lt;blockquote&gt;
  &lt;p&gt;《追风筝的人》确实是一部相当优秀而又深刻的作品。——小别老师&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/images/blog/the-kite-runner.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;图 1. 《追风筝的人》/卡勒德.胡赛尼 封面&lt;/p&gt;

&lt;p&gt;当在我用一整个下午读完这本书，印象最深的句子是下面这两个：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;那儿有再次成为好人的路。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;为你，千千万万遍。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;这样的句子翻译之后总觉得少了点意思，感受下原文：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;There is a way to be good again.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;For you, a thousand times over.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;就是这两个简单的句子，承载了故事的主要线索——自我救赎与献身。&lt;/p&gt;

&lt;h2 id=&quot;剧透&quot;&gt;剧透&lt;/h2&gt;

&lt;p&gt;小说其实讲述了一个非常简单的故事：&lt;/p&gt;

&lt;p&gt;一心只想讨父亲欢心的少爷阿米尔与他忠诚的仆人哈桑从小一起长大，哈桑总是为阿米尔背锅，还在危急关头为他挺身而出，但是在哈桑被反社会分子逼到巷角时，阿米尔却眼睁睁地看着强暴发生，什么都没有做。&lt;/p&gt;

&lt;p&gt;阿米尔后来无法承受对自己懦弱的自责所带来的痛苦，就设计逼走了哈桑。随后阿富汗发生战乱，阿米尔随父亲逃到美国讨生活，有了美丽的妻子和体面的职业，过上了岁月静好的生活。&lt;/p&gt;

&lt;p&gt;但是多年以后，父亲旧时好友告诉了他一个惊天秘密：原来哈桑是他同父异母的弟弟。虽然被一直以来形象正面的父亲蒙蔽多年给心灵带来的冲击巨大，但为了救赎自己少年时的背叛，他还是冒着生命危险去营救弟弟唯一的骨肉，最后果然有了生命危险，他也为自己多年前的「罪行」受到了「惩罚」，完成了自我救赎。一番波折之后，带着弟弟的骨肉回到了美国。&lt;/p&gt;

&lt;h2 id=&quot;笔记&quot;&gt;笔记&lt;/h2&gt;

&lt;h3 id=&quot;整体评价&quot;&gt;整体评价&lt;/h3&gt;

&lt;p&gt;对于我这样的俗人来说，一部小说或者讲故事的电影优秀与否其实很好判断：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;看完之后能否比较容易地复述整个故事。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;不为了制造戏剧冲突而夸大其词，造成情节和情感脱线。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;能让人在听故事之余，在人性或亲情等方面产生更深刻的认识。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;从这几点来讲，《追风筝的人》都不失为一部好作品。&lt;/p&gt;

&lt;p&gt;下面分几个方面来记录一下我个人的理解：&lt;/p&gt;

&lt;h3 id=&quot;哈桑&quot;&gt;哈桑&lt;/h3&gt;

&lt;p&gt;哈桑是忠诚的，一辈子都在「献身」，但他却因此成为故事里悲剧部分的主要载体。&lt;/p&gt;

&lt;p&gt;少爷出主意恶作剧时，他负责背锅；少爷受欺负时，他负责挡枪；自己遭受暴行时，少爷袖手旁观，但他却依然不变初心；少爷想要激怒他来减轻自己的负罪感时，默默承受；少爷栽赃给他时，波澜不惊地应承下来；直至最后，都是为了守护少爷的房子而死。&lt;/p&gt;

&lt;p&gt;他让我想起我们小学时接受思想品德教育时，「舍己为人」、「先人后己」和「毫不利己，专门利人」这些词汇，我们可以逐步跳脱出来，而身处那个环境的哈桑——少爷说，「哈桑从未拒绝我任何事情」。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;但在你为他献身之前，你想过吗？他会为你献身吗？&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;他对少爷怀着的是一种我无法理解的感情。&lt;/p&gt;

&lt;h3 id=&quot;父亲&quot;&gt;父亲&lt;/h3&gt;

&lt;p&gt;在大部分时候，他是一个令人敬佩的形象。&lt;/p&gt;

&lt;p&gt;他乐善好施，不屈从世俗与宗教，选择自己认为对的路，并且将生活经营得有声有色；他心怀高尚的情操，面对俄国士兵的枪杆也毫不退缩，靠自己赢得所有人的尊敬；即使逃到美国，也只靠自己双手劳作，拒绝靠政府的救济来生存。&lt;/p&gt;

&lt;p&gt;他对世间罪行的概括：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;罪行只有一种，那就是盗窃，其它罪行都是盗窃的变种。当你杀害一个人，你偷走一条性命，你偷走他妻子身为人妇的权利，夺走他子女的父亲。当你说谎，你偷走别人知道真相的权利。当你诈骗，你偷走公平的权利。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;在阅读他的事迹的时候，我常在想，原来这样的人，真的存在。&lt;/p&gt;

&lt;p&gt;他这一生也许只做过一件羞耻的错事，那就是给阿米尔带来了一个同父异母的兄弟。所以当我看到这一点，受到的冲击是巨大的，可以想见阿米尔为何会因此而崩溃。&lt;/p&gt;

&lt;p&gt;他展现在大伙面前的正面的神迹般的一生，也是对这唯一一件错事的自我救赎。&lt;/p&gt;

&lt;h3 id=&quot;阿米尔&quot;&gt;阿米尔&lt;/h3&gt;

&lt;p&gt;故事的绝对主线，一个懦弱的孩子，要不是在父亲，哈桑，和好些其它人的保护之下，我很怀疑他能顺利长大。小时候的他，身上充斥着各种他自己的察觉或未察觉的阴暗面。&lt;/p&gt;

&lt;p&gt;他与哈桑的一段对话让我印象深刻：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;「我骗过你吗，阿米尔少爷？」&lt;/p&gt;

  &lt;p&gt;「我不知道，你会骗我吗？」&lt;/p&gt;

  &lt;p&gt;「我宁愿吃泥巴也不会骗你。」&lt;/p&gt;

  &lt;p&gt;「真的吗？你会那样做？」&lt;/p&gt;

  &lt;p&gt;「做什么？」&lt;/p&gt;

  &lt;p&gt;「如果我让你吃泥巴，你会吃吗？」&lt;/p&gt;

  &lt;p&gt;「如果你要求，我会的。不过我怀疑，你是否会让我那么做。你会吗，阿米尔少爷？」&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;阿塞夫是反社会，但是他对阿米尔的总结却也并不见得有多偏颇：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;为什么他跟客人玩总不喊上你？为什么他总是在没有人的时候才理睬你？我告诉你为什么，哈扎拉人。因为对他来说，你什么都不是，只是一只丑陋的宠物。一种他无聊的时候可以玩的东西，一种他发怒的时候可以踢开的东西。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;阿米尔小时候拼命想得到父亲的认可与亲近，而哈桑却在不经意间就能获得，所以一定程度上讲，他是嫉妒哈桑的。&lt;/p&gt;

&lt;p&gt;他了解哈桑对自己的感情与忠诚，并且利用和背叛了它，却又受自己的良心煎熬，毕竟「一直以来，你对自己太严苛了」，所以在二十五年后，冒着生命危险也要回到故乡去带回索拉博，名义上是援救这个孩子，实际只为了完成那一场自我救赎。只是与他受人尊敬坚毅果敢的父亲不同，他的这场救赎来得实在太晚。&lt;/p&gt;

&lt;h3 id=&quot;阿富汗&quot;&gt;阿富汗&lt;/h3&gt;

&lt;p&gt;这个国度以前在我的印象里真的只有连年战乱，塔利班，火箭弹。&lt;/p&gt;

&lt;p&gt;现在，脑海里对它的曾经的样子，经历的历史进程，国民遭受的苦难有了更具象的刻画，也许有一天，我会去查更多关于它的资料，只为理解这个世界上真的有这样一个地方，它的人民真的生活在这样的环境里，而它曾经孕育过一代又一代能快乐地追风筝的少年。&lt;/p&gt;

&lt;p&gt;作者胡赛尼「立志拂去蒙在阿富汗普通民众面孔的尘灰，将背后灵魂的悸动展示给世人」，从某种意义上讲，他实现了这个志向。&lt;/p&gt;

&lt;h3 id=&quot;同名电影&quot;&gt;同名电影&lt;/h3&gt;

&lt;p&gt;在 2017 贺岁档电影里，我唯一觉得还不错的《乘风破浪》（豆瓣 7.0 分），之所以广受好评，主要也是因为第一点做得比较好，完整地讲述了一个简单的故事，让人知所云，这本来应该是一部电影的基本素质，但是它做到这一点，却已比如今一众故弄玄虚总想搞个大新闻的烂片不知道高到哪里去了。&lt;/p&gt;

&lt;p&gt;而本书的同名电影在豆瓣上评分高达了 8.2 分，可见也很值得一看。但我的体会是在阅读本书的过程中，脑海里能根据作者的讲述不断脑补起各种场景、人物和剧情，所以不建议看完本书之后立即去看电影——脑海里刚刚放映过包含各种细节和微妙之处的完整版，马上接着去看有删节有改编版，难免会失落。&lt;/p&gt;

&lt;h2 id=&quot;感受&quot;&gt;感受&lt;/h2&gt;

&lt;p&gt;一个好的故事，应该连续地读完，及时记下所感所想。&lt;/p&gt;

&lt;p&gt;虽然我不擅长写读书笔记、读后感，但是输入之后有输出真的是一个能让自己受益良多的好习惯。不顾忌那么多，先写下来，然后对记录的模板、方式和内容进行迭代。&lt;/p&gt;

&lt;p&gt;希望本篇成为一个良好的开端。&lt;/p&gt;</content><author><name>JiuJiuShu</name></author><summary type="html">《追风筝的人》确实是一部相当优秀而又深刻的作品。——小别老师</summary></entry><entry><title type="html">我的 2016 盘点</title><link href="http://mazhuang.org/2017/01/01/my-2016/" rel="alternate" type="text/html" title="我的 2016 盘点" /><published>2017-01-01T00:00:00+00:00</published><updated>2017-01-01T00:00:00+00:00</updated><id>http://mazhuang.org/2017/01/01/my-2016</id><content type="html" xml:base="http://mazhuang.org/2017/01/01/my-2016/">&lt;p&gt;总结是为了更好地再上路。&lt;/p&gt;

&lt;p&gt;在我人生的前二十几年是没有做年度计划和总结的习惯的，但在 2015-12-31 时和饭团团员们心血来潮一起做了个 2016 PLAN，现在 2016 已经被完整地甩在身后，是时候回顾以明得失，展望以知进退了。&lt;/p&gt;

&lt;p&gt;如果用一句话来概括，这一年是玩得不错，学得不咋样；展开来讲的话，按传统得欲扬先抑，先把批评做在前头，上成绩单：&lt;/p&gt;

&lt;h2 id=&quot;成绩单&quot;&gt;成绩单&lt;/h2&gt;

&lt;p&gt;当时制定的计划一共 16 项，现状如下：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/blog/2016-plan-progress.png&quot; alt=&quot;2016 Plan Progress&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;自评&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;惨，不及格。&lt;/p&gt;

&lt;p&gt;当然我的过去就是我存在的基石，一味地全盘否定并不能改变什么，需要认可我自己的是清单里可能最难、但对我提升最大的两项任务完成了。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;反思&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;我对跨度较大的计划的把控能力略差，做这件事情需要的能力跟项目管理很类似，都还需要我有意识地花大力气去培养。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;目标的约束力&lt;/p&gt;

    &lt;p&gt;引用最有故事的女同学曲玮玮的话说：&lt;strong&gt;真正的目标是清晰明确的、有时间约束的、可操作执行并且可以检验的&lt;/strong&gt;。&lt;/p&gt;

    &lt;p&gt;我在制定计划时存在一个很大的问题是没有给任务加上时间约束，而在一年这样一个相对很长的时间跨度里，没有时间约束的目标很容易被无限押后，并最终导致计划的流产。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;计划的迭代&lt;/p&gt;

    &lt;p&gt;在一个计划周期里，处境，心态，都可能发生了天翻地覆的变化，想要做的事情也可能需要随之调整，保持对计划清单的关注，确保留在清单里的仍然是你最想完成的事项。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;执行力&lt;/p&gt;

    &lt;p&gt;候捷老师说，天下大事，必作于细。&lt;/p&gt;

    &lt;p&gt;小别老师说，&lt;strong&gt;「做事情抓重点」+「执行力」&lt;/strong&gt;。&lt;/p&gt;

    &lt;p&gt;我对自己说，想明白最重要的里面最想做的，迈出第一步，少年莫踌躇。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;有形的记录&quot;&gt;有形的记录&lt;/h2&gt;

&lt;h3 id=&quot;阅读和影音娱乐&quot;&gt;阅读和影音娱乐&lt;/h3&gt;

&lt;p&gt;数据主要来自豆瓣上的记录。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/blog/books-and-movies.png&quot; alt=&quot;Books and Movies&quot; /&gt;&lt;/p&gt;

&lt;p&gt;用一句网络流行语来说，努力了可能没什么卵用，但不努力真的很舒服啊。:sob:&lt;/p&gt;

&lt;p&gt;从数字上看，我这一年过得没有之前努力了，花在书籍上的时间与影音方面的时间此消彼长，特别是技术类书籍的阅读少了很多，这都是需要注意的地方。&lt;/p&gt;

&lt;h3 id=&quot;网络活动&quot;&gt;网络活动&lt;/h3&gt;

&lt;h4 id=&quot;github&quot;&gt;GitHub&lt;/h4&gt;

&lt;p&gt;贡献日历：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/blog/github-contributions-2016.png&quot; alt=&quot;GitHub Contributions 2016&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;过去一年总共有 935 次 Commits/Issues/PR，相比 2015 年的 765 次小幅提升；&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;最长连击记录是 28 天，是 2015-12-31 到 2016-01-27；&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;每一周都活跃。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;相较于活跃的数字来讲，过去一年里值得一提的个人项目主要是下面这三个：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://github.com/mzlogin/awesome-adb&quot;&gt;awesome-adb&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;目前网络上能找到的最完善的 ADB 用法大全。&lt;/p&gt;

    &lt;p&gt;它在 GitHub 的 Trending 上待了几天，最高 Repositories 排名第 4，最高 Developers 排名第 6，目前 Star 数过 2000。我至今仍记得上 Trending 的第一天我激动地与 Linus 合影留恋时的心情。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://github.com/mzlogin/vim-markdown-toc&quot;&gt;vim-markdown-toc&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;一款 Vim 插件，主要功能是为 Markdown 文档自动生成和维护 Table of Contents。&lt;/p&gt;

    &lt;p&gt;Star 数不到百，但每天都有人 clone，Vim 必备插件 nerdtree 的作者 &lt;a href=&quot;https://github.com/scrooloose&quot;&gt;scrooloose&lt;/a&gt; 还来提过 Issue 和 PR，让我体会到与传说中的人交流的感受。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://github.com/mzlogin/chinese-copywriting-guidelines&quot;&gt;chinese-copywriting-guidelines&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;中文文案排版指北（简体中文版）。&lt;/p&gt;

    &lt;p&gt;这是一个 Fork 项目，却也是第一个让我尝到 Star 数破百的滋味的项目，感谢它。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;得与失：&lt;/p&gt;

&lt;p&gt;参与和维护开源项目是一件很有意思的事情，可能让你接触到久仰的大神，也可能占用你很多的时间，可以从中学到多人协作的方式与智慧，也可能让你在连击与 Star 里迷失。起初最盼望的是自己的项目有人关注，这样的时刻真正来临之后你就会发现身上多了许多责任，解答网友们与项目相关的问题义不容辞，及时响应对维持热度必不可少。&lt;/p&gt;

&lt;p&gt;在这方面的付出与收获自己觉得还比较满意，以后会继续保持活跃，而且要活跃得更有质量，更有效率。&lt;/p&gt;

&lt;p&gt;需要引起重视的地方是作为一名 Android 开发者，没有一个长期维护的相关代表作，这是严重的失误。&lt;/p&gt;

&lt;h4 id=&quot;技术社区&quot;&gt;技术社区&lt;/h4&gt;

&lt;p&gt;这一年里我成为了掘金联合编辑、极乐知乎专栏原创作者，在掘金分享和发布了 11 篇文章，收获了 1388 个收藏，在极乐知乎专栏发布 1 篇文章，收获 80 个赞和 60 名粉丝。&lt;/p&gt;

&lt;p&gt;在它们的原创作者群里可以接触到很多业界知名的开发者和很厉害的小朋友们，他们也跟大家一样嬉笑怒骂，但又明摆着实力碾压，无形中带来很多的压力和激励。&lt;/p&gt;

&lt;h4 id=&quot;博客&quot;&gt;博客&lt;/h4&gt;

&lt;p&gt;这一年在个人博客上共发表 17 篇文章，大致上半年每月 2 篇，下半年每月 1 篇的节奏。&lt;/p&gt;

&lt;p&gt;以后可以再多写一点。我比较满意自己的一点是近两年我对学过的东西和遇到过的问题在 OneNote 上都作了详细的分类记录，而这些笔记趁热乎的成篇发布出来对整理思路和加深理解都是有益的，毕竟你能清楚地讲解给别人听，才算是真懂了。&lt;/p&gt;

&lt;h3 id=&quot;运动&quot;&gt;运动&lt;/h3&gt;

&lt;p&gt;过去一年的运动记录主要分布在羽毛球、跑步、瑜伽和网球上。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;羽毛球&lt;/p&gt;

    &lt;p&gt;参加公司羽毛球俱乐部活动 20 次，集团俱乐部活动几次，搜狐联赛 1 次。技术上进步不大，抽空看完了李在福的《追球》系列，周末偶尔参加回龙观的情怀羽毛球俱乐部的活动。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;跑步&lt;/p&gt;

    &lt;p&gt;参加公司跑团活动 15 次，和小伙伴们约跑以及自己练习若干次，收获了两枚半程马拉松奖牌和很多好友。&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/blog/marathon-2016.jpeg&quot; alt=&quot;Marathon&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;瑜伽&lt;/p&gt;

    &lt;p&gt;参加集团俱乐部活动几次，身体僵硬，练习完很放松，很久没去了。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;网球&lt;/p&gt;

    &lt;p&gt;参加公司网球俱乐部活动 15 次，入门菜鸡选手，到处捡球，很久没打了。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;工作&quot;&gt;工作&lt;/h3&gt;

&lt;p&gt;占据绝大多数时间的工作，在这一年里只能说中规中矩，却也实现了升职加薪的愿望。&lt;/p&gt;

&lt;p&gt;继续从事 Android 开发，因工作需要也接手了一些 PHP 后台代码维护，踩过很多坑，改过很多 Bug，个人能力的提升并不能令自己满意。&lt;/p&gt;

&lt;p&gt;一方面深感自己在技术上缺乏深度，另一方面也因职业发展焦虑而迫切想要进一步提升在实际编码层次之上的架构规划与设计能力。试着去阅读更多优秀的源码，也试着让自己在接手任务之后将更多的时间用于设计，更多地画图、做笔记来捋清和记录自己的想法，确保自己的编码过程中是思路清晰的。蜕变的过程是辛苦的，但这一步别人只能提供一些建议，更多的还得靠自己去学习和思考。&lt;/p&gt;

&lt;p&gt;制订一个清晰合理的职业规划来指引自己前行是必要的，否则可能看上去很努力，实际也做了很多事情，但两点之间直线最短，有明确的目标你才能笔直前进。&lt;/p&gt;

&lt;h3 id=&quot;游戏&quot;&gt;游戏&lt;/h3&gt;

&lt;p&gt;今年游戏玩得比去年多，主要是手游《皇室战争》和《阴阴师》，在业余时间里它们能让我暂时摆脱焦虑与烦恼，专注于一个小屏幕里，去发掘和操作一些套路，尽管那也许就是游戏策划们设计好的套路。&lt;/p&gt;

&lt;p&gt;另外，和李小昂同学合作使用网易的自动化测试框架写网易游戏的自动化脚本也挺有意思。&lt;/p&gt;

&lt;p&gt;昨天我卸载了《阴阳师》，从中节省出来的时间我想干一点更有意思的事情，目前还没有想好，欢迎推荐。&lt;/p&gt;

&lt;h3 id=&quot;旅行&quot;&gt;旅行&lt;/h3&gt;

&lt;p&gt;由于异地装修，这一年里稍长一点的假期基本奔波于帝都和武汉之间，能称得上旅行的只有和范师傅周大神一起的大五朝台了。&lt;/p&gt;

&lt;p&gt;两天步行五十多公里，单日计步超过五万，在徒步过程中数次想放弃然而最终坚持下来，第一次在寺庙挂单，这些都深深地印在脑海里。&lt;/p&gt;

&lt;h2 id=&quot;无形的收获&quot;&gt;无形的收获&lt;/h2&gt;

&lt;p&gt;除了上述的这些，我还收获了一些看不见摸不着，但是也实实在在的东西。&lt;/p&gt;

&lt;p&gt;一是和小别同学在经历了无数的争吵后达成的共识越来越多，求同存异中也多了许多体谅与包容。&lt;/p&gt;

&lt;p&gt;二是在参加各种运动的过程中收获了许多好友，让我得以在工作之外感受更多生活的精彩。&lt;/p&gt;

&lt;h2 id=&quot;展望&quot;&gt;展望&lt;/h2&gt;

&lt;p&gt;参加工作六年有余，近一两年日益焦虑，猜想大致与若干年后将体会到的中年危机类似，唯不断的思考和努力方可突破。&lt;/p&gt;

&lt;p&gt;在接下来的日子里，我期望自己有：&lt;/p&gt;

&lt;p&gt;更多的思考，虽然 done is better than perfect；&lt;/p&gt;

&lt;p&gt;更多的阅读，特别是 the fucking source code；&lt;/p&gt;

&lt;p&gt;更多的交流，训练简洁的表达能联动促进思维更敏捷；&lt;/p&gt;

&lt;p&gt;更少的焦虑，想清楚，笃定前行；&lt;/p&gt;

&lt;p&gt;一个家。&lt;/p&gt;

&lt;h2 id=&quot;结语&quot;&gt;结语&lt;/h2&gt;

&lt;p&gt;最后要感谢亲人朋友们一如既往的支持，感谢领导和同事们的爱护与帮助，引用最近认识的超厉害的 &lt;a href=&quot;http://blog.csdn.net/u010850027&quot;&gt;小故事&lt;/a&gt; 的年终总结标题与大家共勉：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;你只管努力，剩下的交给时光。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;祝大家新年快乐！&lt;/p&gt;</content><author><name>JiuJiuShu</name></author><summary type="html">总结是为了更好地再上路。</summary></entry><entry><title type="html">搭建大型源码阅读环境——使用 OpenGrok</title><link href="http://mazhuang.org/2016/12/14/rtfsc-with-opengrok/" rel="alternate" type="text/html" title="搭建大型源码阅读环境——使用 OpenGrok" /><published>2016-12-14T00:00:00+00:00</published><updated>2016-12-14T00:00:00+00:00</updated><id>http://mazhuang.org/2016/12/14/rtfsc-with-opengrok</id><content type="html" xml:base="http://mazhuang.org/2016/12/14/rtfsc-with-opengrok/">&lt;p&gt;RTFSC 是程序员打怪升级路上避不开的功课，那营造一个舒适的环境来提升上课的体验就很有必要了。&lt;/p&gt;

&lt;p&gt;比如阅读 AOSP 这种大型源码，用什么姿势来阅读才能丝般顺滑，让 F**king Source Code 也变得不那么可恶呢？&lt;/p&gt;

&lt;h2 id=&quot;工具的选择&quot;&gt;工具的选择&lt;/h2&gt;

&lt;p&gt;阅读源码的工具我尝试过以下几类：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;IDE&lt;/p&gt;

    &lt;p&gt;在看特定类型项目时这是我的首选。比如它原本就是一个 Visual Studio 工程，那当然用 Visual Studio 来打开阅读，看 Android App 或者 Library 源码当然用 Android Studio 体验更好。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;编辑器配合插件&lt;/p&gt;

    &lt;p&gt;比如 Vim + Ctags + Cscope，再配合文件模糊查找插件 LeaderF 和神器 YouCompleteMe，在源码规模不大时很方便，打开也轻快，阅读一些小项目时我还是乐意使用它们。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;专门的源码阅读工具&lt;/p&gt;

    &lt;p&gt;在针对特大型源码时，比如 AOSP 和 Chromium，使用上述两种方案可能会感觉乏力，这时候就需要祭出专门的源码阅读工具了。&lt;/p&gt;

    &lt;p&gt;一类是商业软件，比如 Windows 下有著名的 Source Insight，跨平台的有 Understand，功能都很强大，都是不错的选择。当然它们都价格不菲。&lt;/p&gt;

    &lt;p&gt;而我这里要讲的主角 OpenGrok 属于另一类，免费，开源，运行流畅，功能也毫不逊色。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;如果你还在寻觅适合你自己的解决方案，大可以花一点时间将以上几种都尝试一遍，哪个称手用哪个，也可以像我一样，针对不同的项目使用不同的工具。想直观了解 OpenGrok 的同学可以直接先看看一些使用 OpenGrok 的在线源码查看网站，看看它能否满足你的需求，其中的一些列在 &lt;a href=&quot;https://github.com/OpenGrok/OpenGrok/wiki/OpenGrok-installations&quot;&gt;OpenGrok installations&lt;/a&gt;。&lt;/p&gt;

&lt;h2 id=&quot;opengrok-特性&quot;&gt;OpenGrok 特性&lt;/h2&gt;

&lt;p&gt;译自官方 &lt;a href=&quot;https://github.com/OpenGrok/OpenGrok/wiki/Features&quot;&gt;Wiki&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;OpenGrok 提供如下特性：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;快速搜索代码的引擎&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;搜索全文、定义、符号、文件路径和修改历史&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;搜索任意指定子目录（分层搜索）&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;增量更新索引文件&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;支持类似 Google 的查询语法，比如 &lt;code class=&quot;highlighter-rouge&quot;&gt;path:Makefile defs:target&lt;/code&gt;&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;搜索日期范围内修改的文件&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;支持使用通配符搜索，如 &lt;code class=&quot;highlighter-rouge&quot;&gt;*&lt;/code&gt; 表示多个字符，&lt;code class=&quot;highlighter-rouge&quot;&gt;?&lt;/code&gt; 表示单个字符&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;在搜索结果中展示匹配行&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;一个 Web 只读版的版本历史查看界面&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;文件的修改日志&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;文件在两个版本间的 diff&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;文件夹的历史记录&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;带语法高亮的交叉引用显示，可以使用 CSS 自定义样式&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;可以开发插件支持新的语言和版本控制系统&lt;/p&gt;

    &lt;p&gt;已经支持的语言： &lt;a href=&quot;https://github.com/OpenGrok/OpenGrok/wiki/Supported-Languages-and-Formats&quot;&gt;Supported Languages and Formats&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;已经支持的版本控制系统：&lt;a href=&quot;https://github.com/OpenGrok/OpenGrok/wiki/Supported-Revision-Control-Systems&quot;&gt;Supported Revision Control Systems&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;配置-opengrok&quot;&gt;配置 OpenGrok&lt;/h2&gt;

&lt;h3 id=&quot;截屏&quot;&gt;截屏&lt;/h3&gt;

&lt;p&gt;按惯例先上图吧，万一你一眼就发现不是你的菜呢（截图来自&lt;a href=&quot;https://opengrok.github.io/OpenGrok/&quot;&gt;官网&lt;/a&gt;）。&lt;/p&gt;

&lt;p&gt;搜索功能和源码树：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/tools/opengrok-scr1.png&quot; alt=&quot;OpenGrok Search and Browse&quot; /&gt;&lt;/p&gt;

&lt;p&gt;代码导航和版本历史记录：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/tools/opengrok-scr2.png&quot; alt=&quot;OpenGrok Navitation and History&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;安装和配置&quot;&gt;安装和配置&lt;/h3&gt;

&lt;p&gt;如下以 Windows 下为例，Mac OS X 与 Linux 下与此类似，很多步骤能使用 brew 或者 apt-get 会更方便。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;安装 &lt;a href=&quot;http://www.oracle.com/technetwork/java/&quot;&gt;JDK&lt;/a&gt;。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;下载 &lt;a href=&quot;http://tomcat.apache.org/&quot;&gt;Tomcat&lt;/a&gt;，解压到一个目录，如 D:\Programs\apache-tomcat-8.5.8。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;下载 &lt;a href=&quot;https://github.com/universal-ctags/ctags&quot;&gt;Universal Ctags&lt;/a&gt; for Windows，将 ctags.exe 文件所在目录添加到 PATH 环境变量。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;下载 &lt;a href=&quot;https://github.com/OpenGrok/OpenGrok/releases&quot;&gt;OpenGrok&lt;/a&gt; 的最新包，比如 opengrok-0.13-rc4.zip，解压到一个目录，如 D:\Programs\opengrok-0.13-rc4。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;配置 data root。&lt;/p&gt;

    &lt;p&gt;data root 用于放置生成的索引文件和配置信息，比如我在 OpenGrok 目录下创建了一个 data 目录用作 data root，即 D:\Programs\opengrok-0.13-rc4\data。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;将 OpenGrok 的 lib 目录里的 source.war 解压到 D:\Programs\apache-tomcat-8.5.8\webapps\source，配置 WEB-INF\web.xml 文件的 CONFIGURATION 为上一步生成的 data 目录下的 configureation.xml，比如我的配置：&lt;/p&gt;

    &lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;display-name&amp;gt;&lt;/span&gt;OpenGrok&lt;span class=&quot;nt&quot;&gt;&amp;lt;/display-name&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;description&amp;gt;&lt;/span&gt;A wicked fast source browser&lt;span class=&quot;nt&quot;&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;context-param&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;description&amp;gt;&lt;/span&gt;Full path to the configuration file where OpenGrok can read its configuration&lt;span class=&quot;nt&quot;&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;param-name&amp;gt;&lt;/span&gt;CONFIGURATION&lt;span class=&quot;nt&quot;&gt;&amp;lt;/param-name&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;param-value&amp;gt;&lt;/span&gt;D:/Programs/opengrok-0.13-rc4/data/configuration.xml&lt;span class=&quot;nt&quot;&gt;&amp;lt;/param-value&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/context-param&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;配置 source root。&lt;/p&gt;

    &lt;p&gt;可以让 OpenGrok 认为 source root 下的每个子文件夹是一个项目，所以我们利用这个特性来配置和阅读多个项目源码就好了。&lt;/p&gt;

    &lt;p&gt;我的做法是在 OpenGrok 下创建了一个子目录 D:\Programs\opengrok-0.13-rc4\projects，然后将需要阅读的源码使用符号链接的方式链接到这个目录里：&lt;/p&gt;

    &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /d D:&lt;span class=&quot;se&quot;&gt;\P&lt;/span&gt;rograms&lt;span class=&quot;se&quot;&gt;\o&lt;/span&gt;pengrok-0.13-rc4&lt;span class=&quot;se&quot;&gt;\p&lt;/span&gt;rojects
mklink /J android D:&lt;span class=&quot;se&quot;&gt;\s&lt;/span&gt;ources&lt;span class=&quot;se&quot;&gt;\a&lt;/span&gt;ndroid_5.1
mklink /J openjdk7 D:&lt;span class=&quot;se&quot;&gt;\s&lt;/span&gt;ources&lt;span class=&quot;se&quot;&gt;\o&lt;/span&gt;penjdk7
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;这样就有一个叫 android 的工程，它实际对应 D:\sources\android_5.1 下的源码，一个叫 openjdk7 的工程，它实际对应 D:\sources\openjdk7 下的源码。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;建立索引。&lt;/p&gt;

    &lt;p&gt;使用 opengrok.jar 调用 ctags 来为源码建立索引。命令行：&lt;/p&gt;

    &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;java &lt;span class=&quot;nt&quot;&gt;-jar&lt;/span&gt; /path/to/opengrok.jar &lt;span class=&quot;nt&quot;&gt;-P&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /path/to/source/root &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; /path/to/data/root &lt;span class=&quot;nt&quot;&gt;-W&lt;/span&gt; /path/to/configuration.xml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;-P&lt;/code&gt; 表示为 source root 目录下的每个一级子目录生成一个工程。&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;-S&lt;/code&gt; 表示搜索并添加 “external” source repositories。&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;-v&lt;/code&gt; 表示打印操作的进度信息。&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;-s&lt;/code&gt; 表示指定 source root。&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;-d&lt;/code&gt; 表示指定 data root。&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;-W&lt;/code&gt; 表示指定将配置写到该文件。&lt;/p&gt;

    &lt;p&gt;还有更多配置选项可以使用 &lt;code class=&quot;highlighter-rouge&quot;&gt;java -jar /path/to/opengrok.jar&lt;/code&gt; 查看。&lt;/p&gt;

    &lt;p&gt;比如我使用的完整命令行：&lt;/p&gt;

    &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;java &lt;span class=&quot;nt&quot;&gt;-jar&lt;/span&gt; D:&lt;span class=&quot;se&quot;&gt;\P&lt;/span&gt;rograms&lt;span class=&quot;se&quot;&gt;\o&lt;/span&gt;pengrok-0.13-rc4&lt;span class=&quot;se&quot;&gt;\l&lt;/span&gt;ib&lt;span class=&quot;se&quot;&gt;\o&lt;/span&gt;pengrok.jar &lt;span class=&quot;nt&quot;&gt;-P&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; D:&lt;span class=&quot;se&quot;&gt;\P&lt;/span&gt;rograms&lt;span class=&quot;se&quot;&gt;\o&lt;/span&gt;pengrok-0.13-rc4&lt;span class=&quot;se&quot;&gt;\p&lt;/span&gt;rojects &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; D:&lt;span class=&quot;se&quot;&gt;\P&lt;/span&gt;rograms&lt;span class=&quot;se&quot;&gt;\o&lt;/span&gt;pengrok-0.13-rc4&lt;span class=&quot;se&quot;&gt;\d&lt;/span&gt;ata &lt;span class=&quot;nt&quot;&gt;-W&lt;/span&gt; D:&lt;span class=&quot;se&quot;&gt;\P&lt;/span&gt;rograms&lt;span class=&quot;se&quot;&gt;\o&lt;/span&gt;pengrok-0.13-rc4&lt;span class=&quot;se&quot;&gt;\d&lt;/span&gt;ata&lt;span class=&quot;se&quot;&gt;\c&lt;/span&gt;onfiguration.xml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;每次需要建立或更新索引的时候敲这么长一个命令当然很不爽，使用 doskey 或者 Cmder 里的 alias 命令将其 alias 为 opengrok-index 命令会省力不少，再不济把这命令存成个 bat 文件也行啊。&lt;/p&gt;

    &lt;p&gt;为大型源码建立索引可能需要漫长的时间，这时候可以去干点别的事了。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;启动 Tomcat，愉快地 RTFSC。&lt;/p&gt;

    &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;D:&lt;span class=&quot;se&quot;&gt;\P&lt;/span&gt;rograms&lt;span class=&quot;se&quot;&gt;\a&lt;/span&gt;pache-tomcat-8.5.8&lt;span class=&quot;se&quot;&gt;\b&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\c&lt;/span&gt;atalina.bat start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;用你最爱的浏览器打开 &lt;a href=&quot;http://localhost:8080/source/&quot;&gt;http://localhost:8080/source/&lt;/a&gt;，然后就能愉快地跟 OpenGrok 玩耍了。&lt;/p&gt;

    &lt;p&gt;当新添加了项目，或者现有项目有源码更新时，再次执行上一步的命令，就能增量更新索引了。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;配置多项目&quot;&gt;配置多项目&lt;/h3&gt;

&lt;p&gt;我曾经为如何在 OpenGrok 里配置多项目苦恼了好久——一开始我是把 Android 源码的根目录当作 source root 的，可想而知 OpenGrok 把 Android 分成了好多个子项目，而这时我也没法再添加新的工程了。&lt;/p&gt;

&lt;p&gt;后来才发现建一个专用的 source root，然后把各种项目源码根目录软链接过来，让 OpenGrok 为 source root 下的每个 symbol 一级子目录建立一个项目才是正确的使用方法。&lt;/p&gt;

&lt;p&gt;Windows 下建立软链接的方法是使用 &lt;code class=&quot;highlighter-rouge&quot;&gt;mklink /J android D:\sources\android_5.1&lt;/code&gt;，Mac OS X 和 Linux 下可以使用 &lt;code class=&quot;highlighter-rouge&quot;&gt;ln -s /path/to/source project_name&lt;/code&gt;。&lt;/p&gt;

&lt;h3 id=&quot;折腾狂魔&quot;&gt;折腾狂魔&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;在 Vim 里使用&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;没错，还有人做了支持在 Vim 里使用 OpenGrok 的插件，如果你是 Vim 控+折腾狂魔，可以一试，这里仅给出插件地址：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/asenac/vim-opengrok&quot;&gt;asenac/vim-opengrok&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/jdevera/vim-opengrok-search&quot;&gt;jdevera/vim-opengrok-search&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;反正像我这种智商是折腾不动了，就安心在浏览器里用了。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;在源码里做笔记&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;配合 Chrome 插件 &lt;a href=&quot;https://chrome.google.com/webstore/detail/diigo-web-collector-captu/pnhplgjpclknigjpccbcnmicgcieojbh&quot;&gt;Diigo&lt;/a&gt;，还能给源码加标签，写注释等等。&lt;/p&gt;

&lt;p&gt;参考：&lt;a href=&quot;https://www.zhihu.com/question/33505693/answer/132224974&quot;&gt;https://www.zhihu.com/question/33505693/answer/132224974&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;后话&quot;&gt;后话&lt;/h2&gt;

&lt;p&gt;古人教会了我们工欲善其事，必先利其器的智慧，但我们也不能沉迷和徘徊于各种利器之间，选择一样自己感觉最称手的工具，把它用熟练，少再在这上面花时间折腾，毕竟把有限的生命投入到无限的 RTFSC 才是正道不是么。&lt;/p&gt;</content><author><name>JiuJiuShu</name></author><summary type="html">RTFSC 是程序员打怪升级路上避不开的功课，那营造一个舒适的环境来提升上课的体验就很有必要了。</summary></entry><entry><title type="html">vim-markdown-toc 发布 v1.0 版</title><link href="http://mazhuang.org/2016/10/22/vim-markdown-toc-release/" rel="alternate" type="text/html" title="vim-markdown-toc 发布 v1.0 版" /><published>2016-10-22T00:00:00+00:00</published><updated>2016-10-22T00:00:00+00:00</updated><id>http://mazhuang.org/2016/10/22/vim-markdown-toc-release</id><content type="html" xml:base="http://mazhuang.org/2016/10/22/vim-markdown-toc-release/">&lt;p&gt;前几天，第一款由我独立开发的 Vim 插件 vim-markdown-toc 升级了功能，发布了 v1.0 版本。&lt;/p&gt;

&lt;p&gt;它的主要功能是为 Markdown 文件生成 toc（Table of Contents）、更新已经存在的 toc 和在保存时自动更新 toc。&lt;/p&gt;

&lt;p&gt;说它是当前使用 Vim 编辑 Markdown 文件时维护 Table of Contents 的最佳解决方案应该不为过。&lt;/p&gt;

&lt;h2 id=&quot;下载地址&quot;&gt;下载地址&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mzlogin/vim-markdown-toc&quot;&gt;vim-markdown-toc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;主要更新&quot;&gt;主要更新&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;支持使用 &lt;code class=&quot;highlighter-rouge&quot;&gt;:UpdateToc&lt;/code&gt; 命令更新已经存在的 toc。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;支持保存时自动更新 toc。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;功能演示&quot;&gt;功能演示&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/mzlogin/vim-markdown-toc/master/screenshots/english.gif&quot; alt=&quot;vim-markdown-toc-screenshot&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;一些体会&quot;&gt;一些体会&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;相比于 &lt;a href=&quot;https://github.com/mzlogin/awesome-adb&quot;&gt;awesome-adb&lt;/a&gt; 的一千多个 Star，&lt;a href=&quot;https://github.com/mzlogin/vim-markdown-toc&quot;&gt;vim-markdown-toc&lt;/a&gt; 的三十多个 Star 在我心目中含金量更高。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;做能挣钱的东西，或者对自己有用的东西。&lt;/p&gt;

    &lt;p&gt;有天和我们组去年来的小朋友聊天，他说了一个观点我觉得很有道理：做能给自己产生经济效益的东西，你才有动力持续下去。虽然听起来功利，但不无道理。&lt;/p&gt;

    &lt;p&gt;这么一个插件显然不能挣钱，它属于第二种。本次更新的功能其实在半年前就有网友提过需求，见 &lt;a href=&quot;https://github.com/mzlogin/vim-markdown-toc/issues/6&quot;&gt;#6&lt;/a&gt;，但我却迟迟没有动手。半年后的某个夜里，突然就决定要把这些做出来，并且花了几个小时就做完了。究其原因，还是因为自己现在有了需求，我现在要维护几份比较长的 Markdown 文档，如果每次手动去删除已有 toc 然后再次生成，虽然比纯手工写 toc 要不知道方便和准确到哪里去了，但归根结底还是不够完美。果然最后用着自己做的功能替自己省下不少重复劳动时，那种感觉也是很爽的。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;酒香也怕巷子深。&lt;/p&gt;

    &lt;p&gt;发布了个人的项目后，适当地在相关的社区进行推广，让更多的人享受到你的劳动成果，帮助验证和反馈，也能给自己带来更多的成就感和关注度。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;</content><author><name>JiuJiuShu</name></author><summary type="html">前几天，第一款由我独立开发的 Vim 插件 vim-markdown-toc 升级了功能，发布了 v1.0 版本。</summary></entry><entry><title type="html">一道在知乎很火的 Java 题——如何输出 ab</title><link href="http://mazhuang.org/2016/09/20/java-output-ab/" rel="alternate" type="text/html" title="一道在知乎很火的 Java 题——如何输出 ab" /><published>2016-09-20T00:00:00+00:00</published><updated>2016-09-20T00:00:00+00:00</updated><id>http://mazhuang.org/2016/09/20/java-output-ab</id><content type="html" xml:base="http://mazhuang.org/2016/09/20/java-output-ab/">&lt;p&gt;这是一个源自知乎的话题，原贴链接：&lt;a href=&quot;https://www.zhihu.com/question/50801791&quot;&gt;一道百度的面试题，有大神会嘛？&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;虽然我不是大神，但我也点进去看了一下，思考了一会之后有了一些思路，然后去看其它人的答案的时候果然全都已经被各路大神们先想到并贴出来了，所以我就不去凑热闹写重复答案了，整理一下网友们的智慧在这里自娱自乐好了。&lt;/p&gt;

&lt;h2 id=&quot;题目&quot;&gt;题目&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/java/output-ab.jpg&quot; alt=&quot;java-output-ab&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;思路一&quot;&gt;思路一&lt;/h2&gt;

&lt;p&gt;作为一个多年前也见过不少笔试题的少年，看到这个题目的第一想法是脑筋急转弯——注入一段逻辑直接改变原 if 结构。&lt;/p&gt;

&lt;h3 id=&quot;解法一&quot;&gt;解法一&lt;/h3&gt;

&lt;p&gt;填入内容 &lt;code class=&quot;highlighter-rouge&quot;&gt;true){System.out.print(&quot;a&quot;);}if(false&lt;/code&gt;。&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;类似地也可以填入 &lt;code class=&quot;highlighter-rouge&quot;&gt;true){System.out.print(&quot;ab&quot;);return;}if(false&lt;/code&gt; 等。&lt;/p&gt;

&lt;p&gt;当初大学时单纯的少年可是很难想出这样的套路的，时间改变了我们啊。&lt;/p&gt;

&lt;h2 id=&quot;思路二&quot;&gt;思路二&lt;/h2&gt;

&lt;p&gt;如果正经遵从题目的原代码结构，那就得想办法构造一段代码，既能输出 &lt;code class=&quot;highlighter-rouge&quot;&gt;a&lt;/code&gt;，又能返回 &lt;code class=&quot;highlighter-rouge&quot;&gt;false&lt;/code&gt;。&lt;/p&gt;

&lt;h3 id=&quot;解法二&quot;&gt;解法二&lt;/h3&gt;

&lt;p&gt;我也想到能否使用 &lt;code class=&quot;highlighter-rouge&quot;&gt;System.out.print&lt;/code&gt; 的返回值来做文章，但奈何并不记得它返回什么，首先让我们复习一下 &lt;code class=&quot;highlighter-rouge&quot;&gt;PrintStream&lt;/code&gt; 的 &lt;code class=&quot;highlighter-rouge&quot;&gt;print&lt;/code&gt;、&lt;code class=&quot;highlighter-rouge&quot;&gt;println&lt;/code&gt; 和 &lt;code class=&quot;highlighter-rouge&quot;&gt;printf&lt;/code&gt; 方法的区别：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;方法&lt;/th&gt;
      &lt;th&gt;功能&lt;/th&gt;
      &lt;th&gt;返回值&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;print&lt;/td&gt;
      &lt;td&gt;打印一个值或者对象&lt;/td&gt;
      &lt;td&gt;void&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;println&lt;/td&gt;
      &lt;td&gt;打印并换行&lt;/td&gt;
      &lt;td&gt;void&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;printf&lt;/td&gt;
      &lt;td&gt;格式化打印&lt;/td&gt;
      &lt;td&gt;PrintStream&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;所以适用的是 &lt;code class=&quot;highlighter-rouge&quot;&gt;printf&lt;/code&gt;，它的返回值是 &lt;code class=&quot;highlighter-rouge&quot;&gt;PrintStream&lt;/code&gt; 类型的 &lt;code class=&quot;highlighter-rouge&quot;&gt;System.out&lt;/code&gt;，判它是否为空即可。&lt;/p&gt;

&lt;p&gt;填入内容 &lt;code class=&quot;highlighter-rouge&quot;&gt;System.out.printf(&quot;a&quot;) == null&lt;/code&gt;。&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;经测试填入 &lt;code class=&quot;highlighter-rouge&quot;&gt;System.out.append(&quot;a&quot;) == null&lt;/code&gt; 也是可以达到效果的。&lt;/p&gt;

&lt;h3 id=&quot;解法三&quot;&gt;解法三&lt;/h3&gt;

&lt;p&gt;仍然是思路二，但从匿名内部类来作文章。&lt;/p&gt;

&lt;p&gt;实现代码：&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这里利用的知识点是匿名内部类可以声明基类没有的新方法并且马上调用。&lt;/p&gt;

&lt;h3 id=&quot;解法四&quot;&gt;解法四&lt;/h3&gt;

&lt;p&gt;使用 Java 8 里的 lambda 来实现思路二。&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BooleanSupplier&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;})).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAsBoolean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;严格来讲这个不一定能算作正确答案，因为要增加 &lt;code class=&quot;highlighter-rouge&quot;&gt;import java.util.function.BooleanSupplier;&lt;/code&gt;。&lt;/p&gt;

&lt;h2 id=&quot;脑洞大开&quot;&gt;脑洞大开&lt;/h2&gt;

&lt;p&gt;讲完严肃的解法，来看看网友 &lt;a href=&quot;https://www.zhihu.com/people/qiong-xiao-zi-158&quot;&gt;穷小子&lt;/a&gt; 开脑洞的思路：&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//    if ( ) {&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//    } else {&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//    }&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如果没有特意说明只能在括号里加东西，倒真是个妙计！&lt;/p&gt;

&lt;p&gt;同样看得我一愣一愣的还有 &lt;a href=&quot;https://www.zhihu.com/people/caiwei710&quot;&gt;caiwei&lt;/a&gt; 同学的答案，他和朋友们发现题目里少写了个大括号（真的），于是我们看到他的朋友老方的解决方案：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/java/add-brace.jpg&quot; alt=&quot;add-brace&quot; /&gt;&lt;/p&gt;

&lt;p&gt;真是防不胜防啊~不过我喜欢！:+1:&lt;/p&gt;

&lt;h2 id=&quot;参考&quot;&gt;参考&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.zhihu.com/question/50801791/answer/122781965&quot;&gt;RednaxelaFX 的回答&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.zhihu.com/question/50801791/answer/122773831&quot;&gt;仓鼠君 的回答&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.zhihu.com/question/50801791/answer/122769426&quot;&gt;放开那女孩 的回答&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.zhihu.com/question/50801791/answer/122863062&quot;&gt;穷小子 的回答&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.zhihu.com/question/50801791/answer/122795854&quot;&gt;caiwei 的回答&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>JiuJiuShu</name></author><summary type="html">这是一个源自知乎的话题，原贴链接：一道百度的面试题，有大神会嘛？</summary></entry><entry><title type="html">C++ 程序员的 Java 指南</title><link href="http://mazhuang.org/2016/08/30/java-guide-to-cpp-programmers/" rel="alternate" type="text/html" title="C++ 程序员的 Java 指南" /><published>2016-08-30T00:00:00+00:00</published><updated>2016-08-30T00:00:00+00:00</updated><id>http://mazhuang.org/2016/08/30/java-guide-to-cpp-programmers</id><content type="html" xml:base="http://mazhuang.org/2016/08/30/java-guide-to-cpp-programmers/">&lt;p&gt;这是一个 C++ 程序员自己总结的 Java 学习中应该注意的点。&lt;/p&gt;

&lt;h2 id=&quot;缘起&quot;&gt;缘起&lt;/h2&gt;

&lt;p&gt;因工作原因从 Windows 客户端开发转为 Android 客户端开发，所以主要的开发语言也由 C++ 变为了 Java，在学习 Java 的过程中，即享受到 Java 的自带程序库的丰富带来的便捷，也遇到一些与 C++ 里的习惯不符需要注意的地方。&lt;/p&gt;

&lt;p&gt;初学时的计划是看完一本 Java 教材，过程中整理 C++ 程序员学习 Java 需要注意的点，然后对照写一篇《C++ 程序员的 Java 指南》，但最后懒癌犯了，只整理了一部分不同点，要形成一份「指南」还有很长的路要走，暂且把这个坑挖在这里，如果哪天心血来潮就填上。&lt;/p&gt;

&lt;p&gt;一个知乎问答下有我的答案，与本篇文章内容同步：&lt;a href=&quot;https://www.zhihu.com/question/49770330/answer/118395115?from=profile_answer_card&quot;&gt;习惯写C++的人突然转去写Java，会有什么样的坑？&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;注意点&quot;&gt;注意点&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;char 是两个字节（字符及字符串默认都是 utf-16）。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;浮点数默认是 double，所以要写成 float f = (float)5.0 或 5.0f，不然会报错。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;整数除整数可能导致除零异常，而浮点数不会。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;break 和 continue 能够使用 flag 来跳出和继续指定循环。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;boolean 值只能是 true 和 false，不能从整形等其它值转换而来。用于字符串连接的时候会自动转换成「true」和「false」。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;if 里只能接受 boolean 值，所以 C++ 里的好习惯 if (5 == var) 在 Java 里不再必要，少写了一个 = 的时候 IDE 和编译器都会提示你。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;new Person(); 必须有 ()，否则编译不过。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;数组的声明方式推荐 int[] nArray = new int[4]; 或者 int[] nArray = {1,2,3};，第一种称为动态初始化，第二种称为静态初始化。动态初始化时，系统按如下规则分配初始值：整形为 0，浮点型为 0.0，字符型为’\u0000’，布尔型为 false，引用类型为 null。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;当系统加载类或创建该类的实例时，系统自动为成员变量分配内存空间，并在分配内存空间后，自动为成员变量指定初始值。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;局部变量定义后，必须经过显式初始化后才能使用，系统不会为局部变量执行初始化。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;访问控制符有 private、default、protected、public。private 只能在同一个类中访问，default 能在同一个类、同一个包中访问，protected 能在同一个类、同一个包、子类中访问，public 能在全局范围内访问。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;在构造器中可以使用 this(params) 来调用本类的其它构造器，使用 super(params) 来调用父类构造器，只能书写在本构造器第一行，所以它们不能同时出现。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;使用 super 调用父类中的实例方法，使用父类类名调用父类中的类方法。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;如果父类方法具有 private 访问权限，则该方法对其子类是隐藏的，因此其子类无法访问和重写该方法。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;java 中有 instanceof 运算符，c++ 中对应的 RTTI 方式是（typeid）？instanceof 运算符的前一个操作数通常是一个引用类型的变量，后一个操作数通常是一个类（也可以是接口，可以把接口理解成一种特殊的类），它用于判断前面的对象是否是后面的类，或者其子类、实现类的实例。如果是，则返回 true，否则返回 false。判断是否是同一个类的实例时应使用 obj1.getClass()==obj2.getClass()。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;初始化块和声明属性时指定初始值，这些按源程序中排列顺序执行。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;java 中只有值传递。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;对 private 方法，即使它使用 final 修饰，在子类中也可以定义一个相同的，因为这是子类定义了一个新方法，并非重写。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;final 和 abstract 永远不能同时使用；static 和 abstrace 不能同时修饰某个方法；private 和 abstrace 不能同时修饰某个方法。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;java 中的 abstract 方法不能有方法体，c++ 中的 pure virtual 函数可以有实现。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;interface 的方法只能是 public abstract 的，属性只能是 public static final 的，使用 private 等修饰编译会报错。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;从内部类里引用外部类的属性或者方法时，可以用命 OuterClass.this.。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;非静态内部类里不能有静态成员。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;内部类可以使用 static 修饰，外部类不行。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;从外部类外创建内部非静态类的语法：OuterClass.InnerClass varName = OuterInstance.new InnerConstructor();
从外部类外创建内部静态类的语法：OuterClass.InnerClass varName = new OuterClass.InnerConstructor();&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;内部类不可能被外部类的子类中重写，因为命名空间不同。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;纠误一处：《疯狂 Java 讲义》P214 讲道「如果匿名内部类需要访问外部类的局部变量，则必须使用 final 修饰符来修饰外部类的局部变量，否则系统将报错。经验证，只要这个局部变量在后续不改变其值，即使它不以 final 修饰，但实际表现是有效的 final 时，在 Java 8 环境下编译后会自动为它加上 final，不报错。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;switch 表达式可以使用整形或者枚举类实例（从 Java 7 开始，可以使用 String 对象了，参考：&lt;a href=&quot;http://docs.oracle.com/javase/7/docs/technotes/guides/language/strings-switch.html&quot;&gt;Strings in switch Statements&lt;/a&gt;）。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Set 判断两个对象是否相同不是使用 == 运算符，而是根据 equals 方法。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;HashSet 判断两个元素相等的标准是两个对象通过 equals 方法比较相等，并且两个对象的 hashCode() 方法返回值也相等。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;foreach 循环仅适用于实现了 Iterable 接口的 Java array 和 Collection 类。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;遍历任何 Collection（例如 Map、Set 或 List）时要删除元素只能使用 Iterator 的 remove 方法。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;</content><author><name>JiuJiuShu</name></author><summary type="html">这是一个 C++ 程序员自己总结的 Java 学习中应该注意的点。</summary></entry><entry><title type="html">在 Vim 里为 Markdown 文档展示导航窗格</title><link href="http://mazhuang.org/2016/08/03/add-outline-for-markdown-in-vim/" rel="alternate" type="text/html" title="在 Vim 里为 Markdown 文档展示导航窗格" /><published>2016-08-03T00:00:00+00:00</published><updated>2016-08-03T00:00:00+00:00</updated><id>http://mazhuang.org/2016/08/03/add-outline-for-markdown-in-vim</id><content type="html" xml:base="http://mazhuang.org/2016/08/03/add-outline-for-markdown-in-vim/">&lt;p&gt;假设我们正在 Vim 里编辑一个很长的 Markdown 文档，这时想跳转到另一个章节去查看或编辑内容，可以怎么做？&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;查找章节标题。&lt;/li&gt;
  &lt;li&gt;上下翻页。&lt;/li&gt;
  &lt;li&gt;记得行号，精确跳转（请收下我的膝盖）。&lt;/li&gt;
  &lt;li&gt;…&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;不知你此时感受如何，反正我是无比想念 Word 的导航窗格，各种编程 IDE 的 Outline。&lt;/p&gt;

&lt;p&gt;但等等，我们正在用编辑器之神 Vim 诶！无论想弄啥折腾折腾就有了。&lt;/p&gt;

&lt;h2 id=&quot;最终效果&quot;&gt;最终效果&lt;/h2&gt;

&lt;p&gt;我的完整 Vim 配置托管在 GitHub，可供参考：&lt;a href=&quot;https://github.com/mzlogin/config-files&quot;&gt;config-files&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/vim/vim-markdown-outline.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;实现步骤&quot;&gt;实现步骤&lt;/h2&gt;

&lt;h3 id=&quot;安装-tagbar&quot;&gt;安装 tagbar&lt;/h3&gt;

&lt;p&gt;这里我们借助于 tagbar 插件实现导航窗格。当然 tagbar 的功能远不限于此，可以为 C、C++、Python 和 Java 等很多语言提供类和方法列表视图等等，详见 &lt;a href=&quot;https://github.com/majutsushi/tagbar&quot;&gt;tagbar&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;推荐使用 &lt;a href=&quot;https://github.com/VundleVim/Vundle.vim&quot;&gt;Vundle&lt;/a&gt; 管理 Vim 插件，这样就可以简单几步安装插件了。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;在 vimrc 文件里添加如下内容：&lt;/p&gt;

    &lt;div class=&quot;language-viml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Plugin &lt;span class=&quot;s1&quot;&gt;'majutsushi/tagbar'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;执行 &lt;code class=&quot;highlighter-rouge&quot;&gt;:so $MYVIMRC&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;执行 &lt;code class=&quot;highlighter-rouge&quot;&gt;:PluginInstall&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;安装-exuberant-ctags&quot;&gt;安装 Exuberant ctags&lt;/h3&gt;

&lt;p&gt;tagbar 正常工作依赖于 Vim 7.0+ 和 Exuberant ctags。&lt;/p&gt;

&lt;p&gt;下载地址：&lt;a href=&quot;http://ctags.sourceforge.net/&quot;&gt;http://ctags.sourceforge.net/&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;下载后将 ctags 可执行文件放置到一个在 PATH 环境变量的文件夹里，或者 Vim 安装目录的 Vim74 文件夹下，比如我是将 ctags.exe 放在 &lt;code class=&quot;highlighter-rouge&quot;&gt;D:\Program Files (x86)\Vim\vim74&lt;/code&gt; 文件夹下。&lt;/p&gt;

&lt;h3 id=&quot;配置-tagbar-显示-markdown-导航窗格&quot;&gt;配置 tagbar 显示 Markdown 导航窗格&lt;/h3&gt;

&lt;p&gt;tagbar 默认并不支持 Markdown 文件，但配置一下就好了。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;给 ~/.ctags 文件（Windows 下是 &lt;code class=&quot;highlighter-rouge&quot;&gt;C:\Users\&amp;lt;username&amp;gt;\.ctags&lt;/code&gt; 里增加如下内容，没有这个文件就新建一个：&lt;/p&gt;

    &lt;div class=&quot;language-viml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;--&lt;/span&gt;langdef&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;markdown
&lt;span class=&quot;p&quot;&gt;--&lt;/span&gt;langmap&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;markdown&lt;span class=&quot;p&quot;&gt;:.&lt;/span&gt;md
&lt;span class=&quot;p&quot;&gt;--&lt;/span&gt;regex&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;markdown&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/^#{1}[ \t]*([^#]+.*)/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; \&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/h,headings/&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;--&lt;/span&gt;regex&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;markdown&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/^#{2}[ \t]*([^#]+.*)/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;   \&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/h,headings/&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;--&lt;/span&gt;regex&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;markdown&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/^#{3}[ \t]*([^#]+.*)/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;     \&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/h,headings/&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;--&lt;/span&gt;regex&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;markdown&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/^#{4}[ \t]*([^#]+.*)/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;       \&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/h,headings/&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;--&lt;/span&gt;regex&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;markdown&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/^#{5}[ \t]*([^#]+.*)/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;         \&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/h,headings/&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;--&lt;/span&gt;regex&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;markdown&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/^#{6}[ \t]*([^#]+.*)/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;           \&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/h,headings/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;这表示提取 Markdown 文件里的一到六级标题，并使用空格缩进表示层次。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;给你的 vimrc 文件里增加如下内容：&lt;/p&gt;

    &lt;div class=&quot;language-viml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;g:tagbar_type_markdown&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;se&quot;&gt;        \&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ctagstype'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'markdown'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;se&quot;&gt;        \&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'kinds'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
&lt;span class=&quot;se&quot;&gt;                \&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'h:headings'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;se&quot;&gt;        \&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;se&quot;&gt;    \&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'sort'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;配置 tagbar 支持 Markdown。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;更多自定义配置&quot;&gt;更多自定义配置&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;现在你可以使用 &lt;code class=&quot;highlighter-rouge&quot;&gt;:TagbarToggle&amp;lt;CR&amp;gt;&lt;/code&gt; 来打开导航窗格了，但每次开关导航窗格都要敲这么长一串命令毕竟不够方便，配置快捷键来操作更顺手，在你的 vimrc 文件里增加一个映射：&lt;/p&gt;

    &lt;div class=&quot;language-viml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nnoremap &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;leader&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;tb &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;TagbarToggle&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;CR&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;现在你可以使用 &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;leader&amp;gt;tb&lt;/code&gt; 来随时开/关导航窗格了。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;导航窗格默认是在右边，如果你也像我一样喜欢它在左边，也想指定它的宽度，可以在你的 vimrc 文件里配置：&lt;/p&gt;

    &lt;div class=&quot;language-viml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;g:tagbar_width&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;30&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;g:tagbar_left&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;至此，大功告成了！&lt;/p&gt;

&lt;h2 id=&quot;参考链接&quot;&gt;参考链接&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/majutsushi/tagbar/issues/70&quot;&gt;majutsushi/tagbar#70&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/majutsushi/tagbar/wiki&quot;&gt;Support for additional filetypes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>JiuJiuShu</name></author><summary type="html">假设我们正在 Vim 里编辑一个很长的 Markdown 文档，这时想跳转到另一个章节去查看或编辑内容，可以怎么做？</summary></entry><entry><title type="html">Kloudsec 挂了，GitHub Pages 去 HTTPS 化</title><link href="http://mazhuang.org/2016/07/11/remove-https/" rel="alternate" type="text/html" title="Kloudsec 挂了，GitHub Pages 去 HTTPS 化" /><published>2016-07-11T00:00:00+00:00</published><updated>2016-07-11T00:00:00+00:00</updated><id>http://mazhuang.org/2016/07/11/remove-https</id><content type="html" xml:base="http://mazhuang.org/2016/07/11/remove-https/">&lt;p&gt;前天收到来自 Kloudsec 的邮件，说 Kloudsec 将于 2016/08/01 停止服务。Bad news，请容许我做一个悲伤的表情。&lt;/p&gt;

&lt;h2 id=&quot;邮件原文&quot;&gt;邮件原文&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hi all,&lt;/p&gt;

  &lt;p&gt;It is with great sadness that I have to inform you that Kloudsec is shutting down.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Why is Kloudsec shutting down?&lt;/strong&gt;&lt;/p&gt;

  &lt;ol&gt;
    &lt;li&gt;We have been funding Kloudsec out of our own pocket&lt;/li&gt;
    &lt;li&gt;Kloudsec is very expensive to maintain (upwards to $10000 / month)&lt;/li&gt;
    &lt;li&gt;We are unable to make money from Kloudsec, nor raise any funds for it&lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;&lt;strong&gt;We will shut Kloudsec down on 1st August&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;From now till then, we will not be maintaining the service.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Migrating out of Kloudsec&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;Migrating out of Kloudsec is extremely simple. All you have to do is to point your domain back at its origin server.&lt;/p&gt;

  &lt;p&gt;You will lose the HTTPS cert. But you can fix that by&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;either issuing your own LetsEncrypt certificate&lt;/li&gt;
    &lt;li&gt;or using Cloudflare.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;&lt;strong&gt;Lessons learnt&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;From the start, we are extremely lucky to have a small revenue stream that let us to experiment with cool products. And Kloudsec is one of our biggest experiment.&lt;/p&gt;

  &lt;p&gt;There are a couple of things we did right, and a couple we did wrong.&lt;/p&gt;

  &lt;p&gt;We did right by having the right team come together, building a seriously sophiscated product. (Thank you Ivan and Bach)&lt;/p&gt;

  &lt;p&gt;We did wrong by building a sophiscated product that made it hard for a small team to maintain, let alone scale.&lt;/p&gt;

  &lt;p&gt;We did wrong by building a product that was not immediately useful enough so much so that people will pay for.&lt;/p&gt;

  &lt;p&gt;We did wrong by building a product that was too expensive to maintain.&lt;/p&gt;

  &lt;p&gt;We did wrong by assuming that traction solves all ailments. Not in Singapore, you don’t. There is no good venture money for real hard-tech software startups in Singapore.&lt;/p&gt;

  &lt;p&gt;We did right with pulling the plug so we can learn from these mistakes and work on the next product.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;What’s next for us&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;From Kloudsec, we identified a few niche problems that we will be looking to solve. In other words, we will continually be building.&lt;/p&gt;

  &lt;p&gt;And you can be sure from our next product onwards, we will charge right from day 1 so we can sustain the product financially.&lt;/p&gt;

  &lt;p&gt;Lastly, thank you!&lt;/p&gt;

  &lt;p&gt;Thank you. Most of you have spoken to me, or read the posts I’ve written on Github, on Hacker News, or Producthunt about Kloudsec. You guys took a leap of faith in trusting this small unknown team and product, and used us.&lt;/p&gt;

  &lt;p&gt;I’m sorry to disappoint you with this piece of news, but I’ll try better next time.&lt;/p&gt;

  &lt;p&gt;If you like, you can follow me on Twitter at @nubela. You can also contact me at anytime at steven@nubela.co&lt;/p&gt;

  &lt;p&gt;Steven Goh.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;我的决定&quot;&gt;我的决定&lt;/h2&gt;

&lt;p&gt;Sigh!&lt;/p&gt;

&lt;p&gt;想起五月份的时候我还欢天喜地地给博客 HTTPS 化了，并为此写了一篇博客 &lt;a href=&quot;http://mazhuang.org/2016/05/21/enable-https-for-github-pages/&quot;&gt;为绑定域名的 GitHub Pages 启用 HTTPS&lt;/a&gt;，还将它推荐到了 &lt;a href=&quot;http://gold.xitu.io/entry/574f7ea17db2a20055c3b818/detail&quot;&gt;掘金&lt;/a&gt;，收获了 64 次收藏，并在那篇文章下创下了我个人博客单篇评论数最多的记录。&lt;/p&gt;

&lt;p&gt;没想到还没等到 Kloudsec 第一次为我的域名证书自动续期，它家的服务就要关停了。&lt;/p&gt;

&lt;p&gt;但也没有办法，使用第三方的服务，特别是初创公司的服务本就有这种风险。&lt;/p&gt;

&lt;p&gt;本来 GitHub Pages + Custom Domain + HTTPS 也还有其它解决方案，但我已不想再折腾了，多引入一层中间服务，就多一层出状况的风险，我只是想作一名安静地写博客的美男子啊。&lt;/p&gt;

&lt;p&gt;所以决定去掉自定义域名的 HTTPS，恢复 HTTP，现在 GitHub Pages 已经支持 &lt;code class=&quot;highlighter-rouge&quot;&gt;*.github.io&lt;/code&gt; 域名的 HTTPS，除非哪天它原生支持 Custom Domain 的 HTTPS，否则我不再折腾这个事情。&lt;/p&gt;

&lt;h2 id=&quot;采取的措施&quot;&gt;采取的措施&lt;/h2&gt;

&lt;p&gt;当初之所以想开启 HTTPS 的一个重要原因就是 Google 收录了博客的 HTTPS 链接，但是证书不对导致用户打不开或者有警告，既然使用自定义域名没有办法让证书对，那就让 Google 不收录 HTTPS 的链接吧。&lt;/p&gt;

&lt;h3 id=&quot;告诉-google-不收录-https-链接&quot;&gt;告诉 Google 不收录 HTTPS 链接&lt;/h3&gt;

&lt;p&gt;如果一个页面使用 HTTPS 和 HTTP 都能访问，那如果想 Google 只收录 HTTP 版，而不收录 HTTPS 版，那可以在页面的 &lt;code class=&quot;highlighter-rouge&quot;&gt;head&lt;/code&gt; 里添加 &lt;code class=&quot;highlighter-rouge&quot;&gt;canonical&lt;/code&gt; 给爬虫以建议，具体方法如下：&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;canonical&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http 开头的 URL&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><author><name>JiuJiuShu</name></author><summary type="html">前天收到来自 Kloudsec 的邮件，说 Kloudsec 将于 2016/08/01 停止服务。Bad news，请容许我做一个悲伤的表情。</summary></entry><entry><title type="html">简化 kramdown 列表嵌套内容缩进的 Vim 插件</title><link href="http://mazhuang.org/2016/06/28/vim-kramdown-tab/" rel="alternate" type="text/html" title="简化 kramdown 列表嵌套内容缩进的 Vim 插件" /><published>2016-06-28T00:00:00+00:00</published><updated>2016-06-28T00:00:00+00:00</updated><id>http://mazhuang.org/2016/06/28/vim-kramdown-tab</id><content type="html" xml:base="http://mazhuang.org/2016/06/28/vim-kramdown-tab/">&lt;p&gt;kramdown 的列表嵌套内容的缩进规则很「奇葩」，不是使用自然的 Tab 缩进。&lt;/p&gt;

&lt;h2 id=&quot;问题&quot;&gt;问题&lt;/h2&gt;

&lt;p&gt;kramdown 的作者对列表嵌套内容的缩进规则的 &lt;a href=&quot;https://github.com/gettalong/kramdown/issues/311#issuecomment-185040348&quot;&gt;描述&lt;/a&gt; 是：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;kramdown does not allow 4 space indent, ……&lt;/p&gt;

  &lt;p&gt;Indentation for list items is &lt;strong&gt;always&lt;/strong&gt; calculated based on the first non-space character after the list item marker.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;在年初 GitHub 宣布 GitHub Pages 服务将只支持 kramdown 这个 Markdown 解析引擎时，我曾经总结过从 Redcarpet 迁移到 kramdown 需要做的一些更改，&lt;a href=&quot;https://mazhuang.org/2016/02/04/switch-to-kramdown-from-redcarpet/&quot;&gt;将 GitHub Pages 从 Redcarpet 切换到 kramdown&lt;/a&gt; 里有说到，嵌套在列表项里的代码块，如果不按如上规则做缩进的话，将会解析不正常。&lt;/p&gt;

&lt;p&gt;比如：&lt;/p&gt;

&lt;div class=&quot;language-markdown highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;1.&lt;/span&gt; list item one&lt;span class=&quot;sb&quot;&gt;

    ```python
    print 'hello, world'
    ```

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;2.&lt;/span&gt; list item two
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;解析后的结果是：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;list item one&lt;/p&gt;

    &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'hello, world'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;list item two&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;这当然不是我们想要的，我们应该如何写呢？&lt;/p&gt;

&lt;div class=&quot;language-markdown highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;1.&lt;/span&gt; list item one

   &lt;span class=&quot;sb&quot;&gt;```&lt;/span&gt;python
   print 'hello, world'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;list item two
```&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;解析后的结果是：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;list item one&lt;/p&gt;

    &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'hello, world'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;list item two&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;看出来区别了吗？没错，这种情况下代码块必须缩进三个空格，因为除开列表记号后的第一个非空字符的缩进是三。&lt;/p&gt;

&lt;p&gt;那么问题来了，有时候是有序列表，序号是个位数时需要缩进三个空格，序号是两位数时需要缩进四个空格，序号是三位数时（弄这么大的列表是闹哪样？）需要缩进五个空格……有时候是无序列表，只需要缩进两个空格。&lt;/p&gt;

&lt;p&gt;当然这是最简单的一级嵌套的情况，如果是多级列表嵌套，那情况就更复杂了，每一次都去手打空格缩进吗？作为一名 Vimer，当然 say no！&lt;/p&gt;

&lt;p&gt;所以为此我做了一个简单的小 Vim 插件专门用于解决此问题。&lt;/p&gt;

&lt;h2 id=&quot;下载地址&quot;&gt;下载地址&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mzlogin/vim-kramdown-tab&quot;&gt;vim-kramdown-tab&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;使用方法&quot;&gt;使用方法&lt;/h2&gt;

&lt;p&gt;安装完此插件后，在你需要对列表嵌套内容进行缩进时，不用掰着手指头去数要打多少个空格了，只用按 &lt;kbd&gt;Leader&lt;/kbd&gt;&lt;kbd&gt;Tab&lt;/kbd&gt; 就好了。&lt;/p&gt;

&lt;h2 id=&quot;安装方法&quot;&gt;安装方法&lt;/h2&gt;

&lt;p&gt;推荐使用 &lt;a href=&quot;http://github.com/VundleVim/Vundle.Vim&quot;&gt;Vundle&lt;/a&gt; 来管理你的 Vim 插件，这样你就可以简单三步完成安装：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;在你的 vimrc 文件中添加如下内容：&lt;/p&gt;

    &lt;div class=&quot;language-markdown highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Plugin 'mzlogin/vim-kramdown-tab'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;:so $MYVIMRC&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;:PluginInstall&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;屏幕截图&quot;&gt;屏幕截图&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/mzlogin/vim-kramdown-tab/master/screenshots/test.gif&quot; alt=&quot;vim-kramdown-tab screenshot&quot; /&gt;&lt;/p&gt;</content><author><name>JiuJiuShu</name></author><summary type="html">kramdown 的列表嵌套内容的缩进规则很「奇葩」，不是使用自然的 Tab 缩进。</summary></entry><entry><title type="html">为绑定域名的 GitHub Pages 启用 HTTPS</title><link href="http://mazhuang.org/2016/05/21/enable-https-for-github-pages/" rel="alternate" type="text/html" title="为绑定域名的 GitHub Pages 启用 HTTPS" /><published>2016-05-21T00:00:00+00:00</published><updated>2016-05-21T00:00:00+00:00</updated><id>http://mazhuang.org/2016/05/21/enable-https-for-github-pages</id><content type="html" xml:base="http://mazhuang.org/2016/05/21/enable-https-for-github-pages/">&lt;p&gt;&lt;strong&gt;Update 2016/07/11: 收到 Kloudsec 的邮件，说将在 2016/08/01 停止服务，所以如下方法在那之后会无法使用，寻找 GitHub Pages + Custom Domain + HTTPS 的方法的童鞋请不要再尝试 Kloudsec 了，去找一找别的方法吧。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;虽然现在各种网站都在 HTTPS 化，甚至有的个人网站在添加链接的说明里明确声明只与启用 HTTPS 的网站交换链接，但一直以来我启用 HTTPS 的需求并不强烈，又加上有懒癌在身，实在是没有动力去折腾，直到最近发生了几件事情。&lt;/p&gt;

&lt;h2 id=&quot;缘起&quot;&gt;缘起&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;最近一段时间也不知道是 GitHub Pages 做了调整还是 Google 的收录策略有了变化，Google 收录我的博客页面都是同时收录了 HTTP 和 HTTPS 两种版本，而很遗憾这个博客并没有配置有效的 SSL 证书，所以点开的是一个 HTTPS 的链接就会被浏览器提示连接不可信，有安全风险云云，虽然访问量不大，但这样体验太差，也是蛮闹心的。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;恰逢知乎上有人邀我答题 &lt;a href=&quot;https://www.zhihu.com/question/33495825&quot;&gt;Github Pages 绑定了个人域名，怎么使用 HTTPS 访问而证书不报错呢？&lt;/a&gt;。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;三月份的时候 &lt;a href=&quot;https://github.com/nubela&quot;&gt;@nubela&lt;/a&gt; 发邮件邀请我试用他为绑定域名的 GitHub Pages 制作的一键启用 HTTPS 的工具，而我当时答复的是实在太忙，后来有空再折腾。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;几个理由加在一起，终于战胜了懒癌，让我动了起来。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/github/github-pages-with-https.png&quot; alt=&quot;enable https for GitHub Pages&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;步骤&quot;&gt;步骤&lt;/h2&gt;

&lt;p&gt;@nubela 提供的工具非常友好且方便，第一次使用的我只简单做了一些配置，没有对 GitHub Pages 仓库做任何更改就实现了全站 HTTPS 化，自动使用了 Let’s Encrypt 提供的免费 SSL 证书，有效期 90 天，Kloudsec 会在它过期前自动续期，换句话说，只要 Kloudsec 还活着并且免费提供这项服务的话，后面就不用管这个了。&lt;/p&gt;

&lt;p&gt;记录操作步骤如下：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;打开 Kloudsec 为 GitHub Pages 提供的工具 &lt;a href=&quot;https://kloudsec.com/github-pages/new&quot;&gt;Kloudsec for GitHub Pages&lt;/a&gt;。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;按工具里的要求填好三个部分的内容，依次是&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;用于注册 Kloudsec 的邮箱和为 Kloudsec 账户设置的密码。&lt;/p&gt;

        &lt;p&gt;&lt;img src=&quot;/images/posts/github/https-kloudsec-account.png&quot; alt=&quot;Register a Kloudsec account&quot; /&gt;&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;GitHub Pages 项目的 URL 和绑定的域名。&lt;/p&gt;

        &lt;p&gt;&lt;img src=&quot;/images/posts/github/https-config-gh.png&quot; alt=&quot;Configure your Github Page&quot; /&gt;&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;到你的域名解析控制面板里添加工具要求的 A 记录。&lt;/p&gt;

        &lt;p&gt;&lt;img src=&quot;/images/posts/github/https-config-dns.png&quot; alt=&quot;Configure your DNS settings&quot; /&gt;&lt;/p&gt;

        &lt;p&gt;&lt;strong&gt;注意：&lt;/strong&gt; 每个 A 记录应只保留一个 IP，比如之前将 @ 做了 A 记录到 GitHub Pages 的 IP 上了，那现在将其删除，并添加工具提供的 IP。&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;去上一步填写的邮箱里收邮件，激活 Kloudsec 账号并登录。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;进入到 Dashboard 的 SETTINGS，在 Web Server Origin IP / Hostname 一栏填上 GitHub Pages 的可用 IP，比如我填写的是 &lt;code class=&quot;highlighter-rouge&quot;&gt;103.245.222.133&lt;/code&gt;。&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/posts/github/https-config-server-ip.png&quot; alt=&quot;Web Server Origin IP&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;开启 HTTP 自动跳转到 HTTPS。&lt;em&gt;（非必须，按自己需求来。）&lt;/em&gt;&lt;/p&gt;

    &lt;p&gt;进入到 Dashboard 的 PROTECTION，点击 SSL Encryption 里的按钮，选择你的网站：&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/posts/github/https-config-redirection-1.png&quot; alt=&quot;PROTECTION&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;将 Automatically redirect to HTTPS site? 下面的开关切换到 ON：&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/posts/github/https-config-redirection-2.png&quot; alt=&quot;Automatically redirect to HTTPS site?&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;进入到 Dashboard 的 PLUGIN STORE，启用 Offline Protection、Page Optimizer 和 One-Click Encryption，一般来讲免费的计划就够用了，如果你想要使用付费计划提供更多更好的服务，那按需选择吧。&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/posts/github/https-config-plugin-store.png&quot; alt=&quot;Plugin Store&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;恭喜你已完成所有步骤！等待几分钟生效即可。&lt;/p&gt;

&lt;h2 id=&quot;后话&quot;&gt;后话&lt;/h2&gt;

&lt;h3 id=&quot;实现原理&quot;&gt;实现原理&lt;/h3&gt;

&lt;p&gt;看 Kloudsec 的文档里描述的 &lt;a href=&quot;https://docs.kloudsec.com/#section-how-does-it-work-&quot;&gt;HOW DOES IT WORK?&lt;/a&gt;，它提供的服务处于我们的网站服务器和我们的网站访问者之间，其原理是缓存了我们服务器上的页面，所以实际用户建立的 HTTPS 连接是用户的浏览器与 Kloudsec 之间的。&lt;/p&gt;

&lt;h3 id=&quot;使用-kloudsec-的好处&quot;&gt;使用 Kloudsec 的好处&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;摆脱了证书不可信存在安全风险的不友好提示。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;配置方便，一劳永逸。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;访问速度并未受影响&lt;del&gt;，因为缓存里优化了图片大小，合并了 CSS/JS，甚至可能更快了。&lt;/del&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;小绿锁看着舒心。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;使用-kloudsec-的风险和影响&quot;&gt;使用 Kloudsec 的风险和影响&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;貌似是个小公司，这样的免费服务能提供多长时间只有天知道。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;del&gt;因为用户看到是在 Kloudsec 上的缓存页面，所以我们更新 GitHub Pages 内容后，刷新线上页面效果的时间变久了，以前上传完基本马上就能看到，现在有时候部分页面会延迟两三分钟，我勉强能接受。&lt;/del&gt;&lt;/p&gt;

    &lt;p&gt;Update: 2016/6/16 现在基本上传完马上就能看到了。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;del&gt;很偶尔会出现样式加载不完整的情况，刷新就好了。&lt;/del&gt;&lt;/p&gt;

    &lt;p&gt;Update: 2016/6/16 最近基本没出现过了。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;del&gt;缓存页面合并了 CSS 和 JS 文件，使用开发工具在线调试时要找到样式源文件变困难了——可能看到全都在一个 CSS 文件里。不过我大部分情况下都是用 Jekyll 在本地调试好再上传，这点对我影响不大。&lt;/del&gt;&lt;/p&gt;

    &lt;p&gt;Update: 2016/6/16 现在貌似不会合并了。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;如果引用了其它域名下的非 HTTPS 的 CSS 和图片资源等，开发者控制台下会有 error，显示不受影响。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;del&gt;Google 索引状态会受影响，目前本博客来自 Google 的流量完全没有了，估计需要一段时间才能恢复。&lt;/del&gt;&lt;/p&gt;

    &lt;p&gt;Update: 2016/6/16 应该影响不大，只是 Google Search Console 将 http 与 https 的未当成一个网站来统计，所以给我造成错觉了。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;接下来，能做的就是祈祷 Kloudsec 不要挂了。:laughing:&lt;/p&gt;

&lt;h2 id=&quot;其它做法&quot;&gt;其它做法&lt;/h2&gt;

&lt;p&gt;如果使用 GitLab 提供的 Pages 服务，那它直接支持添加自定义域名的 SSL 证书，可以配合免费申请的 SSL 证书一起使用。详情可见 &lt;a href=&quot;https://www.figotan.org/2016/04/26/using-free-wosign-to-certificate-your-blog-on-gitlab/&quot;&gt;零成本打造安全博客的简单办法&lt;/a&gt;。&lt;/p&gt;</content><author><name>JiuJiuShu</name></author><summary type="html">Update 2016/07/11: 收到 Kloudsec 的邮件，说将在 2016/08/01 停止服务，所以如下方法在那之后会无法使用，寻找 GitHub Pages + Custom Domain + HTTPS 的方法的童鞋请不要再尝试 Kloudsec 了，去找一找别的方法吧。</summary></entry></feed>