<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>郑泽鑫的博客</title>
        <link>https://zhengzexin.com/</link>
        <description>一个生信工作者的独立博客</description>
        <lastBuildDate>Mon, 07 Mar 2022 00:39:29 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>Gridsome Feed Plugin</generator>
        <image>
            <title>郑泽鑫的博客</title>
            <url>https://zhengzexin.com/av.png</url>
            <link>https://zhengzexin.com/</link>
        </image>
        <atom:link href="https://zhengzexin.com/feed/index.xml" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[使用 Github Actions 自动更新 ANNOVAR 的 Clinvar 数据库]]></title>
            <link>https://zhengzexin.com/archives/automatic_update_Clinvar_db_for_ANNOVAR/</link>
            <guid>https://zhengzexin.com/archives/automatic_update_Clinvar_db_for_ANNOVAR/</guid>
            <pubDate>Mon, 14 Jun 2021 22:20:32 GMT</pubDate>
            <content:encoded><![CDATA[<p>前段时间，看到ANNOVAR在文档里更新了一个可以自行更新Clinvar数据库的脚本，ANNOVAR更新Clinvar的频率，一般是半年到一年才更新一次。</p>
<p><img src="https://zhengzexin.com/archives/automatic_update_Clinvar_db_for_ANNOVAR/images/2021/06/14/automatic_update_Clinvar_db_for_ANNOVAR_01.png" alt="ANNOVAR文档"></p>
<p>恰好又看到Github新推出了<a href="https://octo.github.com/projects/flat-data">“Flat Data”</a>，就想着是不是能够像Flat Data一样，抓取Clinvar数据库，然后定期更新成ANNOVAR数据库；可惜研究了一圈，Flat Data的示例都是使用JavaScript或者Typescript脚本的。
​
此路不通，那就换一条路，使用<a href="https://github.com/mobidic/update_annovar_db">David Baux的脚本</a>和Github Actions来实现以下目的：
​</p>
<ol>
<li>定时从NCBI抓取Clinvar的VCF更新（Github在国外，下载快）；</li>
<li>转换成ANNOVAR的数据库文件（省却下载到服务器再处理的步骤）；</li>
<li>发布到Github repo和打包成release，使用CDN加速下载</li>
</ol>
<p>正好Clinvar的数据库压缩后的文件为15Mb左右，不会超过大小限制；其他ANNOVAR的数据库，也可以使用相同的实现方法。</p>
<h2 id="建立github-repo">建立Github repo</h2>
<p>首先我们建立一个repo，如<a href="https://github.com/ryuzheng/clinvar_db_for_annovar">ryuzheng/clinvar_db_for_annovar</a>，主要存放生成的Clinvar数据库文件、release和Github Actions脚本；
​
然后为了整洁，我另外建立2个repo，分别存放</p>
<ol>
<li>需要用到的ANNOVAR脚本，如<code>ryuzheng/ANNOVAR_script</code>，版权问题，设置为私有repo，请自行到ANNOVAR官网下载<ul>
<li><code>convert2annovar.pl</code></li>
<li><code>index_annovar.pl</code></li>
</ul>
</li>
<li>修改过的脚本，如<a href="https://github.com/ryuzheng/update_annovar_db">ryuzheng/update_annovar_db</a>，修改为下载weekly更新的VCF与其他一些更适合Github Actions的改动，这里不赘述</li>
</ol>
<p>然后我们通过<code>submodule</code>，将这2个repo与原来的主repo连接起来，</p>
<pre><code class="language-shell"># 进入主repo的文件夹
cd clinvar_db_for_annovar

# 注意这个repo是私有的，所以得用ssh的形式
git submodule add git@github.com:ryuzheng/ANNOVAR_script.git

# 这个repo是公开的，https和ssh的形式都可以
git submodule add https://github.com/ryuzheng/update_annovar_db.git、

# 后期如果更新了其中某个submodule的repo，需要更新链接的版本
git submodule update --remote
# 或者进入submodule的文件夹
cd update_annovar_db
git pull origin main</code></pre>
<p>我们整个目录的结构如图</p>
<p><img src="https://zhengzexin.com/archives/automatic_update_Clinvar_db_for_ANNOVAR/images/2021/06/14/automatic_update_Clinvar_db_for_ANNOVAR_02.png" alt="目录结构"></p>
<p>这样做的好处是，</p>
<ul>
<li>主repo看起来很干净，只存放生成的文件，并且commit的记录也很干净；</li>
<li>后期如果需要更新代码，我们只需要单独修改submodule的链接，submodule项目的其他代码修改不会影响这个项目；</li>
<li>由于部分代码不能公开，submodule可以引入私有repo</li>
</ul>
<h2 id="编写github-actions">编写Github Actions</h2>
<p>我们在repo文件夹下建立<code>.github/workflows</code>文件夹，用来存放Github Actions的yml文件，Github会自动识别该文件夹下的yml文件。
​
在<code>.github/workflows</code>下新建一个<code>update_clinvar.yml</code>文件，内容如下：</p>
<pre><code class="language-yaml">name: Update Clinvar database for ANNOVAR # 设置该action的名称

on:
  schedule:
    - cron: &quot;0 0 */3 * *&quot; # 由于Clinvar一周更新一次，这里设置为每3天一次
  workflow_dispatch: # 用于手动执行</code></pre>
<p>然后我们先建立第一个任务（jobs），将这个任务命名为<code>build</code>，运行我们修改后脚本，将clinvar的VCF文件转换成ANNOVAR的数据库，并上传结果到artifacts，用于下一步。</p>
<pre><code class="language-yaml">jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        genome: [&quot;hg19&quot;, &quot;hg38&quot;] # 设置一个matrix，分别为hg19和hg38 2个基因组版本的任务

    steps:
      - uses: actions/checkout@v2
        with:
          token: ${{ secrets.GH_TOKEN }}
          submodules: &quot;true&quot;

      - name: Set up Python 3.9 # 使用python 3
        uses: actions/setup-python@v1
        with:
          python-version: 3.9

      - name: Install dependencies # 安装依赖
        run: |
          python -m pip install --upgrade pip
          pip install -r requirement.txt

      - name: Update Clinvar with GRCh37 # hg19的clinvar文件处理
        if: matrix.genome == &#39;hg19&#39;
        run: |
          cd ./update_annovar_db
          python3 ./update_resources.py -d clinvar -w -hp ../Clinvar_build/hg19 -a ../ANNOVAR_script -g GRCh37

      - name: Update Clinvar with GRCh38 # hg38的clinvar文件处理
        if: matrix.genome == &#39;hg38&#39;
        run: |
          cd ./update_annovar_db
          python3 ./update_resources.py -d clinvar -w -hp ../Clinvar_build/hg38 -a ../ANNOVAR_script -g GRCh38

      - name: Upload artifacts # 上一步生成地址为Clinvar_build/hg*，上传文件成artifact
        uses: actions/upload-artifact@v2
        with:
          name: ${{ matrix.genome }}
          path: ./Clinvar_build/${{ matrix.genome }}</code></pre>
<p>然后我们建立第二个任务，将这个任务命名为<code>release</code>，用于当clinvar更新时，存放我们更新后的文件，以及打包成release发布。</p>
<pre><code class="language-yaml">  release:
    runs-on: ubuntu-latest
    needs: build # 需要上一步build执行成功后方能执行

    steps:
      - uses: actions/checkout@v2
        with:
          token: ${{ secrets.GH_TOKEN }}

      - name: clean previous build # 删除之前的版本
        run: |
          rm -f Clinvar_build/hg19/*
          rm -f Clinvar_build/hg38/*

      - name: Download artifacts for GRCh37 # 将hg19的artifact下载到指定路径
        uses: actions/download-artifact@v2
        with:
          name: &quot;hg19&quot;
          path: ./Clinvar_build/hg19

      - name: Download artifacts for GRCh38 # 将hg38的artifact下载到指定路径
        uses: actions/download-artifact@v2
        with:
          name: &quot;hg38&quot;
          path: ./Clinvar_build/hg38

      - name: Commit # 只有文件发生变动，才会commit
        id: auto-commit-action
        uses: stefanzweifel/git-auto-commit-action@v4

      - name: Push changes
        uses: ad-m/github-push-action@master
        with:
          github_token: ${{ secrets.GH_TOKEN }}
          branch: master

      - name: Get current date # 获取当前日期，作为release的版本
        id: date
        run: echo &quot;::set-output name=date::$(date +&#39;%Y-%m-%d&#39;)&quot;

      - name: Create Github Release # 只有新的commit，才打包发布新版本
        if: steps.auto-commit-action.outputs.changes_detected == &#39;true&#39;
        uses: actions/create-release@v1
        id: create_release
        with:
          tag_name: tag-${{ steps.date.outputs.date }}
          release_name: release-${{ steps.date.outputs.date }}
        env:
          GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}

      - name: Upload assets to Github Release # 将生成文件上传到release的asset
        if: steps.auto-commit-action.outputs.changes_detected == &#39;true&#39;
        uses: csexton/release-asset-action@v2
        with:
          pattern: &quot;Clinvar_build/*/*.gz&quot;
          github-token: ${{ secrets.GH_TOKEN }}
          release-url: ${{ steps.create_release.outputs.upload_url }}</code></pre>
<p>完整的yml文件请查看<a href="https://github.com/ryuzheng/clinvar_db_for_annovar/blob/master/.github/workflows/update_clinvar.yml">update_clinvar.yml</a>。
​</p>
<h2 id="配置github-token">配置Github token</h2>
<p>​
在上一步的yml文件里，相信大家多次看到类似<code>github_token: ${{ secrets.GH_TOKEN }}</code>这样的配置，这是因为Github在执行诸如commit、checkout、push等git操作时，都需要权限，因此我们需要配置一个token。而这个token，我们放在secrets里，别人是无法看到的。</p>
<p>打开<a href="https://github.com/settings/tokens">Personal access tokens</a>，点击右上角的<strong>Generate new token</strong>，输入一个名字用于识别，然后勾选上repo的框（允许repo的操作，视乎你所需的权限），然后点击<strong>Generate token</strong>，将生成的token复制好。</p>
<p><img src="https://zhengzexin.com/archives/automatic_update_Clinvar_db_for_ANNOVAR/images/2021/06/14/automatic_update_Clinvar_db_for_ANNOVAR_03.png" alt="Generate new token"></p>
<p>再打开你的repo的Settings选项卡，然后选择Secrets该项，点击右上角的<strong>New repository secret</strong>，填入名称，如<code>GH_TOKEN</code>，这个名称要与yml里的<code>${{ secrets.GH_TOKEN }}</code>相同，然后将刚才复制好的token填入下面的value里。</p>
<p><img src="https://zhengzexin.com/archives/automatic_update_Clinvar_db_for_ANNOVAR/images/2021/06/14/automatic_update_Clinvar_db_for_ANNOVAR_04.png" alt="repository secret"></p>
<p>这样我们就配置好了token；如果大家有其他密钥或者需要保密的内容，也可以设置在secrets里。
​</p>
<h2 id="运行github-actions">运行Github Actions</h2>
<p>我们点击repo的Actions选项卡进入该repo的Actions，第一次进去，可能会提示<strong>Get started with GitHub Actions</strong>，我们点击“Skip this and set up a workflow yourself”就行。
​
然后我们在All workflows下会看到我们刚才命名为<code>Update Clinvar database for ANNOVAR</code>的action，点击进入，点击右边的run workflow就可以手动执行。</p>
<p><img src="https://zhengzexin.com/archives/automatic_update_Clinvar_db_for_ANNOVAR/images/2021/06/14/automatic_update_Clinvar_db_for_ANNOVAR_05.png" alt="run workflow"></p>
<p>如果执行成功，我们可以看到不同的jobs运行结果以及生成的artifacts。</p>
<p><img src="https://zhengzexin.com/archives/automatic_update_Clinvar_db_for_ANNOVAR/images/2021/06/14/automatic_update_Clinvar_db_for_ANNOVAR_06.png" alt="运行结果"></p>
<h2 id="cdn加速下载">CDN加速下载</h2>
<p>打开<a href="https://github.com/ryuzheng/clinvar_db_for_annovar/releases/latest">https://github.com/ryuzheng/clinvar_db_for_annovar/releases/latest</a>，就能看到最新的release，我们可以<a href="https://doc.fastgit.org/zh-cn/guide.html#release-%E5%92%8C%E6%BA%90%E7%A0%81%E5%AD%98%E6%A1%A3%E7%9A%84%E4%B8%8B%E8%BD%BD">FastGit</a>或者<a href="https://www.jsdelivr.com/features#gh">jsDelivr</a>来作为CDN，示例如下</p>
<pre><code class="language-shell"># Release
# 假设下载链接为https://github.com/ryuzheng/clinvar_db_for_annovar/releases/download/tag-2021-05-21/hg19_clinvar_20210517.txt.gz
wget https://download.fastgit.org/ryuzheng/clinvar_db_for_annovar/releases/download/tag-2021-05-21/hg19_clinvar_20210517.txt.gz

# 假设文件位置为Clinvar_build/hg38/hg38_clinvar_20210517.txt.gz
wget https://cdn.jsdelivr.net/gh/ryuzheng/clinvar_db_for_annovar/Clinvar_build/hg38/hg38_clinvar_20210517.txt.gz</code></pre>
<p>至此，我们的目的已经达成，如无意外，Github Actions会每3天去抓取Clinvar最新的VCF文件，并转换成ANNOVAR的文件形式。
​</p>
<h2 id="一个小讨论">一个小讨论</h2>
<p>ANNOVAR在进行VCF注释之前，需要先对VCF文件进行split以及left-normalization（详见<a href="https://annovar.openbioinformatics.org/en/latest/articles/VCF/">VCF Processing Guide</a>），因为ANNOVAR的注释文件，都是left-normalization的。</p>
<p><img src="https://zhengzexin.com/archives/automatic_update_Clinvar_db_for_ANNOVAR/images/2021/06/14/automatic_update_Clinvar_db_for_ANNOVAR_07.png" alt="VCF文件处理"></p>
<p><strong>那么Clinvar的VCF文件，是否需要进行split和left-normalization，然后再转换成ANNOVAR的注释文件？</strong>这个问题<a href="https://github.com/mobidic/update_annovar_db">David Baux也提到了</a>。</p>
<p><img src="https://zhengzexin.com/archives/automatic_update_Clinvar_db_for_ANNOVAR/images/2021/06/14/automatic_update_Clinvar_db_for_ANNOVAR_08.png" alt="David Baux"></p>
<p>我对Clinvar的VCF文件进行了测试，发现它已经是split和left-normalization的了。由此验证了我以前看过某篇博客，上面说Clinvar的突变描述格式，在基因组注释，是left-normalization，而在cDNA注释和氨基酸注释上，则遵循HGVS的标准。这或许能作为我们处理突变描述格式时的一个参考。
​
截止该篇博客发布，<a href="https://github.com/ryuzheng/clinvar_db_for_annovar">这个repo</a>已经运行了将近一个月，目前已经较为稳定，欢迎大家使用。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[2020 年终总结]]></title>
            <link>https://zhengzexin.com/archives/Summary_of_2020/</link>
            <guid>https://zhengzexin.com/archives/Summary_of_2020/</guid>
            <pubDate>Thu, 31 Dec 2020 16:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p><img src="https://zhengzexin.com/archives/Summary_of_2020/images/2021/01/01/summary_of_2020_01.png" alt="图 1. 南都的记疫"></p>
<blockquote>
<p>与上述信息同样高度契合的，是微信公号 “小山狗” 1 月 28 日曾发布过的一篇题为 “记录一下首次发现新型冠状病毒的经历” 的文章。作者在留言区自称就职于位于广州黄埔的一家民营企业，文中记录：“2019 年 12 月 26 日刚上班，还是如往常一样先大概浏览一下这一天的 mNGS 病原微生物自动解读结果。意外的是，发现有一个样本报出了敏感病原体 ——SARS 冠状病毒，有几十条的序列，且这个样本只有这么一个有意义的病原体。心头一紧，赶紧后台查看详细的分析数据，发现相似度并不算很高，只有大约 94.5%。为了确认结果的可靠性，开始了详细分析。探索版的分析结果提示这个病原体跟 Bat SARS like coronavirus（蝙蝠类 SARS 冠状病毒）最相似，整体相似度在 87% 左右，而跟 SARS 的相似度是约 81%。”</p>
<p>——《财新 | 独家 | 新冠病毒基因测序溯源：警报是何时拉响的》</p>
</blockquote>
<p>今年年初时小山狗的那篇文章在群里转发开来，一方面，我惊讶于他们的速度（24日收到样品，27日口头报告新冠病毒，而到了30日，已经有3家公司报告了这个病毒）；另一方面，我对于自己工作于生物这个行业而感到荣幸，虽不如这些大佬那么牛逼，但是无论是从事肿瘤药物检测、遗传病，还是病原体检测等，生物行业对群众都是有用的，而且生物行业的成熟，检测到病毒，短时间内就组装好了病毒序列，分享给全世界（参考<a href="http://www.ruanyifeng.com/blog/2020/12/weekly-issue-139.html">科技爱好者周刊（第 139 期）：生物学的可怕进展</a>这一期的本周话题），以及后来的检测试剂盒开发，我认为在这一次疫情中，生物行业的反应速度和表现，可以说满分不为过。</p>
<h2 id="工作">工作</h2>
<p>有一个之前听说过的故事，最近又听了一次，对我有些触动：</p>
<blockquote>
<p>有一个人问一个得道的老和尚：“得道前干啥？”老和尚说：“挑水、扫地、做饭。”这个人又问得道后呢。回答依然是挑水、扫地、做饭。那人又问区别在哪里。老和尚回答说：“不得道前挑水时想着扫地，扫地时想着做饭。现在挑水时想着挑水，扫地时想着扫地，做饭时想着做饭。”</p>
</blockquote>
<p>有时候我们工作久了，想达到的目标就多，所以我们工作时就会做着这件事情时就想着下一件，比如做着RNA分析时，就想着要是我去学机器学习，将一些机器学习的方法应用到分析中，是不是能达到更好的效果。</p>
<p>而且我们做生信分析时，有时候就是要等程序运行完，才能得到结果，而等结果这段时间，又想着给自己安排一些其他工作，结果边做着其他工作，边时不时看看程序跑完没有，最后就是三心两意。</p>
<p>所以工作越久，越觉得自己专注力不行，效率下降。看到这个故事之后，我忽然明白，心里装的事情越多，越不可能把当前的事情做好。</p>
<h2 id="学习">学习</h2>
<p>今年在看了一些别人的源码后，突然理解一个包/项目应该是怎么写的，感觉Python的水平提高了不少（只是自我感觉良好哈哈哈）；然后今年由于项目要用到R，终于在自己默默学习了R很久之后，会写一些R脚本了，果然实践是检验真理的唯一标准。</p>
<p>不过由于搬家后是地铁通勤，所以没有再像以前一样，上班途中看视频学习，略有遗憾。</p>
<p>今年终于报考驾考了，目前进度是科目一。。。</p>
<h2 id="消费">消费</h2>
<ul>
<li>跟着mjj，屯了几台vps，自己搭了TTRSS，非常好用，之前想搞Emby/Jellyfin之类，最终放弃了</li>
<li>给自己换了iPhone 11，给女友换了12</li>
<li>投影仪（女朋友先斩后奏送的礼物）</li>
<li>健身环大冒险、动森，还有疫情在家时，买了很多switch卡带玩，比如巫师3，路易基鬼屋等，强烈推荐鬼屋，女友通关后又将所有宝石收集完</li>
<li>小熊料理锅，自己在家烤肉/烤鱼，搬家后还请爸妈来吃了一顿烤肉，二老也很喜欢这个锅</li>
</ul>
<p><img src="https://zhengzexin.com/archives/Summary_of_2020/images/2021/01/01/summary_of_2020_02.png" alt="图 2. 小熊料理锅"></p>
<h2 id="输出">输出</h2>
<p>我在语雀上建了个<a href="https://www.yuque.com/ryuz/shares">“好物分享”</a>的知识库，用来分享自己觉得好的、值得分享的网站、软件等，特别是在分享轻芒杂志的邀请码后，竟然有很多朋友使用了我的邀请链接，所以分享还是有价值的；来年我会继续更新。</p>
<p>今年也参与了思考问题的熊举办的“<a href="https://kaopubear.top/blog/2020-01-19-refgroup2020/">素材学习分享周刊</a>”小组，贡献了自己的一期，也收获了很多大佬分享的干货。</p>
<p>生活里很多内容都是在工作中学习到的，但由于工作内容保密的原因，之前很多想写的博客都没有动手，拖的时间久了，自然就觉得可写可不写了；但今年把语雀当作自己的wiki后，确实很方便，一些工作上遇到的问题，可以及时地记录下来，由于是私人wiki，也不用像博客一样要原创才行，大胆地摘录下别人的方法就好；而且过一段时间后，如果有价值，还可以修改修改，放到博客上。</p>
<p><img src="https://zhengzexin.com/archives/Summary_of_2020/images/2021/01/01/summary_of_2020_03.png" alt="图 3. Google Analytics 的统计"></p>
<p>今年博客只更新了4篇博客，慢慢地我也不强求自己每年更新多少篇，只希望自己之后有更多有价值的想法和经验可以分享给大家。今年没有参加到farbox 2.0的内测，然后自己抄了spencerwoo的博客，搬到Vercel上用Gridsome来生成。</p>
<h2 id="生活">生活</h2>
<p>今年又搬了一次家，年初的时候，由于疫情的关系，所住的城中村管得比较严，想要回去，便要在村口的关卡，找本地房东来签责任书，但我租的是二手房东那种公寓，二手房东也在外省回不来，本地一手房东也不愿意出面来担责，而我当时已经拿着行李回到村口了，那些工作人员根本不理会任何解释，只会机械重复地说，让房东出来接你回去；类似的情形，大家在年初返京的新闻同样可以了解到；</p>
<p>正是这种政策，城中村让我觉得毫无人权，所以今年我搬家的时候，就选择了住宅小区，同时也满足了自己想要一个有飘窗的卧室和屋子有个阳台的心愿。但是房租也涨了2倍，而且物价水平也比以前在城中村里高。</p>
<p>今年由于把mbp拿到公司了，所以就用女友的旧笔记本的内存+SSD，捡垃圾组了一台戴9020m的小主机，加上网卡，花了700块钱左右，装上黑苹果，用起来也很舒服；特别是有时候拿去插在投影仪和电视上，当个没广告的电视盒子，因为小机箱，所以特别轻。</p>
<p><img src="https://zhengzexin.com/archives/Summary_of_2020/images/2021/01/01/summary_of_2020_04.png" alt="图 4. 刘德华的造型"></p>
<p>今年看到了《扫毒2》里刘德华的发型，很喜欢那种辫子发型，突发奇想留了一段时间长头发，留的过程自然度过一段时间的尴尬期。但是最近又剪掉了，当然是因为我不够帅，而且留这种发型的人忽然多了起来，就一点都不个性了。</p>
<p>最后是今年的一点小感悟：</p>
<ol>
<li>没有什么是永久的，做好准备，拥抱变化</li>
<li>适合自己的才是最好的</li>
<li>勿忘本心</li>
</ol>
<h2 id="2021">2021</h2>
<p>明年的目标，</p>
<ul>
<li>都买健身环了，当然是减肥、减肥再减肥</li>
<li>早日写出自己想要做的那个软件</li>
<li>顺利拿到驾照</li>
</ul>
<p>最后，祝大家新年快乐，心想事成！</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[解包一个 PAR 打包的 perl 程序源码]]></title>
            <link>https://zhengzexin.com/archives/decoded_a_Perl_script/</link>
            <guid>https://zhengzexin.com/archives/decoded_a_Perl_script/</guid>
            <pubDate>Sun, 18 Oct 2020 07:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>最近在流程debug时，和同事发现一个perl脚本有问题；然后发现这个perl脚本是别人打包好的，所以看不到源码。我就想把这个perl脚本给解包（不敢称为反编译，因为实际上也没做反编译）了。因为打包perl脚本这事，我以前也做过，所以我觉得应该可行。</p>
<h2 id="如何用par来打包perl程序">如何用PAR来打包perl程序</h2>
<p>首先，一般打包perl程序，现在应该是使用<a href="http://search.cpan.org/~rschupp/PAR-Packer-1.040/lib/PAR/Packer.pm">PAR::Packer</a>打包perl程序，具体参数参考<a href="http://search.cpan.org/~rschupp/PAR-1.015/lib/PAR/Tutorial.pod">http://search.cpan.org/~rschupp/PAR-1.015/lib/PAR/Tutorial.pod</a>。打包的命令如下：</p>
<pre><code class="language-bash">pp -g -B -o xxx xxx.pl # -g 生成二进制程序, -B 将各种依赖项打包进去, -o 生成的文件名</code></pre>
<h2 id="解包par打包的perl程序">解包PAR打包的perl程序</h2>
<p>首先运行一次程序，然后在 <code>/tmp/</code> 目录下，查看是否有 <code>par-</code> 开头的文件夹，PAR打包的程序有个特点，就是会将程序解压到 <code>/tmp</code> 目录下，然后再运行。</p>
<p><img src="https://zhengzexin.com/archives/decoded_a_Perl_script/images/2020/10/18/decoded_a_perl_script_1.png" alt="tmp目录下的文件"></p>
<p>如果有这样子的目录，应该就是PAR打包的了。然后我们使用 <code>unzip -d unarchive xxx</code>，xxx是你的程序的名称，这样子我们就能得到解压的目录。（<a href="https://www.yuque.com/attachments/yuque/0/2020/zip/109224/1595582389314-7fa0e4b2-c9aa-4722-94eb-e75b1cef9f79.zip?_lake_card=%7B%22uid%22%3A%221595582387315-0%22%2C%22src%22%3A%22https%3A%2F%2Fwww.yuque.com%2Fattachments%2Fyuque%2F0%2F2020%2Fzip%2F109224%2F1595582389314-7fa0e4b2-c9aa-4722-94eb-e75b1cef9f79.zip%22%2C%22name%22%3A%22xxx.zip%22%2C%22size%22%3A2757816%2C%22type%22%3A%22application%2Fzip%22%2C%22ext%22%3A%22zip%22%2C%22progress%22%3A%7B%22percent%22%3A99%7D%2C%22status%22%3A%22done%22%2C%22percent%22%3A0%2C%22id%22%3A%22V2kji%22%2C%22card%22%3A%22file%22%7D">xxx.zip</a>，语雀对上传文件的后缀有限制，大家自行解压，然后执行exe文件测试）</p>
<h2 id="发现是bleach加密过的源码">发现是Bleach加密过的源码</h2>
<p>一般解压后我们就能得到脚本的原始<code>.pl</code> 文件，但是这次，我打开 <code>xxx.pl</code> 文件，却只看到一行很奇怪的代码，而文件的大小却很大。这里上传一个<a href="https://zhengzexin.com/archives/decoded_a_Perl_script/images/2020/10/18/xxx.pl">xxx.pl</a>给大家玩一下😄️。</p>
<pre><code class="language-perl">$_=&lt;&lt;&#39;&#39;;y;\r\n;;d;y; \t;01;;$_=pack&#39;b*&#39;,$_;$_=eval;$@&amp;&amp;die$@;$_</code></pre>
<p>是的，整个文件，我wc了一下，足足有2000多行，但是打开来看，却只看到一行代码，这时，我就猜想，这里应该是使用了什么方法来加密的代码，将代码替换成不可见的字符。</p>
<p>于是我使用 <code>cat -vet xxx.pl| less -SN</code> 来查看该文件，发现这个文件只有这种类似与tab的字符，</p>
<pre><code class="language-perl">$_=&lt;&lt;&#39;&#39;;y;\r\n;;d;y; \t;01;;$_=pack&#39;b*&#39;,$_;$_=eval;$@&amp;&amp;die$@;$_$
^I^I   ^I  ^I$
^I  ^I^I$
^I^I ^I  ^I ^I$</code></pre>
<p>幸运的是，当我将 <code>$_=&lt;&lt;&#39;&#39;;y;\r\n;;d;y; \t;01;;$_=pack&#39;b*&#39;,$_;$_=eval;$@&amp;&amp;die$@;$_$</code> 这串字符串拿去google之后，很快发现了<a href="https://www.marcbilodeau.com/compiling-perl/">A Beginner’s Guide to Compiling Perl Scripts</a>这篇文章，原来这种源码是经过Bleach这种方法加密过的。</p>
<p>当然，这里我还在stackoverflow查到这种方法是如何生效的。</p>
<ul>
<li><code>$_ = &lt;&lt; &#39;&#39;;</code> reads the rest of the file into the accumulator.</li>
<li><code>y;\r\n;;d;</code> strips carriage returns and line feeds.</li>
<li><code>$_ = pack &#39;b*&#39;, $_;</code> converts characters to bits in <code>$_</code>, LSB first.</li>
<li><code>$_ = eval;</code> executes <code>$_</code> as Perl code.</li>
<li><code>$@ &amp;&amp; die $@; $_</code> handles exceptions and the return code gracefully.</li>
</ul>
<h2 id="解密bleach加密的源码">解密Bleach加密的源码</h2>
<p>明白是怎么加密之后，我就开始找如何解密的方法，一开始我找到一个<a href="https://www.perlmonks.org/?node_id=85918">unbleach.pl</a>的代码，但是运行了之后，可能是这个代码太老了，并不能解码。</p>
<p>然后我看到<a href="https://stackoverflow.com/questions/24578917/how-does-this-obfuscated-perl-script-work/24591240">How does this obfuscated Perl script work?</a>和<a href="https://www.perlmonks.org/?node_id=1101852">bleach question</a>，一下子就醒悟过来，上面的原理解释里不是说了吗，用 <code>eval</code> 来执行 <code>$_</code>里的perl代码，那将 <code>eval</code> 修改为 <code>print</code>，就变成了将代码都打印出来😄️。</p>
<p>原来那么简单！</p>
<p>最后我修改文件头一行为</p>
<pre><code class="language-perl">$_=&lt;&lt;&#39;&#39;;y;\r\n;;d;y; \t;01;;$_=pack&#39;b*&#39;,$_;$_=print;$@&amp;&amp;die$@;$_</code></pre>
<p>然后执行 <code>perl xxx.pl | less -SN</code>，终于看到源码了。</p>
<h2 id="讨论">讨论</h2>
<p>其实，我在几年前，也做过加密打包perl代码的工作，然后当时就发现，这个打包然并卵。首先会解压到 <code>/tmp</code> 目录下，其次 <code>unzip</code> 一下也能解包，当时我也有看到 <code>PAR::Filter::Bleach</code> 和 <code>PAR::Filter::Bytecode</code> 等加密方法，以为加上这个参数应该就可以，但现在发现这种方法还是不安全的。</p>
<p>另外，我看了<a href="https://www.marcbilodeau.com/compiling-perl/">A Beginner’s Guide to Compiling Perl Scripts</a>里面加上 <code>PAR::Filter::Crypto</code> 的方法，我看到程序要解密加密后的代码，代码必须将密钥也写在代码里，所以应该也是然并卵的。</p>
<pre><code class="language-bash">dev@virtualbox:~/Desktop/decompile$ more script/bestProgram.pl

use Filter::Crypto::Decrypt;
e6ad69e3dd1e9901ccf6ba701ff66dfb09ba6b2f6c3b872e33e1929e56298f9861777c6a21255012
c658fa873214cd41071f6915ef594ee5447ae02afc1e2d726333fb855148920518e827fbb0990053
73eddabe4e608e15fcc54008c659f218ac32d56ac8d05a78cfd446ae05cf6c19f7e3c1b30fab747f
c0b0017243f764b3d3db0ef081bbf245478bd5a6af4c361b22e488edf203d91d4018d930fe4d2c1b
8d4d103810eb0603

dev@virtualbox:~/Desktop/decompile$ ../bestProgram_Encrypted.exe 
$VAR1 = {
 &#39;second&#39; =&gt; 2,
 &#39;first&#39; =&gt; 1,
 &#39;third&#39; =&gt; 3
 };</code></pre>
<p>最好的方法，还是将perl代码转换为c代码，甚至是c代码的模块的形式，增加反编译的难度。</p>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://www.marcbilodeau.com/compiling-perl/">A Beginner’s Guide to Compiling Perl Scripts</a></li>
<li><a href="https://stackoverflow.com/questions/7556782/what-does-this-perl-line-from-a-bleached-file-do">What does this perl line from a “bleached” file do?</a></li>
<li><a href="https://www.perlmonks.org/?node_id=1101852">bleach question</a></li>
<li><a href="https://stackoverflow.com/questions/24578917/how-does-this-obfuscated-perl-script-work/24591240">How does this obfuscated Perl script work?</a></li>
<li><a href="https://www.perlmonks.org/?node_id=85918">unbleach.pl</a></li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[阿里云PBS作业排队管理]]></title>
            <link>https://zhengzexin.com/archives/Aliyun_PBS/</link>
            <guid>https://zhengzexin.com/archives/Aliyun_PBS/</guid>
            <pubDate>Sat, 27 Jun 2020 08:59:18 GMT</pubDate>
            <content:encoded><![CDATA[<p>找了很久PBS的文档，阿里云的PBS应该是OpenPBS，现在名字叫做<a href="https://www.pbspro.org/">PBS Pro</a>，找了很久才找到个18.2版本的说明书，虽然服务器上的是18.1，但是版本相差不大，应该也通用。</p>
<p><a href="https://www.pbsworks.com/pdfs/PBSUserGuide18.2.pdf">PBSUserGuide18.2.pdf</a></p>
<p>然后最近写到一个程序，想要先等某些任务执行完才继续执行后面的任务。虽然snakemake也可以qsub提交任务，但是snakemake还不是很熟练。而我的Python脚本，需要自定义计算的地方很多，用snakemake也不方便，于是就想找PBS原生的实现方法。</p>
<p>在网上搜索，找到 <code>-hold_jid</code> 和 <code>-W depend</code> 两种，一开始觉得 <code>-hold_jid</code> 这种比较简单明了，但是阿里云的 <code>qsub</code> 很多参数都不支持，其中 <code>-hold_jid</code> 就不支持。</p>
<h2 id="用-w-depend属性去修改">用-W depend属性去修改</h2>
<p>然后对于 <code>-W depend</code> 这个一开始有点迷糊，后来看过Userguide之后，才知道depend后面可以接多种参数，然后再用分号接job id；</p>
<pre><code class="language-bash"># &lt;type&gt;:&lt;arg list&gt;[,&lt;type&gt;:&lt;arg list&gt; ...] 这种形式
# 其中&lt;arg list&gt;为&lt;job ID&gt;[:&lt;job ID&gt; ...] 这种形式的一串任务id
# type有如下几种，要执行的该任务我们称之为“任务A”，而arg list为depend的其他任务

after:&lt;arg list&gt; # arg list 开始执行 =&gt; 任务A执行
afterok:&lt;arg list&gt; # arg list 成功执行完 =&gt; 任务A执行
afternotok:&lt;arg list&gt; # arg list 执行完失败后 =&gt; 任务A执行
afterany:&lt;arg list&gt; # arg list 执行完后（不管是否成功完成） =&gt; 任务A执行
before:&lt;arg list&gt; # 任务 A 开始执行 =&gt; arg list执行（依赖on:count）
beforeok:&lt;arg list&gt; # 任务 A 成功执行完后 =&gt; arg list执行（依赖on:count）
beforenotok:&lt;arg list&gt; # 任务 A 执行完失败后 =&gt; arg list执行（依赖on:count）
beforeany:&lt;arg list # 任务 A 执行完(不管是否成功) =&gt; arg list执行（依赖on:count）
on:count # 需要依赖的任务数，和以上的before一起搭配使用</code></pre>
<p>下面为几个示例，</p>
<h3 id="示例一">示例一</h3>
<p>你有job1、job2、job3 三个任务，你想要job3在job1、job2完成后才开始执行</p>
<pre><code class="language-bash">qsub job1
16394.jupiter
qsub job2
16395.jupiter
qsub -W depend=afterany:16394:16395 job3
16396.jupiter</code></pre>
<h3 id="示例二">示例二</h3>
<p>你想要job2，必须在job1成功执行完后才开始执行</p>
<pre><code class="language-bash">qsub job1
16397.jupiter
qsub -W depend=afterok:16397 job2
16396.jupiter</code></pre>
<h3 id="示例三">示例三</h3>
<p>job1要在job2、job3前完成，要使用 <code>beforeany</code>，你必须同时使用 <code>on</code></p>
<pre><code class="language-bash">qsub -W depend=on:2 job1
16397.jupiter
qsub -W depend=beforeany:16397 job2
16398.jupiter
qsub -W depend=beforeany:16397 job3
16399.jupiter</code></pre>
<h2 id="用qalter去修改已经提交的任务">用qalter去修改已经提交的任务</h2>
<p>有时候，我们是多人使用一个集群，或者我们提交前没有考虑到，那么我们想修改已经提交的任务，就需要使用 <code>qalter</code> 命令。</p>
<p>比如，我们想让id为16397的任务插队，那么命令为 <code>qalter -W depend=afterok:16397 16396</code>，那么16396号任务就会在16397号任务成功完成后才能开始执行。</p>
<p>另外，如果我们已经像上面那样添加了afterok属性了，而我们又想修改为16396在16397开始执行后就可以开始执行，而不用等到执行成功之后，我们直接 <code>qalter -W depend=after:16397 16396</code> 是不能修改的。我们需要先 <code>qalter -W depend=afterok 16396</code> 清除afterok属性后，才可以重新修改。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[VPS装机记录（3）：任务机器人]]></title>
            <link>https://zhengzexin.com/archives/VPS_No3_shell-bot/</link>
            <guid>https://zhengzexin.com/archives/VPS_No3_shell-bot/</guid>
            <pubDate>Sat, 27 Jun 2020 07:52:54 GMT</pubDate>
            <content:encoded><![CDATA[<p>VPS基本设置好后，开始想在上面放一些自动化的东西，那么我们就需要一个机器人，设想的目的是，我们在常用的社交软件发送一条命令或者设置好的指令，机器人就会在VPS上自动执行，并返回结果。</p>
<p>这种机器人，最好的示例可以参考<a href="https://zhengzexin.com/archives/VPS_No3_shell-bot/images/shell-bot_1.png">湾区日报是如何运作的？</a>和<a href="https://zhengzexin.com/archives/VPS_No3_shell-bot/images/shell-bot_2.png">湾区日报的第一个 “员工”：Slack/Hubot</a></p>
<p>但是我们暂时实现不了定制化那么高的任务机器人，刚好我在telegram上看到有一个机器人，也比较简单，那么我们就用它来搭建在telegram上的机器人。效果参考下图：</p>
<p><img src="https://zhengzexin.com/archives/VPS_No3_shell-bot/images/shell-bot_1.png" alt="image.png"> </p>
<p><img src="https://zhengzexin.com/archives/VPS_No3_shell-bot/images/shell-bot_2.png" alt="image.png"></p>
<h2 id="搭建shell-bot机器人">搭建shell-bot机器人</h2>
<p>该机器人的repo在<a href="https://github.com/botgram/shell-bot">botgram/shell-bot</a>，参照作者给的<a href="https://jmendeth.com/blog/telegram-shell-bot/">安装流程</a>。</p>
<h3 id="创建机器人帐号">创建机器人帐号</h3>
<p><a href="https://t.me/BotFather">点击此链接</a>与Telegram的BotFather聊天，发送 <code>/newbot</code> 指令，然后依照提示给机器人帐号起名字和账号名，然后获得一串HTTP API的token，如：</p>
<pre><code class="language-bash">Use this token to access the HTTP API:
123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
Keep your token secure and store it safely, it can be used by anyone to control your bot.</code></pre>
<h3 id="安装依赖项">安装依赖项</h3>
<p>首先，shell-bot是依赖Node.js的，因此先确定你的VPS上安装好了Node.js，使用 <code>npm -v</code>，确认是否已经安装。</p>
<p>然后，如果你是Ubuntu的系统：</p>
<pre><code class="language-bash">sudo apt-get install build-essential git</code></pre>
<p>如果你跟我一样，是CentOS的系统：</p>
<pre><code class="language-bash">sudo yum install make automake gcc gcc-c++ kernel-devel git</code></pre>
<h3 id="安装并运行shell-bot">安装并运行shell-bot</h3>
<p>clone shell-bot的repo，并使用npm安装依赖的包</p>
<pre><code class="language-bash">git clone https://github.com/botgram/shell-bot.git
cd shell-bot
npm install</code></pre>
<p>然后首次运行shell-bot，它会要求你提供token，并且在Telegram的BotFather帐号，会要求你确认是否是你在连接该机器人，最后生成设置文件</p>
<pre><code class="language-bash">node server</code></pre>
<p>当shell-bot运行起来后，在你的telegram，对话你设置好的机器人，如 <code>/help</code> 或者需要执行的命令前加 <code>/run</code>，如 <code>/run uname -a</code>。</p>
<h3 id="持久化运行shell-bot">持久化运行shell-bot</h3>
<p>然后我们安装 <code>forever</code> 来持久化运行shell-bot，使用 <code>-g</code> 来全局安装</p>
<pre><code class="language-bash">sudo npm install -g forever</code></pre>
<p>然后在你的 <code>/etc/rc.local</code> 或者开机执行文件里，加入调用的命令，如：</p>
<pre><code class="language-bash">forever start /path/to/shell-bot/server.js</code></pre>
<p>至此，我们的任务机器人就搭建好了，当需要执行某些任务的时候，我们就打开telegram，然后 <code>/run 命令</code>，机器人就会自动帮我们在VPS上执行命令，如果是运行较久的命令，我们则静静等待机器人返回执行结果就好了。该机器人支持的命令，可以使用<code>/help</code>命令，或者在<a href="https://github.com/botgram/shell-bot/blob/master/commands.txt">该文件</a>中查看到。</p>
<p>下一篇文章，我会介绍一些服务器监控的APP。</p>
<hr>
<h2 id="npm-install一直报错的解决方法">npm install一直报错的解决方法</h2>
<p>可能是由于你的Node.js版本太久导致，因此更新Node.js到最新版本，如果你跟我一样是CentOS，需要先更新内核（注意更新内核该操作比较危险，请查清楚后再做，特别是更新后开机项要设置好，不然可能无法开机），然后更新Node.js版本。</p>
<h3 id="更新内核">更新内核</h3>
<h4 id="载入公钥">载入公钥</h4>
<pre><code class="language-bash"> rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org</code></pre>
<h4 id="安装elrepo">安装ELrepo</h4>
<pre><code class="language-bash">yum install https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm # CentOS 7，其他版本不一样</code></pre>
<h4 id="载入-elrepo-kernel-元数据">载入 elrepo-kernel 元数据</h4>
<pre><code class="language-bash"> yum --disablerepo=\* --enablerepo=elrepo-kernel repolist</code></pre>
<h4 id="更新内核-1">更新内核</h4>
<pre><code class="language-bash"> yum --disablerepo=\* --enablerepo=elrepo-kernel install  kernel-ml.x86_64  -y</code></pre>
<h4 id="删除旧工具包">删除旧工具包</h4>
<pre><code class="language-bash">yum remove kernel-tools-libs.x86_64 kernel-tools.x86_64  -y</code></pre>
<h4 id="安装新版本工具包">安装新版本工具包</h4>
<pre><code class="language-bash">yum --disablerepo=\* --enablerepo=elrepo-kernel install kernel-ml-tools kernel-ml-devel kernel-ml-headers -y</code></pre>
<h4 id="查看内核插入顺序">查看内核插入顺序</h4>
<p>默认新内核是从头插入，默认启动顺序也是从 0 开始。</p>
<pre><code class="language-bash">grep &quot;^menuentry&quot; /boot/grub2/grub.cfg | cut -d &quot;&#39;&quot; -f2

CentOS Linux (3.10.0-1127.10.1.el7.x86_64) 7 (Core)
CentOS Linux (5.7.2-1.el7.elrepo.x86_64) 7 (Core)
CentOS Linux (0-rescue-96820b9851c24560b5f942f2496b9aeb) 7 (Core)</code></pre>
<h4 id="查看当前实际启动顺序">查看当前实际启动顺序</h4>
<pre><code class="language-bash">grub2-editenv list

saved_entry=CentOS Linux (3.10.0-1127.10.1.el7.x86_64) 7 (Core)</code></pre>
<h4 id="设置默认启动">设置默认启动</h4>
<pre><code class="language-bash">grub2-set-default &#39;CentOS Linux (5.7.2-1.el7.elrepo.x86_64) 7 (Core)&#39;</code></pre>
<h4 id="重启并检查">重启并检查</h4>
<pre><code class="language-bash">reboot
uname -r</code></pre>
<h3 id="更新nodejs">更新Node.js</h3>
<pre><code class="language-bash">yum remove nodejs npm -y
yum install -y nodejs</code></pre>
<h2 id="reference">Reference</h2>
<ul>
<li><a href="https://jmendeth.com/blog/telegram-shell-bot/">Telegram shell bot</a></li>
<li><a href="https://fuckcloudnative.io/posts/deploy-k3s-cross-public-cloud/#2-%E5%8D%87%E7%BA%A7%E5%86%85%E6%A0%B8">跨云厂商部署 k3s 集群</a></li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[VPS装机记录（2）：使用mosh]]></title>
            <link>https://zhengzexin.com/archives/VPS_No2_mosh/</link>
            <guid>https://zhengzexin.com/archives/VPS_No2_mosh/</guid>
            <pubDate>Thu, 16 Apr 2020 14:43:03 GMT</pubDate>
            <content:encoded><![CDATA[<p>家里的网络有点差，之前买的VPS，直接连接SSH，输命令时有时卡卡的，于是就想到之前看到过的<a href="https://mosh.org/"><code>mosh</code></a>。引用维基百科的话来介绍一下<code>mosh</code>的特性。</p>
<blockquote>
<p><code>mosh</code>不绑定使用者端的 IP address，这使得使用者从移动网络（像是 3G、4G）与 WiFi 之间切换时，不会造成连线中断。
<code>mosh</code>保持连线开启，当此用者断线时，服务器端只会认定为暂时离线（sleep）让使用者可以稍候连回来。相对的，SSH 因为透过 TCP，在使用者断线时会造成连线中断。
<code>mosh</code>会试着在本地端马上显示使用者所输入的按键，这使得使用者会感觉到更少的延迟。</p>
</blockquote>
<h2 id="centos安装mosh">CentOS安装mosh</h2>
<p>CentOS安装mosh比较简单，使用<code>yum install mosh</code>就可以。如果你提示错误，参考Reference里的文章，可能需要先添加源。</p>
<p>另外，如果你之前参考我的文章，服务器的防火墙关闭了多余的端口，那么这时候就要手动打开端口。</p>
<p>因为<code>mosh</code>默认是走UDP协议的，然后默认使用的端口是<code>60000-61000</code>，第一个连接时用的是60000，第二个连接使用的就是60001，以此类推。当然，你也可以手动指定。</p>
<pre><code class="language-bash">firewall-cmd --zone=public --add-port=60000/udp --permanent # firewall添加你选择的ssh端口，--permanent是保存设置，否则下次重启后不生效
systemctl start firewalld # 若firewall未启动，则先启动
firewall-cmd --reload # 重新加载firewall
firewall-cmd --zone=public --query-port=60000/udp # 查看端口是否添加成功，yes表示成功，no表示未添加成功</code></pre>
<p>使用管理员权限执行上面的命令，打开防火墙的端口就可以了，不要相信网上某些文章，将整个防火墙都关掉那种，简直饮鸩止渴。</p>
<h2 id="mac使用mosh连接服务器">Mac使用mosh连接服务器</h2>
<p>macOS默认是没有安装mosh的，类似于ssh，我们需要mosh连接，要首先安装好mosh，在mac下直接用brew安装。</p>
<pre><code class="language-bash">brew update # 可以不更新
brew install mosh</code></pre>
<p>如果没有修改过服务器的ssh端口，直接以下命令就可以连接；如果参考我的文章，修改过服务器的ssh默认端口的，参考第二条命令来连接；如果你连防火墙的udp端口也修改了，那么参考第三条命令，指定mosh走的udp端口。</p>
<pre><code class="language-bash">mosh username@server_ip # 默认情况下的命令
mosh username@server_ip --ssh=&quot;ssh -p 245&quot; # 修改ssh端口为你设置的端口
mosh username@server_ip -P 60011 # -P 指定mosh走的udp端口，如果你只打开了某个udp端口的话</code></pre>
<h2 id="win使用mosh连接服务器">Win使用mosh连接服务器</h2>
<p><img src="https://zhengzexin.com/archives/VPS_No2_mosh/images/mosh_2.png" alt=""></p>
<p>Win下我习惯使用<a href="">Termius</a>来登录mosh连接，当然如果你有其他终端软件也可以，如图将mosh的开关打开，然后填入你自己定义的SSH端口，如2222；填入用户名和密码，保存即可。</p>
<h2 id="后言">后言</h2>
<p>mosh有其优点，比如对ssh支持很好，安全性也很好；但是也有一些缺点，比如只能刷新一个屏幕，如果你的运行结果超出一个屏幕，无法滚动看回，只能用<code>less</code>来捕获来看了。</p>
<p>另外，我查看mosh的官网，发现mosh在很多不同的平台，都有支持，所以真的很优秀。</p>
<p><img src="https://zhengzexin.com/archives/VPS_No2_mosh/images/mosh.png" alt=""></p>
<h2 id="reference">Reference</h2>
<ul>
<li><a href="https://juejin.im/post/5d654f716fb9a06acf2b6af0">ssh卡顿还经常掉线？试下mosh吧！ - 掘金</a></li>
<li><a href="https://www.jianshu.com/p/8e9940ac64d4">centos7安装mosh - 简书</a></li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[2019 年终总结]]></title>
            <link>https://zhengzexin.com/archives/Summary_of_2019/</link>
            <guid>https://zhengzexin.com/archives/Summary_of_2019/</guid>
            <pubDate>Tue, 31 Dec 2019 10:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<blockquote>
<p>“听到一个段子：2019 年可能会是过去十年里最差的一年，但却是未来十年里最好的一年。”
——美团 王兴</p>
</blockquote>
<p><img src="https://zhengzexin.com/archives/Summary_of_2019/images/meituan_wangxing.png" alt="图1. 美团王兴：2019年，是未来十年最好的一年"></p>
<p>好像离18年年终总结，才没过几个月的时间，19年就悄然结束了。相比上一年，今年做出了很多第一次的尝试，因此也多了很多跟其他同龄人的交流，收获了不少大家处于相似阶段的体会。</p>
<h2 id="工作">工作</h2>
<p>去年年底裸辞，就连社保都断交了，过年后，在面试了好几家公司后，挑选了一个符合自己意愿的offer，继续从事NGS的生物信息学数据分析的工作，不过相比以前，反而专注生物信息学和程序本身，有和团队一起开发生信的软件，也有捡起HTML+CSS+JavaScript来开发工具。</p>
<p>若论影响最大的，莫过于机器学习。以前我对于机器学习只处于稍微读过公众号的阶段，觉得机器学习在目前的生活和工作中用不上，而且深度学习需要的成本也颇高，对于个人，是没有条件去学习或者实践的。机缘巧合的条件下，今年更加深入地了解机器学习，同时由于自己也在学习各种算法，对我造成的震撼还是很大的。我认为机器学习，不需要牵涉到大数据那么高的层面，反而是一类新的算法，用于辅助人们在有限的成本下，找到近似最优解。</p>
<h2 id="学习">学习</h2>
<p>今年，给自己定了许多学习计划，有一些还未完成；有成就感的是，将北京大学的《生物信息学导论》重新刷了一遍。在我刚毕业那会，其实就看过一次，但是当时刚入行，里面有很多不会用到的、太过深奥的，自己就跳过了，所以今年才要求自己完完全全重新学习一遍。我是在Coursera上学习的，在ipad上缓存好，然后就在通勤的时间里一点一点看完。</p>
<p><img src="https://zhengzexin.com/archives/Summary_of_2019/images/coursera_2.png" alt="图2. 北京大学-生物信息学导论"></p>
<h2 id="消费">消费</h2>
<p>2019年的消费，依旧是一些订阅服务，费用与去年差不多。强力推荐Office 365的订阅，1T的Onedrive存储，真的很好用！</p>
<p><img src="https://zhengzexin.com/archives/Summary_of_2019/images/bobby_2019.png" alt="图3. Bobby 的订阅统计"></p>
<ul>
<li>终于购入了年轻人的第一台macbook pro，生产力，不需要解释；</li>
<li>iPad Pro 10.5寸 + Apple Pencil，我在通勤路上，看了很多视频教程，也用MarginNote来看文献；</li>
<li>雅马哈 F600，学了一首生日歌唱给女友听，不过目前闲置ing🤦‍♂️</li>
</ul>
<h2 id="输出">输出</h2>
<p>今年博客较去年多更了一些，总共7篇日志，还是不理想。不过今年发的大部分都是较长的一些经验记录，所以也不算水，还要督促自己，有什么好的想法，就要及时记录，不要拖延到忘记。</p>
<p>博客的阅读量相比上年，其实是差不多的；今年尝试过重新用Typecho来搭建博客，感觉还不错；现在则是Github Page + Maverick来生成静态博客，希望来年能多输出有价值的文章给大家。</p>
<p><img src="https://zhengzexin.com/archives/Summary_of_2019/images/GA_2019.png" alt="图4. Google Analytics 的统计"></p>
<h2 id="生活">生活</h2>
<p>今年搬了一次家，换了一个更好的环境，虽然通勤时间长了些，却也正好我可以沿途听听播客、看看视频。</p>
<p>今年还试过去野餐，铺上一张野餐布，躺在上面吃点心，2个人一起玩switch，原来在大城市里还有那么闲暇的下午时光。</p>
<h2 id="2020">2020</h2>
<blockquote>
<p>最后，这几天我常常在想， 这个十年只剩下了最后一个月，二十一世纪 10 年代马上就要过去了，这个十年期我到底做了哪些事情，达到了十年前我对自己的期望吗。
——科技爱好者周刊：第 83 期（20191122）</p>
</blockquote>
<p>前几天，在V2EX，看到这篇<a href="https://iwenson.com/2010-2020-lost-golden-decade/">2010-2020 我错过的黄金十年</a>，如果有什么新兴的事物，你想去做，就抓紧时间去做，10年里新兴的事物太多，你能赶上抓住的太少。</p>
<p>2020年的目标，</p>
<ul>
<li>用Python写一个包，开源在Github上</li>
<li>从头到尾地看完几本书，并做好笔记</li>
<li>掌握R等语言</li>
<li>养成锻炼的习惯，减掉一身的肥肉</li>
</ul>
<p>前几天和同事吃饭才说起，以前过年时，试过大年三十晚上出门给我爸找手机充值，那时候还没有支付宝充值这些，大家过年也是互相发短信祝福。其实现在想想，也就是几年前的事，但是智能手机和移动支付的时代来得是如此迅猛；十年后，2029年时我写的年终总结会是什么样。。。。。。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[VPS装机记录（1）：SSH篇]]></title>
            <link>https://zhengzexin.com/archives/VPS_No1_SSH/</link>
            <guid>https://zhengzexin.com/archives/VPS_No1_SSH/</guid>
            <pubDate>Sat, 14 Dec 2019 12:07:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>前段时间趁黑五折扣，买了个<a href="https://zhuanlan.zhihu.com/p/23151978">小鸡</a>[^1台独立服务器开出来的多台虚拟机，叫作小鸡]来玩，由于是什么都没有的centos系统，因此一切装机都要靠自己来，也顺便记录一下自己的心得。</p>
<p>首先，开启一台VPS后，第一步肯定是登录上去，才能进行后续的操作，而我们的VPS平时放在网上，肯定有一堆无聊的人会去扫端口，密码爆破这种<a href="https://zhengzexin.com/2019/10/29/fuck_the_spam">无聊的事情</a>，所以我们第一步是保证服务器的登录安全。</p>
<p>我想要达到的目的是这样的，以下方法均是在centos7上：</p>
<ol>
<li>修改SSH默认的22端口</li>
<li>使用fail2ban去屏蔽多次尝试密码的IP</li>
<li>禁止root用户直接登录</li>
<li>使用密码加 Google Authenticator 2步验证进行登录</li>
<li>或使用有密码的SSH密钥进行登录</li>
</ol>
<h2 id="1-修改ssh端口">1. 修改SSH端口</h2>
<p>修改ssh端口需要修改ssh配置、修改firewall配置、修改SElinux配置三个文件，以下均是使用管理员权限执行。</p>
<h3 id="11-修改etcsshsshd_config文件">1.1 修改<code>/etc/ssh/sshd_config</code>文件</h3>
<p><code>vi /etc/ssh/sshd_config</code>进入该文件，找到<code>Port 22</code>这一行，然后在下面添加一行如<code>Port 43</code>作为新的端口，注意在确定可以使用新端口登录前，不要注释<code>Port 22</code>这一行，以免无法登录。</p>
<p><img src="https://zhengzexin.com/archives/VPS_No1_SSH/images/CleanShot_2019-12-09_at_22.12.01@2x.png" alt=""></p>
<h3 id="12-修改firewall配置">1.2 修改firewall配置</h3>
<pre><code class="language-bash">firewall-cmd --zone=public --add-port=43/tcp --permanent # firewall添加你选择的ssh端口，--permanent是保存设置，否则下次重启后不生效
systemctl start firewalld # 若firewall未启动，则先启动
firewall-cmd --reload # 重新加载firewall
firewall-cmd --zone=public --query-port=43/tcp # 查看端口是否添加成功，yes表示成功，no表示未添加成功</code></pre>
<p><img src="https://zhengzexin.com/archives/VPS_No1_SSH/images/CleanShot_2019-12-09_at_22.18.38@2x.png" alt=""></p>
<h3 id="13-修改selinux配置">1.3 修改SELinux配置</h3>
<p>这一步有的VPS可能是关闭SELinux的，就不需要修改；但是默认应该是打开了SELinux的，因此推荐修改。</p>
<pre><code class="language-bash">semanage port -l | grep ssh # 查看当前SELinux允许的ssh端口</code></pre>
<p>如果显示<code>semanage command not found</code>，则</p>
<pre><code class="language-bash">yum provides semanage # 或 yum whatprovides semanage
yum -y install policycoreutils-python # 安装</code></pre>
<pre><code class="language-bash">/usr/sbin/sestatus -v # 查看SELinux状态，enabled即为开启状态</code></pre>
<p>若未开启，则<code>vi /etc/selinux/config</code>，将<code>SELINUX=disabled</code>修改为<code>SELINUX=enforcing</code>，需要重启。</p>
<pre><code class="language-bash">semanage port -a -t ssh_port_t -p tcp 443 # 添加ssh端口
semanage port -l | grep ssh # 再执行一次查看是否添加成功</code></pre>
<h3 id="14-重启服务，并测试是否成功">1.4 重启服务，并测试是否成功</h3>
<pre><code class="language-bash">systemctl restart sshd  
systemctl restart firewalld.service  
shutdown -r now # 重启机器，最好重启一下</code></pre>
<p>重启后使用新端口进行ssh登录，测试是否添加成功。</p>
<pre><code class="language-bash">ssh usrname@server -p 43 # 使用-p指定端口</code></pre>
<p>登录成功后<code>vi /etc/ssh/sshd_config</code>将<code>Port 22</code>这一行注释，并继续重启服务以生效。</p>
<h2 id="2-使用fail2ban去屏蔽多次尝试密码的ip">2. 使用fail2ban去屏蔽多次尝试密码的IP</h2>
<p>修改默认ssh端口后已经可以防御很多只扫描特定端口的脚本，但是还是有被密码爆破的风险，因此我们安装fail2ban来屏蔽多次尝试密码的坏人。</p>
<pre><code class="language-bash">yum -y install epel-release # CentOS内置源并未包含fail2ban，需要先安装epel源
yum -y install fail2ban # 安装fail2ban</code></pre>
<p><code>vi /etc/fail2ban/jail.local</code>来新建fail2ban的配置，复制以下配置作为默认规则：</p>
<pre><code class="language-bash">[DEFAULT]
ignoreip = 127.0.0.1/8
bantime  = 86400
findtime = 600
maxretry = 5
#这里banaction必须用firewallcmd-ipset,这是fiewalll支持的关键，如果是用Iptables请不要这样填写
banaction = firewallcmd-ipset
action = %(action_mwl)s

[sshd]
enabled = true
filter  = sshd
port    = 43
# 这里的43为你修改后的端口
action = %(action_mwl)s
logpath = /var/log/secure</code></pre>
<p>上面的配置为十分钟内，如果连续错误超过5次，就ban掉这个IP。</p>
<p>输入<code>systemctl start fail2ban</code>启动fail2ban。<code>fail2ban-client status sshd</code>显示fail2ban的状态，查看是否有被攻击的记录。</p>
<h2 id="3-禁止root用户直接登录">3. 禁止root用户直接登录</h2>
<p>前面由于要修改、安装各种服务，因此使用root账户比较方便。但在VPS的实际使用中，首先我们要避免被坏人攻陷，直接root登录；其次我们要避免使用root用户执行危险的操作，发生意外，所以我们禁止root用户直接登录，新建一个拥有sudo权限的用户，平时使用其来登录和执行操作，减低风险。</p>
<pre><code class="language-bash">useradd newone # 新建名为newone的用户
passwd newone # 设置newone的密码</code></pre>
<p><strong>注意！！！该步骤非常重要，否则新用户可能无法登录。</strong>输入<code>vi /etc/ssh/sshd_config</code>，使用<code>AllowUsers newone</code>添加可以ssh登录的用户，<code>systemctl restart sshd</code>重启ssh服务。</p>
<p><img src="https://zhengzexin.com/archives/VPS_No1_SSH/images/CleanShot_2019-12-09_at_23.02.19@2x.png" alt=""></p>
<p>修改上一步后，保留一个终端窗口，测试新用户是否能成功登录，如果能成功登录，则禁用root用户登录。<code>vi /etc/ssh/sshd_config</code>修改其中<code>PermitRootLogin yes</code>为<code>PermitRootLogin no</code>。<code>systemctl restart sshd</code>重启ssh服务。此时root账户已经无法登录。</p>
<h2 id="4-使用密码加-google-authenticator-2步验证进行登录">4. 使用密码加 Google Authenticator 2步验证进行登录</h2>
<p>比较安全的SSH登录方式，一种是禁止密码且只允许密钥登录，只要保证密钥的安全，就能保证登录的安全；而另外一种2步验证的方法了。这里我们会用到Google Authentication，其实很多网站/App已经运用到2步验证了。</p>
<h3 id="41-安装google-authenticator">4.1 安装Google Authenticator</h3>
<pre><code class="language-bash">yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
yum install google-authenticator</code></pre>
<p>切换到要使用Google Authenticator的用户，然后输入<code>google-authenticator</code>，屏幕会显示一个超大的二维码，你需要使用支持Google Authenticator的软件，扫描该二维码或者输入“secret key”以生成动态的验证码。</p>
<p><img src="https://zhengzexin.com/archives/VPS_No1_SSH/images/CleanShot_2019-12-10_at_22.48.02@2x.png" alt=""></p>
<p><img src="https://zhengzexin.com/archives/VPS_No1_SSH/images/CleanShot_2019-12-10_at_22.50.11@2x.png" alt=""></p>
<p>红色方框就是“secret key”，而绿色方框中是临时密码，这几个密码使用一次就会失效；后面的选择可以参考我的设置；另外，Google Authenticator会在当前用户的home目录生成<code>.google_authenticator</code>文件，如果你需要更换，删掉该文件，然后重新生成即可。</p>
<h3 id="42-修改配置">4.2 修改配置</h3>
<p>修改pam配置文件，<code>vi /etc/pam.d/sshd</code>，在首行加入<code>auth required pam_google_authenticator.so</code>，这样子在输入密码登录之前，会先要求输入Google Authentication的验证码，如果是希望反过来，则将这行代码写入到pam配置文件的最后则可；</p>
<p>修改ssh配置文件，<code>vi /etc/ssh/sshd_config</code>将<code>ChallengeResponseAuthentication no</code>修改为<code>ChallengeResponseAuthentication yes</code>。</p>
<p>检查系统时间，</p>
<pre><code class="language-bash">#查看下服务器时间
date
#如果时区不一样，再使用命令修改为本地时间
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime</code></pre>
<p>最后，在保留一个活动的终端窗口的前提下，重启ssh服务，<code>systemctl restart sshd</code>，然后重新登录该用户测试是否成功（登录失败也有可能是因为终端软件的问题，比如，尝试更换软件）。</p>
<h2 id="5-使用有密码的ssh密钥进行登录">5. 使用有密码的SSH密钥进行登录</h2>
<p>其实，使用密钥进行登录已经算非常安全了，但是为了更加安全，我们还可以给密钥文件添加密码。建议在自己的常用工作电脑上使用密钥登录服务器，而在其他电脑上则保留使用密码登录的方式。</p>
<p>使用密钥登录，我们会生成非对称加密的一对密钥（不清楚非对称加密是什么？看看阮一峰老师的<a href="https://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html">这篇文章</a>），分别称之为“私钥”和“公钥”。如果公钥加密的信息只有私钥才能解开，那么只要私钥不泄露，通信就是安全的。</p>
<blockquote>
<p>（1）乙方生成两把密钥（公钥和私钥）。公钥是公开的，任何人都可以获得，私钥则是保密的。</p>
<p>（2）甲方获取乙方的公钥，然后用它对信息加密。</p>
<p>（3）乙方得到加密后的信息，用私钥解密。</p>
</blockquote>
<p>而我们使用密钥来进行登录也是这样，将公钥放在远程要登录的服务器上，从远程发送过来的数据，只有我们在本地的私钥才能解读，从而保证两者之间的通信是安全的。</p>
<h3 id="51-生成密钥对">5.1 生成密钥对</h3>
<p>在终端输入<code>ssh-keygen</code>来生成密钥，默认会保存在<code>~/.ssh/id_rsa</code>，可以自定义该文件的地址和名称，例如<code>~/.ssh/remote_server</code>。然后会询问是否添加密钥，默认是不设置密码的，这里我输入了设定的密码。然后会生成密钥文件，其中你指定的路径就是私钥文件，而<code>.pub</code>结尾的就是公钥文件。</p>
<p><img src="https://zhengzexin.com/archives/VPS_No1_SSH/images/CleanShot_2019-12-14_at_19.09.50@2x.png" alt=""></p>
<p>然后在本地的<code>~/.ssh/config</code>中添加以下代码，用于指定密钥</p>
<pre><code class="language-bash">Host RemoteServer # 随意自己起，但是要用到
    HostName 102.133.250.111 # 修改为服务器的地址，域名或IP
    User newone # 指定登录的用户
    PreferredAuthentications publickey
    IdentityFile ~/.ssh/remote_server # 指定私钥的地址
    Port 43 # 默认端口为22，如果你修改了端口，则修改为对应的端口</code></pre>
<h3 id="52-将公钥存放到目标服务器上">5.2 将公钥存放到目标服务器上</h3>
<p>打开目标服务器的目标用户的<code>~/.ssh</code>路径，然后将<code>.ssh/remote_server.pub</code>文件的内容复制到<code>~/.ssh/authorized_keys</code>里，如果没有<code>~/.ssh</code>文件夹则参考以下代码，先localhost登录一次。</p>
<pre><code class="language-bash">$ ssh localhost # 输入密码登录
The authenticity of host &#39;localhost (::1)&#39; can&#39;t be established.
ECDSA key fingerprint is SHA256:DYd7538oOsqpIIDTs01C3G4S6PRE7msA91yUgk9Dzxk.
ECDSA key fingerprint is MD5:88:80:21:03:b2:52:6b:06:ff:c7:3b:d5:2d:47:c9:ad.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added &#39;localhost&#39; (ECDSA) to the list of known hosts.
newone@localhost&#39;s password: 
Last login: Sat Dec 14 19:49:07 2019 from localhost
$ exit</code></pre>
<p>登录过后就会生成<code>~/.ssh</code>文件夹了。注意<code>~/.ssh</code>目录权限必须为700，<code>~/.ssh/authorized_keys</code>权限必须为600。</p>
<h3 id="53-修改配置文件">5.3 修改配置文件</h3>
<p>又来到熟悉的配置文件，输入<code>vi /etc/ssh/sshd_config</code>，将该文件添加以下3行，如果已有则改成一样的。</p>
<pre><code class="language-bash">RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys</code></pre>
<p>然后<code>systemctl restart sshd</code>重启ssh服务。</p>
<p>在本地使用类似<code>ssh newone@RemoteServer</code>的命令进行登录，如果登录成功则说明设置生效了。</p>
<p>至此，我们所希望的5个目标已经完全实现了。</p>
<h2 id="reference">Reference</h2>
<ul>
<li><a href="https://juejin.im/post/5c8bba80e51d4562cd767dfe">Centos7 修改 SSH 端口 - 掘金</a></li>
<li><a href="https://www.xiaoz.me/archives/9831">CentOS 7 安装 fail2ban + Firewalld 防止爆破与 CC 攻击 - 小 z 博客</a></li>
<li><a href="https://www.abcode.club/archives/230">CentOS 7 中添加一个 sudo 新用户并授权 ssh 登录 | happysir&#39;s blog</a></li>
<li><a href="https://www.moerats.com/archives/928/">Linux VPS 安装 Google Authenticator 实现 SSH 登陆二次验证</a></li>
<li><a href="https://www.cnblogs.com/luckyall/p/10368152.html">Centos7 通过 SSH 使用密钥实现免密登录</a> </li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Typecho博客被刷垃圾评论]]></title>
            <link>https://zhengzexin.com/archives/fuck_the_spam/</link>
            <guid>https://zhengzexin.com/archives/fuck_the_spam/</guid>
            <pubDate>Mon, 28 Oct 2019 16:07:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>事情的起由，源自于上周想到看看博客的情况。结果打开aliyun就发现博客最近几天的流量异常多；而打开Cloudflare的监控发现，有2个国家的IP访问数非常多；一打开博客，居然被刷了几千条垃圾评论。</p>
<h2 id="1-监控显示异常">1. 监控显示异常</h2>
<p><img src="https://zhengzexin.com/archives/fuck_the_spam/images/CleanShot_2019-10-28_at_22.15.38@2x.png" alt="上周的流量监控"></p>
<p>可以看到，由于访问量较少，所以一般情况下，每天流量只用到几M，而从20日开始，居然每天都刷了几百M甚至1G的流量，到我发现的25日，其实已经被垃圾评论刷了5天，将近3000条垃圾评论。</p>
<p><img src="https://zhengzexin.com/archives/fuck_the_spam/images/CleanShot_2019-10-28_at_22.17.08@2x.png" alt="上周的IP统计"></p>
<p>而从Cloudflare的统计则显示，来自法国、美国的访问量很异常，甚至比中国的还多；啥时候我的博客有这么多法国🇫🇷读者了？</p>
<h2 id="2-解决垃圾评论">2. 解决垃圾评论</h2>
<p>发现这些垃圾评论的第一瞬间，我就明白博客被攻击了/被刷垃圾评论了，攻击者的目的可能是刷爆你的数据库容量/主机流量||（后来有看到别的博客提到莆田的IP狂发垃圾广告评论等）||。于是第一时间当然是防止垃圾评论，禁止IP访问。</p>
<h3 id="21-删除评论，修改typecho设置">2.1 删除评论，修改Typecho设置</h3>
<p>打开aliyun后台，打开数据库的管理工具DMS，打开表<code>typecho_comments</code>，查找垃圾评论的coid范围，然后打开SQL窗口，输入语句</p>
<pre><code class="language-MYSQL">DELETE FROM `typecho_comments` WHERE `coid` BETWEEN 3180 AND 3185 # 3180到3185是垃圾评论的coid范围</code></pre>
<p>打开Typecho后台-&gt;设置-&gt;评论，勾选“所有评论必须经过审核”或“评论者之前须有评论通过了审核”，由于脚本是会更改IP来刷评论，因此勾选这2项，可以先禁止文章中继续产生垃圾评论。而“允许使用的HTML标签和属性”一栏中，也应该清空，防止垃圾评论里的网页链接。</p>
<p><img src="https://zhengzexin.com/archives/fuck_the_spam/images/CleanShot_2019-10-28_at_22.34.41.png" alt="Typecho后台评论选项"></p>
<h3 id="22-安装typecho-插件或修改php文件">2.2 安装Typecho 插件或修改PHP文件</h3>
<ul>
<li>小墙AntiSpam</li>
<li><a href="http://www.yovisun.com/archive/typecho-plugin-smartspam.html">SmartSpam by YoviSun</a></li>
<li>comment.php修改为只允许中文环境评论</li>
<li><a href="https://www.ruletree.club/archives/1167/">CC 5秒盾</a></li>
</ul>
<p>推荐使用SmartSpam，因为该插件可以屏蔽IP、选择评论的处理方式（标记为待审核/标记为垃圾/评论失败）、禁止关键字/词汇等。也支持只允许中文评论。</p>
<p>而小墙AntiSpam确实能挡住垃圾评论，但是我看了源码，源码只有90行左右，且容易误判。所以还是不推荐。</p>
<p>而CC五秒盾，更多的是防止CC攻击或者频率很高的脚本。如果不清楚作用的，建议不要使用。</p>
<h3 id="23-主机平台屏蔽或cloudflare防御">2.3 主机平台屏蔽或Cloudflare防御</h3>
<p>如果你的主机平台有屏蔽IP的措施，那么你也可以增加规则；而我则使用Cloudflare来防御。首先可以打开Cloudflare的“Overview”下的“Under Attack Mode”，会产生如CC五秒盾一样的效果，每个访问会先等待5秒再进入；而“Firewall”下的“Firewall Rules”也可以增加屏蔽特定国家/IP的访问。</p>
<p><img src="https://zhengzexin.com/archives/fuck_the_spam/images/CleanShot_2019-10-28_at_23.09.35.png" alt="Cloudflare攻击防御模式"></p>
<p><img src="https://zhengzexin.com/archives/fuck_the_spam/images/CleanShot_2019-10-28_at_23.09.55.png" alt="Cloudflare防火墙规则设置"></p>
<h3 id="24-安装评论提醒插件">2.4 安装评论提醒插件</h3>
<ul>
<li><a href="https://blog.imalan.cn/archives/349/">Mailer by 熊猫小A</a></li>
<li><a href="https://lscho.com/tech/comment_to_wechat.html">CommentToWechat by lscho</a></li>
</ul>
<p>这次被攻击了5天才知道，就是由于没有安装评论提醒插件，所以吸取教训，也为了改善评论访客的体验，所以安装这2款插件；Mailer是VOID主题作者配套的邮件提醒插件，果然刚设置好，立刻收到好几封垃圾评论邮件，也算间接测试了；而CommentToWechat则借用了Server酱发送微信提醒，更加能随时随地收到评论提醒。</p>
<h2 id="3-从垃圾评论说开来">3. 从垃圾评论说开来</h2>
<p>有了以上的这些手段，一般的攻击应该是可以防御了。其实从将博客迁移回Typecho前，我就有这方面的担心，因为很久以前使用Wordpress搭建博客时，也遇到过攻击；那时大部分博客工具如Wordpress、Emlog等都是php语言写的，而很多这方面的攻击工具就针对php的站点，如扫描你数据库的端口等各种攻击。</p>
<p>其实，躲在网络另一边的攻击者，一般技术没有多厉害，不然的话，我的博客早就被打瘫了。而这种人只是找到了这些工具，然后就迫不及待地去找别人的站点来尝试，如果尝试成功了，就感觉得到莫名的成就感/虚荣感。</p>
<p>很神奇的是，并不止博客类站点有这种情况，其实网络上就是充斥了很多这种损人不利己的行为，如我之前听到GGtalk里的<a href="https://talk.swift.gg/43">《游戏加速纵横谈》</a>这期，就提到曾经有段时间，加速器服务厂商们经常受到DDOS攻击，其实大家都能猜到大概是哪些人做的。对付无聊的人，最好的方法就是不理他们。</p>
<p>截止到目前，攻击还在继续，而它们再也不能威胁到我的博客。</p>
<p><img src="https://zhengzexin.com/archives/fuck_the_spam/images/CleanShot_2019-10-28_at_23.21.47.png" alt="24小时内的IP统计"></p>
<p>背景图：Photo by Franck V. on Unsplash</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[记录 VEP 关于 COSMIC 注释的一个坑]]></title>
            <link>https://zhengzexin.com/archives/VEP_note1/</link>
            <guid>https://zhengzexin.com/archives/VEP_note1/</guid>
            <pubDate>Sun, 30 Jun 2019 15:22:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>工作中有用到VEP，确实是一款出色的注释软件。相比ANNOVAR，最大的优点是支持HGVS标准的注释。</p>
<p>可能由于ANNOVAR面世比较早，当时很多变异描述的标准还没有通行，ANNOVAR采取的是按照基因组来<code>left-normalization</code>的方法，而HGVS的标准，则是根据基因/转录本的方向来<code>left-normalization</code>，因此有可能有的基因与ANNOVAR注释的方向相反。在某些地方，如<code>delins</code>的突变，ANNOVAR与VEP的注释也会不相同，当然，我们还是认为两者都是很出色的注释软件。（关于注释软件的比较，可以看看Golden Helix的这篇文章，<a href="http://blog.goldenhelix.com/goldenadmin/the-sate-of-variant-annotation-a-comparison-of-annovar-snpeff-and-vep/%EF%BC%89">http://blog.goldenhelix.com/goldenadmin/the-sate-of-variant-annotation-a-comparison-of-annovar-snpeff-and-vep/）</a></p>
<p>这次，主要是<a href="https://zhengzexin.com/bioinfo/ji-lu-vepguan-yu-cosmiczhu-shi-de-yi-ge-keng">记录一个VEP关于COSMIC注释的坑</a>，避免大家以后踩到。事情的缘由，还是Ryu的一个同事，发现在一个Somatic突变上，VEP注释了多个COSMIC记录，而查证后却发现，很多事不正确的。</p>
<p>比如，我们用编号为<code>COSM476</code>的<code>BRAF:V600E</code>来举例：</p>
<p><img src="https://zhengzexin.com/archives/VEP_note1/images/CleanShot_2019-06-30_at_20.45.05@2x.png" alt=""></p>
<p>可见，VEP确实注释了多个COSMIC ID，但只有<code>COSM476</code>才是正确的。What？这是怎么发生的。</p>
<p>于是Ryu就去查VEP的文档，终于被我发现了原因。VEP注释是可以注释COSMIC的记录的，但是这个注释，主要是根据染色体坐标而进行的<code>co-located variants</code>注释，没有判断这个突变是什么碱基变化的。</p>
<p><img src="https://zhengzexin.com/archives/VEP_note1/images/CleanShot_2019-06-30_at_20.49.41@2x.png" alt=""></p>
<p>那么为什么要这么做呢？VEP明显是可以实现分辨碱基突变的功能的。援引VEP的原文，原来Ensembl并没有COSMIC、HGMD等数据库的精细到碱基突变的使用许可协议，因此这些数据能够被注释，但是却是换了一个方法，只能精细到染色体位置的层级。</p>
<blockquote>
<p>For some data sources (COSMIC, HGMD), Ensembl is not licensed to redistribute allele-specific data, so VEP will report the existence of co-located variants with unknown alleles without carrying out allele matching. To disable this behaviour and exclude these variants, use the --exclude_null_alleles flag.</p>
</blockquote>
<p>看到这里，不禁感叹外国人对于版权的意识。在国内，可能COSMIC的注释，分分钟就被人注释上去了，也不会有人追究。其实ANNOVAR的COSMIC注释也止步更新于V70，而现在的COSMIC版本都已经快V90了。</p>
<p><img src="https://zhengzexin.com/archives/VEP_note1/images/73373ab0-5d76-4e9b-9cc3-c86321a70725.png" alt=""></p>
<p>大家以后使用VEP的时候，不要直接使用注释其中的COSMIC记录哦。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[记录一次 Name.com 自动续费成功退款的经过]]></title>
            <link>https://zhengzexin.com/archives/successful_refund_from_Name_com/</link>
            <guid>https://zhengzexin.com/archives/successful_refund_from_Name_com/</guid>
            <pubDate>Sat, 04 May 2019 15:22:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>上个月的某天，我收到 Name.com 的邮件提示，告诉我的一个网站自动续费了；之前我已经收到关于这个域名快要到期的邮件了，但是没想到在域名有效期还剩下一个月左右的时候，Name.com 就帮我自动续费了。</p>
<p>本来我是打算在 Name.com 上续费的，因为 Name.com 续费可以使用优惠码进行打折，而且 WHOIS 隐私服务也可以使用优惠码来兑换，算是挺实惠的。</p>
<p><img src="https://zhengzexin.com/archives/successful_refund_from_Name_com/images/CleanShot_2019-05-04_at_12.02.37@2x.png" alt=""></p>
<p>但是没想到 Name.com 抢先在我之前就自动续费了，而且还是按着全额的价格来续费（可以看到，本来 10.99 刀，而现在 12.99+4.99 刀，多花了将近 7 刀）。</p>
<p><img src="https://zhengzexin.com/archives/successful_refund_from_Name_com/images/CleanShot_2019-05-04_at_17.11.13@2x.png" alt=""></p>
<p>于是我想，不能吃了这个哑巴亏呀，我要尝试一下能不能退款。毕竟 7 刀也差不多够我再买一个新的.com 域名了（Name.com COM 注册为 8.99 刀）。于是我到网上 Google，没想到大部分人说的都是，这是不能退款，有的人说这钱是交给注册局的，有的说域名注册能退但续费不能退，也有的说能退款，但是必须删除掉你的域名，这样注册局才能退钱之类云云。但是我也在网上搜到极少数的说成功退款的经历，主要还是域名注册的。</p>
<p>不管怎么说，不试试怎么知道呢，于是我 Google 了一下退款的工单的例子，然后提交了一份工单。一般外国的服务商上班时间都是国内的晚上，所以提交工单之后，就需要耐心地等待那边上班了。</p>
<p><img src="https://zhengzexin.com/archives/successful_refund_from_Name_com/images/CleanShot_2019-05-04_at_17.13.58@2x.png" alt=""></p>
<p>隔了差不多一天，Name.com 给我回复了，</p>
<p><img src="https://zhengzexin.com/archives/successful_refund_from_Name_com/images/CleanShot_2019-05-04_at_17.17.05@2x.png" alt=""></p>
<p>其中有几个需要注意的点，：</p>
<ol>
<li>退款需要在交易的 5 天内完成；</li>
<li>需要删除我的域名；</li>
</ol>
<p>同时他也提到，需要我回复确认是否删除域名；另外删除后我可以提交退款单，退款就会打到我的邮箱。</p>
<p>这时我就有点懵逼了，真的如网上所说的，需要删掉我的域名才能给我退款？但是邮件里他的表达又有点含糊其辞，没有表达清楚这个删除是什么意思？是向注册局提交我放弃我的域名（我的域名还有 1 个月左右的有效期）？还是在 Name.com 上删除我的域名？于是我给他回了邮件，希望他再次解释清楚，并且询问是否能不删除域名，只是取消续费的操作。</p>
<p><img src="https://zhengzexin.com/archives/successful_refund_from_Name_com/images/CleanShot_2019-05-04_at_17.22.19@2x.png" alt=""></p>
<p>很快又收到 Name.com 工作人员的回复了，这次他的回复再次表达到，如果需要退款，必须先删除掉我的域名。</p>
<p><img src="https://zhengzexin.com/archives/successful_refund_from_Name_com/images/CleanShot_2019-05-04_at_17.24.04@2x.png" alt=""></p>
<p>但是后面的第二段内容则有点意思了，他说到我可以选择转移域名或者将域名留在这里。这是否意味着，我将域名转移走，也属于在 Name.com 删除我的域名的操作？于是我怀着希望，再次给他回复邮件了。</p>
<p><img src="https://zhengzexin.com/archives/successful_refund_from_Name_com/images/CleanShot_2019-05-04_at_17.27.00@2x.png" alt=""></p>
<p>很快，我又收到了回复，</p>
<p><img src="https://zhengzexin.com/archives/successful_refund_from_Name_com/images/CleanShot_2019-05-04_at_17.27.14@2x.png" alt=""></p>
<p>没错，这次他肯定地答复，如果我在自动续费交易发生的 5 天内完成域名的转移，那么将能够退款给我。OK，那么其实这个时候已经距离自动续费的交易过了有 3、4 天了，而我则需要尽快完成域名转移。</p>
<p>这时候就要使用 <a href="https://www.domcomp.com/">domcomp</a> 这个神器了，这个网站，可以查询不同后缀的域名，注册、续费、转移的最便宜的价格的域名服务商有哪些。于是我搜索了.com 转移的最便宜的服务商。</p>
<p><img src="https://zhengzexin.com/archives/successful_refund_from_Name_com/images/CleanShot_2019-05-04_at_17.33.43@2x.png" alt=""></p>
<p>没错，我们能看到，.com 最便宜的转移价格在 1&amp;1 这个网站，价格为 1 刀，其实这里可能由于 domcomp 这个网站的数据有些错误，所以 1&amp;1 的转移价格并不是 1 刀，只是新注册.com 的价格为活动价 1 刀。</p>
<p>但是我之前也有域名在 1&amp;1 上面，于是正好，也免得注册别的了，就转移到 1&amp;1 上面吧，这里不得不夸奖 Name.com 的服务，还有 ** 加速转移域名 ** 的按钮，于是很快我的域名就提交了加速转移了。</p>
<p>接着我就直接提交了退款单，等待 Name.com 的退款了，这时还是有点紧张的，因为已经接近 5 天的限期，而且不知道 Name.com 的工作人员上班处理时间是什么时候，也不知道域名是否已经完全转移成功。</p>
<p><img src="https://zhengzexin.com/archives/successful_refund_from_Name_com/images/CleanShot_2019-05-04_at_17.39.00@2x.png" alt=""></p>
<p>接着我就收到与之前几乎一模一样的回复，于是这次我就回复确认删除且退款。</p>
<p><img src="https://zhengzexin.com/archives/successful_refund_from_Name_com/images/CleanShot_2019-05-04_at_17.39.41@2x.png" alt=""></p>
<p><img src="https://zhengzexin.com/archives/successful_refund_from_Name_com/images/CleanShot_2019-05-04_at_17.40.00@2x.png" alt=""></p>
<p> 然后，我就收到了确认退款的回复了，大概需要 3-5 天的时间，退款将会退回到我的信用卡。</p>
<p><img src="https://zhengzexin.com/archives/successful_refund_from_Name_com/images/CleanShot_2019-05-04_at_17.40.16@2x.png" alt=""></p>
<p>最后耐心地等待，就收到银行的退款确认了。可以看到，从自动续费到退款，整个事件在 5、6 天左右。最后称赞一下，Name.com 的服务还是很棒的，工单回复也算及时，而且域名服务有免费的 WHOIS 隐私赠送。</p>
<p><img src="https://zhengzexin.com/archives/successful_refund_from_Name_com/images/CleanShot_2019-05-04_at_17.48.20@2x.png" alt=""></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[静态编译 Tmux]]></title>
            <link>https://zhengzexin.com/archives/Tmux_static_compilation/</link>
            <guid>https://zhengzexin.com/archives/Tmux_static_compilation/</guid>
            <pubDate>Sun, 24 Mar 2019 15:22:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>最近在学习使用 Tmux 这个终端复用神器，由于服务器上并不是管理员用户，因此就想自己静态编译安装 Tmux。</p>
<p><a href="https://github.com/tmux/tmux/wiki">Tmux 的Github wiki</a></p>
<h2 id="centos-静态编译">CentOS 静态编译</h2>
<p>方法很简单，但是也绕了不少弯路。</p>
<p>根据wiki，首先我们下载 <a href="https://github.com/tmux/tmux/releases">tmux</a>，以及所依赖的<code>libevent 2.x</code>与<code>ncurses</code>。</p>
<pre><code class="language-bash">cd ~/Downloads # 将文件下载到Downloads
wget -c https://github.com/tmux/tmux/releases/download/2.8/tmux-2.8.tar.gz
wget -c https://github.com/libevent/libevent/releases/download/release-2.1.8-stable/libevent-2.1.8-stable.tar.gz
wget -c ftp://ftp.invisible-island.net/ncurses/ncurses.tar.gz</code></pre>
<p>首先编译安装依赖项</p>
<pre><code class="language-bash">tar zxf ncurses.tar.gz
cd ncurses-6.1
./configure --prefix=path/to/temp &amp;&amp; make &amp;&amp; make install # 将 ncurses 安装到path/to/temp，请注意使用绝对路径
tar zxf libevent-2.1.8-stable.tar.gz
cd libevent-2.1.8-stable
./configure --prefix=path/to/temp &amp;&amp; make &amp;&amp; make install # 将 libevent 安装到path/to/temp，请注意使用绝对路径</code></pre>
<p>然后编译安装 tmux</p>
<pre><code class="language-bash">tar zxf tmux-2.8.tar.gz
cd tmux-2.8
export LDFLAGS=&quot;-L/usr/lib -Lpath/to/temp/lib -Wl,-R/usr/lib -Wl,-Rpath/to/temp/lib&quot; # 注意修改成上述编译依赖项的绝对路径，注意是-Wl,-R，不会 C 的我卡在这里好久
export CFLAGS=&quot;-I/usr/include -Ipath/to/temp/include&quot; # 注意修改成上述编译依赖项的绝对路径
./configure --prefix=path/to/tmux2 # 注意修改路径
make &amp;&amp; make install
###
PATH=$PATH:path/to/tmux/bin/ # 将这句添加到~/.bashrc或~/.zshrc，然后重启终端或 source 一下
###</code></pre>
<h2 id="其他方法以及在-mac-上">其他方法以及在 Mac 上</h2>
<p>在 Mac 上安装肯定是使用 brew 安装最简单快捷，</p>
<pre><code class="language-bash">brew install tmux</code></pre>
<p>但其实在 Linux 上，也有<a href="https://docs.brew.sh/Homebrew-on-Linux">Linuxbrew</a>，安装完 Linuxbrew 后，也可以使用以上语句进行安装，但我尝试后失败，可能是由于非root用户，所以部分依赖项还是无法安装上，所以这个方法也不是很推荐。</p>
<p>最后一个方法，当然是使用万能的 conda 啦，当时服务器上我并没有安装 conda，因此就直接使用了静态编译。</p>
<p><a href="https://anaconda.org/conda-forge/tmux">conda-forge/packages/tmux 2.7</a></p>
<pre><code class="language-bash">conda install -c conda-forge tmux </code></pre>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[基因组、cDNA、氨基酸坐标转换神器：Transvar]]></title>
            <link>https://zhengzexin.com/archives/Transvar/</link>
            <guid>https://zhengzexin.com/archives/Transvar/</guid>
            <pubDate>Sat, 16 Mar 2019 04:38:00 GMT</pubDate>
            <content:encoded><![CDATA[<h2 id="简介">简介</h2>
<p>Transvar 是 MD Anderson 开发的一款多种方向的突变/坐标转换工具，它支持基因组坐标、cDNA 坐标以及蛋白氨基酸坐标之间的转换。Google 了一下，发现对于这个工具的介绍还是很少的，于是来介绍一下。</p>
<p>举个实际例子，肺癌中的EGFR基因突变，在 COSMIC 上见到的一个突变的描述网页如下，我们可以看到id 为<code>COSM6223</code>的突变，是一个 EGFR 基因上的缺失突变，对应的 cDNA 上的突变为<code>c.2235_2249del15</code>，而氨基酸突变为<code>p.E746_A750delELREA</code>，基因组坐标则为<code>7:55242465..55242479</code>；那么这个突变是否属于 EGFR 19号外显子缺失呢？缺失的序列是哪些？</p>
<p><img src="https://zhengzexin.com/archives/Transvar/images/2019-03-16-CleanShot_2019-02-11_at_00.27.17@2x.png" alt=""></p>
<h2 id="网页版使用">网页版使用</h2>
<p>首先我们打开 Transvar 的网页版：<a href="https://bioinformatics.mdanderson.org/transvar/">https://bioinformatics.mdanderson.org/transvar/</a></p>
<p><img src="https://zhengzexin.com/archives/Transvar/images/2019-03-16-CleanShot_2019-02-11_at_00.14.17@2x.png" alt=""></p>
<h3 id="基因组正向注释">基因组正向注释</h3>
<p>首先我们来尝试从基因组正向注释到 cDNA 及氨基酸坐标上。勾选<code>Forward Annotation: gDNA</code>，我们可以看见示例输入如下。</p>
<p><img src="https://zhengzexin.com/archives/Transvar/images/2019-03-16-CleanShot_2019-02-11_at_00.38.49@2x.png" alt=""></p>
<p>于是如上图，我们勾选<code>GRCh37/hg19</code>，并且勾选下面的<code>RefSeq</code>（需要其他数据库的可以都勾选上），在右侧的输入框中输入<code>chr7:g.55242465_55242479del</code>，点击<code>Submit</code>提交。</p>
<p>然后我们就能看到结果如下，</p>
<p><img src="https://zhengzexin.com/archives/Transvar/images/2019-03-16-CleanShot_2019-02-11_at_00.41.17@2x.png" alt=""></p>
<p>如下图，<code>XM_</code>开头的为预测转录本，我们只看<code>NM_005228</code>的结果，该突变确实为 EGFR 19号外显子缺失，并且缺失的序列为<code>AGGAATTAAGAGAAGC&gt;A</code>。滑动滚动条，我们还能看到更多的注释结果。</p>
<p><img src="https://zhengzexin.com/archives/Transvar/images/2019-03-16-CleanShot_2019-02-11_at_00.42.06@2x.png" alt=""></p>
<h3 id="cdna-反向注释">cDNA 反向注释</h3>
<p>尝试了基因组正向的注释，我们来测试一下通过 cDNA 坐标反向注释回基因组以及氨基酸坐标，这在我们只知道某种转录本的特定突变，需要查找基因、基因组坐标时特别有用。</p>
<p>如下图，勾选<code>Reverse Annotation: cDNA</code>，保持勾选<code>GRCh37/hg19</code>以及下面的<code>RefSeq</code>，根据示例提示，输入<code>EGFR:c.2235_2249del</code>，Submit。</p>
<p><img src="https://zhengzexin.com/archives/Transvar/images/2019-03-16-CleanShot_2019-02-12_at_01.40.24@2x.png" alt=""></p>
<p>如下图我们可以看到结果与之前的基因组正向注释的输入、结果都是一致的。</p>
<p><img src="https://zhengzexin.com/archives/Transvar/images/2019-03-16-CleanShot_2019-02-12_at_01.41.18@2x.png" alt=""></p>
<h3 id="氨基酸反向注释">氨基酸反向注释</h3>
<p>最后我们来尝试一下通过氨基酸突变的反向注释，当我们获得以氨基酸水平的突变表示时，我们可以通过 Transvar，轻松地转换成基因组/cDNA 水平的突变。如下图勾选<code>Reverse Annotation: Protein</code>，同样保持勾选<code>GRCh37/hg19</code>以及下面的<code>RefSeq</code>，根据示例提示，输入<code>EGFR:p.E746_A750delELREA</code>，Submit。</p>
<p><img src="https://zhengzexin.com/archives/Transvar/images/2019-03-16-CleanShot_2019-02-12_at_01.45.00@2x.png" alt=""></p>
<p>如下图，结果毫无疑问是一致的。</p>
<p><img src="https://zhengzexin.com/archives/Transvar/images/2019-03-16-CleanShot_2019-02-12_at_01.54.30@2x.png" alt=""></p>
<p>另外，当我们输入为<code>EGFR:p.746_750</code>时，如下图我们看到 Transvar 依然可以给我们转换出这个密码子的基因组水平的坐标范围以及 cDNA 水平的坐标范围，这在我们需要通过密码子来查找对应的基因组范围时特别有用。</p>
<p><img src="https://zhengzexin.com/archives/Transvar/images/2019-03-16-CleanShot_2019-02-12_at_01.56.34@2x.png" alt=""></p>
<h2 id="终端版使用">终端版使用</h2>
<p>这么有用的工具，即使在网页上上传输入文件<strong>批量转换坐标</strong>，对于我们生信工作者来说，有时仍然有些麻烦。</p>
<p>那么能否将 Transvar 部署到本地呢？答案是肯定的！</p>
<p>Transvar 提供了本地部署的方法：</p>
<p>旧版的代码托管主页放在了 SourceTree，<a href="https://bitbucket.org/wanding/transvar">https://bitbucket.org/wanding/transvar</a>，<em>last modified 2016-04-12</em></p>
<p>而新版的代码托管则迁移到了 Github 上，<a href="https://github.com/zwdzwd/transvar">https://github.com/zwdzwd/transvar</a>，并且用户文档位于<a href="https://transvar.readthedocs.io/en/latest/index.html">Read the Docs</a>。</p>
<p>而且还提供了 <a href="https://cloud.docker.com/repository/docker/zhouwanding/transvar/general">Docker 镜像</a>。</p>
<h3 id="安装">安装</h3>
<p>参考<a href="https://transvar.readthedocs.io/en/latest/download_and_install.html">用户文档</a>，安装 Transvar 主要分<code>pip安装</code>和<code>Docker 镜像</code>2种；但安装后需要下载配置 reference 数据库。</p>
<p>使用Python pip进行安装：</p>
<pre><code class="language-shell">sudo pip install transvar # 全局安装
pip install --user transvar # 用户安装</code></pre>
<p>使用 Docker 镜像进行安装</p>
<pre><code class="language-shell">docker pull zhouwanding/transvar:2.4.6
docker run -v ~/references/hg38:/data -ti zhouwanding/transvar:2.4.6 transvar panno -i PIK3CA:p.E545K --ensembl --reference /data/hg38.fa
# -v 加载~/references/hg38到 Docker Container 中的/data路径
# transvar panno -i PIK3CA:p.E545K --ensembl --reference /data/hg38.fa 为注释调用命令</code></pre>
<p>下载配置 Reference 数据库也很简单，以<code>hg19</code>为例</p>
<pre><code class="language-shell"># set up databases
transvar config --download_anno --refversion hg19

# in case you don&#39;t have a reference
transvar config --download_ref --refversion hg19

# in case you do have a reference to link
transvar config -k reference -v [path_to_hg19.fa] --refversion hg19</code></pre>
<p>也可以自己自定义配置数据库，具体设置请参考<a href="https://transvar.readthedocs.io/en/latest/setup_and_customize_transvar.html#setup-and-customize">Setup and Customize</a>。</p>
<p>另外，由于直接使用Transvar的命令下载参考数据库有点像<code>ANNOVAR</code>，容易因网络问题出错，因此你也可以到<a href="http://transvar.info/transvar_user/annotations/">http://transvar.info/transvar_user/annotations/</a>直接自行下载，然后配置（PS：默认的hg19的 dbSNP 数据库是2016年的，而2018年dbSNP v150等SNP 数量直接翻一番，所以建议自行重新下载）。</p>
<h3 id="使用">使用</h3>
<p>使用命令也很清晰明了，由于与网页版类似，所以只列出对应的命令，更详细的内容请参考<a href="https://transvar.readthedocs.io/en/latest/index.html">用户文档</a>。</p>
<pre><code class="language-shell">transvar ganno --ccds -i &#39;chr3:g.178936091G&gt;A&#39; # 基因组正向注释
transvar canno --ccds -i &#39;PIK3CA:c.1633G&gt;A&#39; # cDNA反向注释
transvar panno -i &#39;PIK3CA:p.E545K&#39; --ensembl # 氨基酸反向注释
# 其中--ccds、--ensembl为使用不同的数据库，如网页版，可以同时多选，\
# 如 --ccds --ensembl --refseq --ucsc 来进行多选

# 批量注释
## 样式一
# cat data/small_batch_input
# chr3:g.178936091G&gt;A
transvar ganno -l data/small_batch_input --ccds # 直接-l输入格式已转换好的输入文件

## 样式二
# cat data/small_batch_input
# chr3 178936091       G       A       CCDS43171
# chr9 135782704       C       G       CCDS6956
transvar ganno -l data/small_batch_input -g 1 -n 2 -r 3 -a 4 -t 5 --ccds 
# 指定-g、-n、-r、-a、-t对应的列（染色体、位置、ref、alt、transcript）

## 样式三
# cat data/small_batch_hgvs
# CCDS43171    chr3:g.178936091G&gt;A
# CCDS6956     chr9:g.135782704C&gt;G
transvar ganno -l data/small_batch_hgvs -m 2 -t 1 --ccds
# 类似样式一，-t可选，指定-t、-m对应的列（mutation、transcript）</code></pre>
<h2 id="总结">总结</h2>
<p>以上，我们可以看到 Transvar 作为坐标转换的神器的作用，特别是大批量的基因组区域、突变需要进行转换/注释时，甚至能指定 VCF 格式的输出。Transvar 其实16年甚至更早就已经发布，一开始源码放在Bitbucket上，经历了很长一段时间的没有更新，后来又转到 Github 上，令人可喜地发现最近又频繁更新起来。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[macOS Case Sensitive to Case Insensitive（使用 Carbon Copy Cloner）]]></title>
            <link>https://zhengzexin.com/archives/macOS_Case_Sensitive_to_Case_Insensitive/</link>
            <guid>https://zhengzexin.com/archives/macOS_Case_Sensitive_to_Case_Insensitive/</guid>
            <pubDate>Sat, 02 Feb 2019 04:33:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>最近，入手了 MBP 2018，就想着将旧电脑的数据<a href="https://support.apple.com/zh-cn/HT204350">使用“迁移助理”迁移到新 macbook</a>，但是打开迁移助理后却提示由于旧电脑的文件系统格式是“Mac OS 拓展（区分大小写，日志式）”（Case-sensitive, Journaled），而新 macbook 则是默认“Mac OS 拓展（日志式”（without the Case-sensitive），因此不支持数据迁移。</p>
<p>这可难倒我了，旧电脑使用了很久，里面有很多购买的软件，也有很有程序的设置和文件，如果要手动拷贝到新 macbook 上，无疑是很低效，而且效果也不好的。</p>
<h2 id="初步搜索结果">初步搜索结果</h2>
<p>于是我初步 Google 了一下，先是找到了2种方法：</p>
<ul>
<li>将新 macbook 格盘成大小写敏感重装系统，再数据迁移（缺点是新 macbook 的文件系统格式变成了大小写敏感）</li>
<li>将旧电脑修改所有大小写重名的文件，做一个 TimeMachine，然后旧电脑格盘成大小写不敏感，再使用 TimeMachine 恢复，最后数据迁移（缺点是较繁琐，且旧电脑的数据被格掉，方法来自 <a href="https://github.com/cr/MacCaseSensitiveConversion">https://github.com/cr/MacCaseSensitiveConversion</a>）</li>
</ul>
<p>先说一下2个方法，第一个方法肯定可行，但是 macOS 默认大小写不敏感是有道理的，很多软件默认不支持大小写敏感的文件系统，比如我装 steam 平台时就遇到过。且目前而言，大小写不敏感的文件系统利大于弊，因此我决定使用大小写不敏感的文件系统，第一个方法被否掉。</p>
<p>第二个方法，其实也算比较冒险且繁琐，需要经历查找-重命名-备份-格盘-恢复-迁移的步骤，而且万一格盘后不能恢复（网上曾见过大小写敏感的 TimeMachine 不能被恢复成大小写不敏感），原始文件都没了。如果没有找到第三个方法，那么我可能被迫只能使用第二个方法了。</p>
<p>另外在Google 过程中，找到一个<a href="https://coriolis-systems.com/">名为“iDefrag”的软件（旧名称为“iPartition”）</a>，有人称是可以进行大小写敏感的转换的，遗憾的是，该软件预计在19年7月份才更新到支持 macOS 10.10以上，因此同样放弃。</p>
<h2 id="解决方法">解决方法</h2>
<p>碰巧的是，当我过了几天，再 Google 搜索时，居然找到有人使用 <a href="https://bombich.com/">Carbon Copy Cloner</a> 将文件系统转换成大小写不敏感的经历，虽然是16年的帖子，但是有成功的经历，且我自己看了整个流程后，发现不用格盘，因此信心倍增。</p>
<p>流程如下：</p>
<ol>
<li><p>下载 Carbon Copy Cloner（以下简称 CCC），安装，有30天的试用期，因此完全够用了； 
<img src="https://zhengzexin.com/archives/macOS_Case_Sensitive_to_Case_Insensitive/images/2019-02-08-CleanShot_2019-02-02_at_01.08.27@2x.png" alt=""></p>
</li>
<li><p>使用 CCC 将 Mac 系统盘备份到一个大小写不敏感的分区（此步我是在旧电脑的硬盘上分出1个足够大小的大小写不敏感分区，读者使用移动硬盘或者足够大小的 U 盘也是可以的）
<img src="https://zhengzexin.com/archives/macOS_Case_Sensitive_to_Case_Insensitive/images/2019-02-08-%E7%A3%81%E7%9B%98%E5%B7%A5%E5%85%B7_2019-02-01_at_17.06.15.png" alt="磁盘工具">
<img src="https://zhengzexin.com/archives/macOS_Case_Sensitive_to_Case_Insensitive/images/2019-02-08-Carbon_Copy_Cloner_2019-02-01_at_17.01.02.png" alt="Carbon Copy Cloner"></p>
</li>
<li><p>检查备份是否成功，下图可见大小写重名冲突只是少量文件，因此我推测可以成功
<img src="https://zhengzexin.com/archives/macOS_Case_Sensitive_to_Case_Insensitive/images/2019-02-08-Carbon_Copy_Cloner_2019-02-01_at_17.01.37.png" alt="Carbon Copy Cloner">
<img src="https://zhengzexin.com/archives/macOS_Case_Sensitive_to_Case_Insensitive/images/2019-02-08-Carbon_Copy_Cloner_2019-02-01_at_17.01.59.png" alt="Carbon Copy Cloner"></p>
</li>
<li><p>挂载备份盘（备份盘分区时命名为 Recovery HD）</p>
</li>
<li><p>在“系统偏好设置”中，进入“启动磁盘”，并选择Recovery HD，重新启动
<img src="https://zhengzexin.com/archives/macOS_Case_Sensitive_to_Case_Insensitive/images/2019-02-08-%E7%B3%BB%E7%BB%9F%E5%81%8F%E5%A5%BD%E8%AE%BE%E7%BD%AE_2019-02-01_at_17.06.32.png" alt="系统偏好设置">
<img src="https://zhengzexin.com/archives/macOS_Case_Sensitive_to_Case_Insensitive/images/2019-02-08-%E7%B3%BB%E7%BB%9F%E5%81%8F%E5%A5%BD%E8%AE%BE%E7%BD%AE_2019-02-01_at_17.06.45.png" alt="系统偏好设置"></p>
</li>
<li><p>以 Recovery HD 重启 mac 系统，登录进入（会发现克隆了一个一模一样的环境，CCC 真强大）</p>
</li>
<li><p>此时我们已经拥有了一个大小写不敏感的 Mac 系统了，启动迁移助理，成功完成数据迁移!（最后需要提醒，使用数据迁移，尽量使用雷电数据线或者网线进行数据传输，速度将会快很多，70G 的数据迁移，<del>WIFI 下需要12h 以上</del>，网线情况下我只使用了约2h）
<img src="https://zhengzexin.com/archives/macOS_Case_Sensitive_to_Case_Insensitive/images/2019-02-08-UNADJUSTEDNONRAW_thumb_9fb.jpg" alt=""></p>
</li>
</ol>
<h2 id="参考网页">参考网页</h2>
<ol>
<li><a href="https://discussions.apple.com/thread/7546003">https://discussions.apple.com/thread/7546003</a></li>
<li><a href="https://forums.macrumors.com/threads/case-sensitive-to-normal.1969880/">https://forums.macrumors.com/threads/case-sensitive-to-normal.1969880/</a></li>
<li><a href="https://twiceyuan.com/2018/12/11/MacCaseSensitiveConversion/">macOS 文件系统的大小写敏感转换</a></li>
</ol>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[2018 年终总结]]></title>
            <link>https://zhengzexin.com/archives/Summary_of_2018/</link>
            <guid>https://zhengzexin.com/archives/Summary_of_2018/</guid>
            <pubDate>Sat, 12 Jan 2019 08:59:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>12月27日 养了5年的垂耳兔“拾三”走了</p>
<p>12月29日 从工作了2年多的公司离职</p>
<p>说是2018年总结，但是由于年底还在忙着离职交接，因此并没有赶在19年前完成，最近去了一趟旅游回来，终于有时间好好总结一下。</p>
<p>2018年，对于我来说，是不一样的一年。由于生活的关系，慢慢地变得成熟，会去思考以后两个人的生活，慢慢地会觉得工作2年以来，自己似乎为了放弃了很多，或者说渐渐地懈怠，不再为以前的目标而努力，只是安逸于每天下班后刷刷剧，然后便休息了。</p>
<p>有时会翻回博客，或者以前自己设定的一些目标，才发现好多都时过境迁，有些目标如今可能已经不再适合，有些目标却还是没有实现，不免心中有些沮丧，同时对突破自我的渴望又强烈了一些。</p>
<h2 id="工作">工作</h2>
<blockquote>
<p><del>孩子，我要求你读书用功，不是因为我要你跟别人比成绩，而是因为，我希望你将来会拥有选择的权利，</del>选择有意义、有时间的工作，而不是被迫谋生。当你的工作在你心中有意义，你就有成就感。当你的工作给你时间，不剥夺你的生活，你就有尊严。成就感和尊严，能给你快乐。</p>
<p>——《亲爱的安德烈》</p>
</blockquote>
<p>我认为从事二代测序、医疗器械行业的同行，都应该抽空阅读一下这篇关于《滴血成金》的推送，<a href="https://zhuanlan.zhihu.com/p/52888244">深度：女版 “乔布斯” 覆灭记！硅谷美女 CEO 被曝百亿美元大骗局 | 远读重洋</a>。里面有很多细节，都可以引以为鉴。</p>
<h2 id="消费">消费</h2>
<p>2018年的消费，除了一些依旧的订阅服务，还多了一些家庭感觉的物件。</p>
<ul>
<li>买了任天堂Switch，和女友一起玩马车8、分手厨房1、2</li>
<li>入手飞利浦吸尘器（因为猫）</li>
<li>富士拍立得 Mini9，居家、旅游都能拍上一张，立马就能看到相片，给生活带来惊喜</li>
</ul>
<p><img src="https://zhengzexin.com/archives/Summary_of_2018/images/2019-02-08-IMG_2397.png" alt="图1. Bobby 的订阅统计!"></p>
<p>订阅服务方面，2018年网络阅读的习惯逐渐从 RSS 订阅转向微信公众号，而书本则是实体书和电子书并存；另外今年入了京东 Plus 会员以及 setapp 家庭计划。</p>
<h2 id="输出">输出</h2>
<p>今年博客只更新了2篇文章，其实相当于也是没有更新，即便如此，博客还是不断有新访客；相较于17年，其实内心是知道现状的，也想要去做。</p>
<p><img src="https://zhengzexin.com/archives/Summary_of_2018/images/2019-02-08-%E4%B8%8B%E8%BD%BD_-7-.png" alt="图2. Google Analytics 的统计"></p>
<h2 id="生活">生活</h2>
<p>12月27日时，拾三突然离去了，很后悔平时没有好好照顾兔子，平时生活得最近的家人，其实也经常忽略。送去宠物医院时，医生也说，要是前两天送来检查就好，但是也没有征兆，无法预料到情况会如此严重。希望它能在兔星球幸福生活。</p>
<p><img src="https://zhengzexin.com/archives/Summary_of_2018/images/2019-02-08-IMG_1534.png" alt="图3. 8月份时给兔子拍的照片"></p>
<p>今年3月份，和女友一起领养了一只小奶牛猫，是个女生，给它取名“小脑斧”。这个家伙是个拖把精，整天把自己搞得脏兮兮；到处乱窜，我工作时经常躺倒在我电脑上，让人哭笑不得。</p>
<p><img src="https://zhengzexin.com/archives/Summary_of_2018/images/2019-02-08-IMG_1522.jpg" alt="图4. 小家伙刚来的时候，和兔子的合影">
<img src="https://zhengzexin.com/archives/Summary_of_2018/images/2019-02-08-IMG_2088.jpg" alt="图5. 霸占我的电脑，不让我工作"></p>
<h2 id="2019">2019</h2>
<p>再多一点输出，勤更新博客；对感兴趣的事物，付出努力去学习。</p>
<p>祝大家2019心想事成。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[ANNOVAR (3): 更新 COSMIC 数据库 (v70+)]]></title>
            <link>https://zhengzexin.com/archives/annovar-3-geng-xin-cosmicshu-ju-ku-v70/</link>
            <guid>https://zhengzexin.com/archives/annovar-3-geng-xin-cosmicshu-ju-ku-v70/</guid>
            <pubDate>Sat, 28 Apr 2018 08:52:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>由于 COSMIC 更新了许可限制，因此 ANNOVAR 提供的 COSMIC 数据库注释最后一版是 v70，之后的版本虽然 ANNOVAR 没有提供，但是 Kai Wang 却很贴心地提供了更新的脚本，用户可以根据<a href="http://annovar.openbioinformatics.org/en/latest/user-guide/filter/#cosmic-annotations">文档</a>，自己将 v70之后版本的 COSMIC 转换成 ANNOVAR 的注释数据库。</p>
<h2 id="所需原始数据及程序">所需原始数据及程序</h2>
<p>COSMIC 数据库 V83 后，以下文件可以直接通过官网点击 Data -&gt; Downloads 下载，不需要再使用 SFTP 下载了。</p>
<p><img src="https://zhengzexin.com/archives/annovar-3-geng-xin-cosmicshu-ju-ku-v70/images/15248434546518.jpg" alt=""></p>
<p><img src="https://zhengzexin.com/archives/annovar-3-geng-xin-cosmicshu-ju-ku-v70/images/11.34.16.png" alt=""></p>
<ul>
<li><p>COSMIC的VCF文件，可以分为 Coding Variant 或者 Non Coding Variant 两种，如<code>CosmicCodingMuts.vcf.gz</code>和<code>CosmicNonCodingVariants.vcf.gz</code></p>
</li>
<li><p>COSMIC MutantExport file，也可以分为 Coding Variant 和 Non Coding Variant 两种，如<code>CosmicMutantExport.tsv.gz</code>和<code>CosmicNCV.tsv</code></p>
</li>
<li><p>ANNOVAR的转换脚本，如<a href="http://www.openbioinformatics.org/annovar/download/prepare_annovar_user.pl"><code>prepare_annovar_user.pl</code></a></p>
</li>
<li><p>ANNOVAR数据库的index脚本 Annovar_index.pl (该脚本在官方文档里面是没有的，by 张求学&amp;周在威)</p>
</li>
</ul>
<h2 id="处理过程">处理过程</h2>
<pre><code class="language-shell">prepare_annovar_user.pl -dbtype cosmic CosmicMutantExport.tsv -vcf CosmicCodingMuts.vcf &gt; hg38_cosmic81_coding.txt # 生成 Coding Variant 的注释文件
prepare_annovar_user.pl -dbtype cosmic CosmicNCV.tsv -vcf CosmicNonCodingVariants.vcf &gt; hg38_cosmic81_noncoding.txt # 生成 Non Coding Variant 的注释文件

## 以下步骤是我自行添加的，可以忽略 ##
sort -k1 -V -s -t &#39;    &#39; hg38_cosmic81_coding.txt &gt; hg38_cosmic81_coding.sorted.txt #排序
perl Annovar_index.pl hg38_cosmic81_coding.sorted.txt 1000 #生成index，但其实注释文件很小，也可以不生成
mv hg38_cosmic81_coding.sorted.txt hg38_cosmic81_coding.txt
mv hg38_cosmic81_coding.sorted.txt.idx hg38_cosmic81_coding.txt.idx</code></pre>
<hr>
<h2 id="annovar-原文引用">ANNOVAR 原文引用</h2>
<p>Note that the <code>prepare_annovar_user.pl</code> file can be downloaded from <a href="http://www.openbioinformatics.org/annovar/download/prepare_annovar_user.pl">here</a>. The final result file should contain coding mutations from COSMIC, as well as the number of occurrences in different tumor types (However, note that these include both targeted screen and genome screen. If you only want genome screen, you should use the CosmicGenomeScreensMutantExport.tsv.gz file instead).</p>
<p>Recently, COSMIC changed their data formats so non-coding mutations are no longer in the <code>MutantExport</code> file, so we can no longer calculate their occurrences in various tumors. COSMIC now provides a <code>CosmicNCV.tsv</code> file, but it is not really that informative as the cancer tissue information is missing from this file.</p>
<p>However, as of 2017, in more recent versions of COSMIC, the noncoding variants are now included in <code>CosmicNCV.tsv</code> file, so that we can use this file to annotate noncoding variants. In early 2017, the <code>prepare_annovar_user.pl</code> script was updated to handle noncoding variants in COSMIC. An example is given below for cosmic81:</p>
<pre><code class="language-shell">prepare_annovar_user.pl -dbtype cosmic CosmicMutantExport.tsv -vcf CosmicCodingMuts.vcf &gt; hg38_cosmic81_coding.txt
prepare_annovar.pl -dbtype cosmic CosmicNCV.tsv -vcf CosmicNonCodingVariants.vcf &gt; hg38_cosmic81_noncoding.txt</code></pre>
<p>There should be 2.58M coding and 14.2M noncoding variants, after you run the commands above. Users cannot index the file, but the file size is not too large, and you do not need to use indexing to use ANNOVAR.</p>
<h2 id="reference">Reference</h2>
<ul>
<li><a href="http://annovar.openbioinformatics.org/en/latest/user-guide/filter/#cosmic-annotations">COSMIC annotations</a></li>
<li><a href="https://mp.weixin.qq.com/s?src=3%C3%97tamp=1524843103&amp;ver=1&amp;signature=X22z2y*tjX88rVER4Xflg19Z4agK5jB70OsTuCZAEJFVcUpIqu0mlPpGi-M1FBLadGxERxovSKUb0IEmuccKkQd-7SdeOS5PW1r8vmQYvTjmyOUassM-MFs4inokRf7U48VYLIcz-c2ZSmFrJtFjSmUNlM3H8wpO3wr3c1CujFE=">怎样让Annovar自建数据库运行飞起来（文末有彩蛋）</a></li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[ANNOVAR (2): 关于注释数据库]]></title>
            <link>https://zhengzexin.com/archives/annovar-2-guan-yu-zhu-shi-shu-ju-ku/</link>
            <guid>https://zhengzexin.com/archives/annovar-2-guan-yu-zhu-shi-shu-ju-ku/</guid>
            <pubDate>Sat, 28 Apr 2018 08:17:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>使用 ANNOVAR 来注释基因组中的突变，首先要下载 ANNOVAR 的注释数据库。如果你需要经常地更新注释数据库，又或者你是“不更新会死星人”，想使用最新的数据库，那么这篇文章也许对你有帮助。</p>
<p>除此之外，ANNOVAR 的注释数据库更新一般会改正一些错误，比如17年10月的一次数据库更新，改正了以前长期存在的 Clinvar 数据库中，同一个 SNP 多种 allele 都注释到同一个突变中的问题，因此使用新的数据库有时也是必要的。</p>
<p><img src="https://zhengzexin.com/archives/annovar-2-guan-yu-zhu-shi-shu-ju-ku/images/9.44.38.png" alt=""></p>
<h2 id="如何下载-annovar-注释数据库">如何下载 ANNOVAR 注释数据库</h2>
<p>ANNOVAR 中自带下载注释数据库的程序，使用的方法是：</p>
<p><img src="https://zhengzexin.com/archives/annovar-2-guan-yu-zhu-shi-shu-ju-ku/images/11.17.33.png" alt=""></p>
<ol>
<li>先到<a href="http://annovar.openbioinformatics.org/en/latest/user-guide/download/">Download ANNOVAR</a>查找自己需要的数据库，例如Clinvar，找到最新的<strong>clinvar_20170905</strong></li>
<li>然后使用命令<code>annotate_variation.pl -buildver hg19 -downdb -webfrom annovar clinvar_20170905 humandb/</code></li>
<li>程序会自动下载该数据库以及索引并解压到<strong>humandb</strong>文件夹</li>
</ol>
<p>这样做的好处是 ANNOVAR 会自动将下载好的数据库进行解压，并放到指定的文件夹；但是注释数据库文件的服务器在国外，如果遇到网络不好的情况，经常性地会断开，又要重新下载一遍；并且 ANNOVAR 的程序下载注释数据库是一条命令一个的，十分不方便。</p>
<h2 id="手动下载-annovar-注释数据库">手动下载 ANNOVAR 注释数据库</h2>
<p>前面提到过，ANNOVAR 下载注释数据库的命令是一次一个，非常不友好；而且身处国内，有时网络又不好，可不可以手动批量下载 ANNOVAR 的注释数据库，答案是当然的。</p>
<p>ANNOVAR 可以使用命令<code>annotate_variation.pl -buildver hg19 -downdb -webfrom annovar avdblist humandb/</code>来获得可供下载的注释数据库的清单，运行该命令后我们可以获得名为<code>hg19_avdblist.txt</code>的文件，查看该文件我们可以看见所有 hg19版本的注释数据库。该文件分为3列，分别为数据库文件名称、发布日期以及文件大小。</p>
<p><img src="https://zhengzexin.com/archives/annovar-2-guan-yu-zhu-shi-shu-ju-ku/images/10.04.22.png" alt=""></p>
<p>我们观察 ANNOVAR 下载注释数据库时的log如下</p>
<p><img src="https://zhengzexin.com/archives/annovar-2-guan-yu-zhu-shi-shu-ju-ku/images/10.08.49.png" alt=""></p>
<p>可以看见，ANNOVAR的注释数据库下载地址都是<strong><a href="http://www.openbioinformatics.org/annovar/download/">http://www.openbioinformatics.org/annovar/download/</a></strong>后面接上需要下载的注释数据库名称（在上图所示的<code>hg19_avdblist.txt</code>文件可以获得），之所以需要下载<code>hg19_avdblist.txt</code>文件是因为<code>http://www.openbioinformatics.org/annovar/download/</code>这个地址无法直接 wget 镜像全站。</p>
<p>由此，我们可以使用 wget或 curl 手动下载注释数据库，例如</p>
<pre><code>wget -P humandb/ http://www.openbioinformatics.org/annovar/download/hg19_clinvar_20170905.txt.gz
wget -P humandb/ http://www.openbioinformatics.org/annovar/download/hg19_clinvar_20170905.txt.idx.gz # 别忘记需要下载注释数据库的 Index
cd humandb/
gzip -d hg19_clinvar_20170905.txt.gz # 下载完后需要解压才能使用
gzip -d hg19_clinvar_20170905.txt.idx.gz</code></pre><p>或者直接将需要下载的地址写到一个文件中，然后运行<code>wget -c -i download.txt</code>来批量下载。</p>
<h2 id="订阅-annovar-更新">订阅 ANNOVAR 更新</h2>
<p>ANNOVAR 的注释数据库一般更新得比较慢，而且不定期，如果我们想定期了解 ANNOVAR 注释数据库更新了哪些，甚至是 ANNOVAR 的更新，是不是需要每隔一段时间去查看一次呢？</p>
<p>当然不需要，我们可以使用第三方的服务，只要Kai Wang更新，我们就能收到提醒。</p>
<p><img src="https://zhengzexin.com/archives/annovar-2-guan-yu-zhu-shi-shu-ju-ku/images/10.24.38.png" alt=""></p>
<p>上图我们可以清晰地看到，ANNOVAR 更新了 Clinvar 数据库的注释数据库，从2016年的03月份的版本更新到了17年的10月份的版本，时间跨度这么久，如果人力去监控，肯定费时费力。</p>
<p>但是我们可以使用<a href="https://www.followthatpage.com/">Follow That Page</a>这个服务，注册该网站后，填写需要监控的页面如<code>http://annovar.openbioinformatics.org/en/latest/user-guide/download/</code>（ANNOVAR 的注释数据库页面）以及扫描频率（一天一次足矣），我们就可以接收邮件提醒，及时了解 ANNOVAR 的更新。</p>
<p><img src="https://zhengzexin.com/archives/annovar-2-guan-yu-zhu-shi-shu-ju-ku/images/10.33.49.png" alt=""></p>
<p>Follow That Page 这个服务免费而且非常稳定，我已经使用了这个服务3年多时间，用来追踪 ANNOVAR 的更新也已经1年多，只要 ANNOVAR 更新，我就能收到提醒；而且这个网站同理可以用来追踪其他的网站，比如某些政府网站的政策公布，这种不定期、没有RSS源而又十分重要的资讯，Follow That Page 可谓屡试不爽。</p>
<p><img src="https://zhengzexin.com/archives/annovar-2-guan-yu-zhu-shi-shu-ju-ku/images/8c54eb53d8e5f5eb61a5fc04bf7f8fd_1280_469_false_86.png" alt=""></p>
<h2 id="脚本自动更新">脚本自动更新</h2>
<p>前面我们提到 ANNOVAR 的程序不友好，一次下载一个注释数据库；后面订阅了数据库更新后还是要手动去更新。</p>
<p>为了解决这个问题，我们可以设置一个定时任务，让服务器自动去更新注释数据库了；实现的原理通过比对新旧两者的<code>hg19_avdblist.txt</code>内容，我们能够得到修改的数据库；实现方式类似于Git diff，我是用了 Linux 系统自带的 diff 命令。以下代码仅为演示，请大家根据需求进行优化。</p>
<pre><code>cp hg19_avdblist.txt old_hg19_avdblist.txt #备份旧的数据库列表
annotate_variation.pl -buildver hg19 -downdb -webfrom annovar avdblist ./ #下载新的数据库列表
diff -c old_hg19_avdblist.txt hg19_avdblist.txt \
| grep -E &#39;^\+|^\!&#39; | cut -f1 \
| sed &quot;s/\! /http\:\/\/www\.openbioinformatics\.org\/annovar\/download\//g;s/\+ /http\:\/\/www\.openbioinformatics\.org\/annovar\/download\//g&quot; &gt; download.txt #获取修改过的数据库，写入 download.txt
wget -c -i download.txt #下载数据库</code></pre><p><img src="https://zhengzexin.com/archives/annovar-2-guan-yu-zhu-shi-shu-ju-ku/images/12.10.31.png" alt=""></p>
<p>将以上命令设置为定时执行，就可以自动更新 ANNOVAR 的注释数据库了。</p>
<p>以上内容，如果有误或者有好的 idea，欢迎大家留言，谢谢。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[PyInstaller 打包 python 脚本的一些心得]]></title>
            <link>https://zhengzexin.com/archives/pyinstaller-da-bao-python-jiao-ben-de-yi-xie-xin-de/</link>
            <guid>https://zhengzexin.com/archives/pyinstaller-da-bao-python-jiao-ben-de-yi-xie-xin-de/</guid>
            <pubDate>Tue, 08 Nov 2016 06:01:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>![Pyinstaller][./images/pyinstaller.png]</p>
<p>因为在公司经常要帮同事做一个从excel表格中提取出需要的内容的重复工作，比较繁琐还容易出错；于是就想着要写个程序，但是同事又不可能在电脑上也装上python以及相关的包依赖（别人一看就觉得太麻烦而且太冗余），于是就想着将写好的python脚本打包成exe，直接双击使用，方便快捷。</p>
<p>说干就干，先是花点时间写完了脚本；然后搜索了相关的关键词，找到了py2exe、PyInstaller、cx_Freeze等工具，最后确定使用<a href="http://www.pyinstaller.org/">PyInstaller</a>。</p>
<p>使用PyInstaller有几个原因：</p>
<ul>
<li>PyInstaller现在仍然在更新</li>
<li>PyInstaller使用方法简单，py2exe比较繁琐</li>
<li>PyInstaller网上教程比较多</li>
</ul>
<h2 id="安装pyinstaller">安装PyInstaller</h2>
<p>推荐使用pip安装</p>
<pre><code class="language-bash">pip install pyinstaller -i https://pypi.douban.com/simple</code></pre>
<p>后面加的<code>-i https://pypi.douban.com/simple</code>是使用豆瓣的源镜像，在天朝速度会快很多；如果你担心安全问题或者网速够快，可以不加，使用官方的源。</p>
<p>安装完后，直接</p>
<pre><code class="language-bash">pyinstaller
usage: pyinstaller-script.py [-h] [-v] [-D] [-F] [--specpath DIR] [-n NAME]
                             [-p DIR] [--hidden-import MODULENAME]
                             [--additional-hooks-dir HOOKSPATH]
                             [--runtime-hook RUNTIME_HOOKS]
                             [--exclude-module EXCLUDES] [--key KEY] [-d] [-s]
                             [--noupx] [-c] [-w]
                             [-i &lt;FILE.ico or FILE.exe,ID or FILE.icns&gt;]
                             [--version-file FILE] [-m &lt;FILE or XML&gt;]
                             [-r RESOURCE] [--uac-admin] [--uac-uiaccess]
                             [--win-private-assemblies]
                             [--win-no-prefer-redirects]
                             [--osx-bundle-identifier BUNDLE_IDENTIFIER]
                             [--distpath DIR] [--workpath WORKPATH] [-y]
                             [--upx-dir UPX_DIR] [-a] [--clean]
                             [--log-level LEVEL] [--upx UPX]
                             scriptname [scriptname ...]
pyinstaller-script.py: error: the following arguments are required: scriptname</code></pre>
<p>可以看到PyInstaller的信息，说明安装完成，可以使用了；详细帮助可以<code>pyinstaller -h</code>查看。</p>
<h2 id="使用pyinstaller">使用PyInstaller</h2>
<p>PyInstaller的使用非常简单：</p>
<pre><code># 打包成一个文件
pyinstaller -F test.py
# 打包成文件夹（默认）
pyinstaller test.py</code></pre><p>因为要精简到底，所以我选择打包成一个文件，打包完成后，打开<code>dist</code>文件夹，里面的那个exe文件就是打包好的程序，运行测试一下是否打包成功。</p>
<p>PyInstaller本身也是有很多选项的。这里挑几个主要的说明一下：</p>
<ul>
<li><code>-D, --one-dir</code>打包成一个文件夹，默认</li>
<li><code>-F, --one-file</code>打包成一个exe文件</li>
<li><code>-p DIR, --paths DIR</code>添加路径，一般用来添加程序所用到的包的所在位置</li>
<li><code>-c, --console, --nowindowed</code>提供程序视窗，程序有输入输出的界面，默认</li>
<li><code>-w, --windowed, --noconsole</code>无视窗，程序后台运行</li>
<li><code>-i &lt;FILE.ico or FILE.exe,ID or FILE.icns&gt;, --icon &lt;FILE.ico or FILE.exe,ID or FILE.icns&gt;</code>添加icon图标</li>
</ul>
<h2 id="openpyxl的一个错误">openpyxl的一个错误</h2>
<p>程序打包之后一定要测试一下是否能成功运行，不然会在同事面前出糗，另外还需要用另一台电脑测试一下。</p>
<p>当我试着运行程序时，发生了报错：</p>
<pre><code>Traceback (most recent call last):
  File &quot;test.py&quot;, line 72, in &lt;module&gt;
  File &quot;site-packages\pandas\core\frame.py&quot;, line 1414, in to_excel
  File &quot;site-packages\pandas\io\excel.py&quot;, line 609, in __new__
  File &quot;site-packages\pandas\io\excel.py&quot;, line 59, in get_writer
AttributeError: module &#39;openpyxl&#39; has no attribute &#39;__version__&#39;
Failed to execute script test</code></pre><p>于是就上网查找原因，一开始是去打包生成的<code>build</code>文件夹下面，查看一个名为<code>warntest.txt</code>的文件（这里是warn[yourscriptname].txt），发现有很多module都是miss，没有加载到。</p>
<pre><code>missing module named &#39;win32com.gen_py&#39; - imported by win32com, c:\python35\lib\site-packages\PyInstaller\loader\rthooks\pyi_rth_win32comgenpy.py
missing module named sys.exc_info - imported by sys, openpyxl.reader.excel, win32com.server.dispatcher
missing module named pywintypes.IIDType - imported by pywintypes, win32com.client.dynamic
missing module named win32com.client._get_good_object_ - imported by win32com.client, win32com.client.util
...</code></pre><p>于是就想着会不会是包的路径没有加载，尝试着使用<code>-p path</code>去加载python下面储存package的目录，结果，重新打包一次仍然还是同样的报错。</p>
<p>于是我重新通过<code>AttributeError: module &#39;openpyxl&#39; has no attribute &#39;__version__&#39;</code>去搜索结果，发现有人遇到同样的bug，原因是使用了<strong>Pandas</strong>，但是pyinstaller在pandas引用的‘openpyxl’包中，无法读取版本信息。<em>（一般使用Python处理科学数据都会使用到Pandas，我是处理excel文件的脚本，当然会用到openpyxl来读写excel）</em></p>
<p>解决的办法是在PyInstaller的<code>hook</code>文件夹中添加‘openpyxl’的一个读取版本信息的hook。这个hook文件是在PyInstaller的<a href="https://github.com/pyinstaller/pyinstaller/pull/2066">Github issue</a>上找到的。于是添加了这个hook，再重新打包，然后运行测试，终于成功了。</p>
<p>关于前面说到的<code>warn[youscriptname].txt</code>文件，有一种说法是如果你在其中没有找到你所用到的包，那么里面的错误信息一般可以忽略，anyway，我是直接忽略掉的。</p>
<h2 id="添加版本信息">添加版本信息</h2>
<p>辛辛苦苦写了个程序，当然希望给程序签个名；PyInstaller是可以添加你自己的个人版本信息的，详细可以参考<a href="https://mborgerson.com/creating-an-executable-from-a-python-script">《Creating an Executable from a Python Script》</a>，写的非常详细，依照相同的格式修改<code>version.txt</code>即可。但不知什么原因，我试了好几次都没有成功。如果以后找到原因，我再更新这篇文章。</p>
<h2 id="关于32位和64位">关于32位和64位</h2>
<p>这个算是后续剧情了。当把程序发给一位同事时，没想到同事的win系统是32位的，而我一直使用的都是64位的系统和64位的程序，而PyInstaller好像没有能选择生成32位/64位exe的选项；也算是PyInstaller的一个缺点吧。最后我是安装了32位的Python以及依赖的库重新生成32位的exe才解决这个问题；所以以后也许生成32位的程序兼容性更好。</p>
<h2 id="reference">Reference</h2>
<ul>
<li><a href="http://www.pyinstaller.org/">PyInstaller official website</a></li>
<li><a href="http://www.crifan.com/use_pyinstaller_to_package_python_to_single_executable_exe/">【记录】用PyInstaller把Python代码打包成单个独立的exe可执行文件</a></li>
<li><a href="https://mborgerson.com/creating-an-executable-from-a-python-script">Creating an Executable from a Python Script</a></li>
<li><a href="https://github.com/pyinstaller/pyinstaller/pull/2066">Add openpyxl hook</a></li>
<li><a href="https://metac0rtex.com/compiling-python-using-pyinstaller/">COMPILING PYTHON USING PYINSTALLER</a></li>
<li><a href="http://legendtkl.com/2015/11/06/pyinstaller/">pyinstaller简洁教程</a></li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[今天是万圣节]]></title>
            <link>https://zhengzexin.com/archives/jin-tian-shi-wan-sheng-jie/</link>
            <guid>https://zhengzexin.com/archives/jin-tian-shi-wan-sheng-jie/</guid>
            <pubDate>Mon, 31 Oct 2016 07:01:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>今天又是万圣节，今年这个时候Github又将背景调为南瓜色，对比上一年的Commit，今年应该算有所进步吧。</p>
<p><img src="https://zhengzexin.com/archives/jin-tian-shi-wan-sheng-jie/images/FireShot_Capture_8.png" alt="16年万圣节"></p>
<p><img src="https://zhengzexin.com/archives/jin-tian-shi-wan-sheng-jie/images/FireShot_Capture_9.png" alt="15年万圣节"></p>
<p>不过话说今年的Google万圣节的Doodle还挺好玩的！！！有兴趣的朋友可以点击图片进去玩玩这个游戏！
<a href="https://www.google.com/doodles/halloween-2016"><img src="https://zhengzexin.com/archives/jin-tian-shi-wan-sheng-jie/images/halloween-2016-5643419163557888-hp2x.gif" alt=""></a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[用 youtube-dl 下载油管视频]]></title>
            <link>https://zhengzexin.com/archives/yong-youtube-dl-xia-zai-you-guan-shi-pin/</link>
            <guid>https://zhengzexin.com/archives/yong-youtube-dl-xia-zai-you-guan-shi-pin/</guid>
            <pubDate>Sat, 17 Sep 2016 03:23:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>最近在上油管看各类视频，因为有些视频不错，而网络条件又不是每时每刻都那么好。所以就想趁着在网络好的地方，先离线好油管的视频，那走到哪还是能接着看啦。</p>
<p>说干就干，立马就Google，虽然找到类似<code>4K Video Downloader</code>这种比较傻瓜式的软件，但是不知为啥，使用<code>proxifier</code>设置它走代理还是下载不动；有的人说，直接用<code>IDM</code>下载就可以啦，但是我的<code>IDM</code>设置代理不知道为啥也不成功，无奈之下，只好找其他方法了；又尝试过直接使用网上那些转换油管视频的网站，例如<a href="http://www.clipconverter.cc">clipconverter</a>，网站本身是十分好的，奈何直接在浏览器下载速度还是太慢了。</p>
<p>虽然尝试了那么多都失败了，但是技术改变生活，幸好我尝试了<code>Youtube-dl</code>，本来以为<code>Youtube-dl</code>很难布置，但是看到了知乎上的一个回答<a href="http://zhihu.com/question/22247271/answer/41909651">《如何下载Youtube的视频》</a>，发现十分简单。于是就自己尝试了一下，请注意，以下布置是于2016年9月17日尝试成功的，<strong>前提是你有一个能上youtube的网络环境，以及Ubuntu操作环境</strong>，如果是Windows，请自行Google在win下的布置方法。</p>
<h2 id="布置ffmpeg--youtube-dl">布置ffmpeg + youtube-dl##</h2>
<p>首先，启动你的Ubuntu系统，或者你可以在你的VPS上操作：
首先安装ffmpeg，打开终端：</p>
<pre><code class="language-bash">sudo apt-get install python-software-properties software-properties-common
sudo apt-add-repository ppa:mc3man/trusty-media
sudo apt-get update
sudo apt-get install ffmpeg gstreamer0.10-ffmpeg</code></pre>
<p>然后安装youtube-dl：</p>
<pre><code class="language-bash">sudo curl -L https://yt-dl.org/downloads/latest/youtube-dl -o /usr/local/bin/youtube-dl
sudo chmod a+rx /usr/local/bin/youtube-dl</code></pre>
<p>这样子就布置成功了，然后是抓取视频：</p>
<pre><code class="language-bash">youtube-dl -F https://www.youtube.com/watch?v=5UB4J_HEHZU #可以是视频链接或者是播放列表链接</code></pre>
<p>返回类似这样的结果，其实是该视频的每种格式的详细情况——</p>
<p><img src="https://zhengzexin.com/archives/yong-youtube-dl-xia-zai-you-guan-shi-pin/images/youtube-dl.png" alt="youtube-dl"></p>
<p>第一列是格式的代号，第二列是文件格式，第三列是音频和视频分辨率等，第四列是视频/音频编码格式及文件大小等详情。</p>
<p>然后我们使用<code>youtube-dl -f</code>下载选中的格式的代号，例如</p>
<pre><code class="language-bash">youtube-dl -f 22 https://www.youtube.com/watch?v=5UB4J_HEHZU #要下载播放列表也是同样，会自动下载列表中所有视频</code></pre>
<h2 id="下载油管字幕">下载油管字幕##</h2>
<p><code>youtube-dl</code>是有字幕选项的，但是博主没有认真去研究过，也许以后有时间，再写一篇详细的youtube-dl的blog，但是有一个网站用来下载油管的字幕还是很方便的，就是<a href="http://downsub.com/">downsub</a>了，直接输入视频链接，然后选择下载的语言。</p>
<hr>
<p>2016.11.20更新
油管下载字幕也非常简单</p>
<pre><code class="language-bash">$ youtube-dl -h
... #直接跳到字幕部分
Subtitle Options:
    --write-sub                      Write subtitle file
    --write-auto-sub                 Write automatically generated subtitle file (YouTube only)
    --all-subs                       Download all the available subtitles of the video
    --list-subs                      List all available subtitles for the video
    --sub-format FORMAT              Subtitle format, accepts formats preference, for example: &quot;srt&quot; or &quot;ass/srt/best&quot;
    --sub-lang LANGS                 Languages of the subtitles to download (optional) separated by commas, use --list-subs for available language tags
... #以下省略非字幕部分</code></pre>
<p>可以看到，youtube-dl是支持字幕下载的，其中：</p>
<ul>
<li><code>write-sub</code> 下载up主自己上传的字幕（非youtube自动生成）</li>
<li><code>write-auto-sub</code> 下载youtube自动生成的字幕</li>
<li><code>all-subs</code> 下载所有字幕（有点夸张，可能用于采集吧）</li>
<li><code>list-subs</code> 列出所有可以下载的字幕，包括语言以及格式</li>
<li><code>sub-format FORMAT</code> 选择下载的字幕格式，如果没有你选定的格式，youtube会选择另外一个格式下载</li>
<li><code>sub-lang LANGS</code> 选择下载字幕的语言</li>
</ul>
<p>所以我们可以看见，本身youtube-dl的字幕下载功能就很强大。我演示一下<code>list-subs</code>以及如何下载一个播放列表并且包括所有视频的英文、中文简体字幕。</p>
<pre><code class="language-bash">$ youtube-dl --list-subs https://www.youtube.com/watch?v=hpb-mH-yjLc&amp;list=PL2mpR0RYFQsBiCWVJSvVAO3OJ2t7DzoHA
#列出所有可供下载的字幕，效果见下图</code></pre>
<p><img src="https://zhengzexin.com/archives/yong-youtube-dl-xia-zai-you-guan-shi-pin/images/youtubedl-subtitle.png" alt=""></p>
<pre><code class="language-bash">$ youtube-dl --write-auto-sub --sub-lang en,zh-Hans --convert-subtitles srt https://www.youtube.com/playlist?list=PL2mpR0RYFQsBiCWVJSvVAO3OJ2t7DzoHA
# 下载播放列表</code></pre>
<h2 id="reference">Reference##</h2>
<ul>
<li><a href="http://zhihu.com/question/22247271/answer/41909651">《如何下载Youtube的视频》</a></li>
<li><a href="http://rg3.github.io/youtube-dl/download.html">youtube-dl download page</a></li>
<li><a href="https://github.com/rg3/youtube-dl">youtube-dl</a></li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[伊恩结]]></title>
            <link>https://zhengzexin.com/archives/yi-en-jie/</link>
            <guid>https://zhengzexin.com/archives/yi-en-jie/</guid>
            <pubDate>Sat, 14 May 2016 21:01:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>受『<a href="http://www.bitvoice.xyz/">比特新声</a>』安利，平日里会时不时地看一下『<a href="http://liqi.io/">利器</a>』，这是『离线』杂志搞的一个网站，一开始是采访优秀的创造者，邀请他们来分享工作时所使用的工具，以及使用工具的方式和原则；然后慢慢丰富到有周报，群分享等内容，可以说是越来越丰富。</p>
<p>今天就给大家安利一发这个『伊恩结』！伊恩结是在『利器』的<a href="http://liqi.io/weekly002/">某一期周报</a>看到的。众所周知，我们现在系鞋带用的最多的应该是蝴蝶结。蝴蝶结其实不算方便，而且容易松开；而这个伊恩结却有着蝴蝶结相似的系法（所以有着相似的外观），而且<del>说不会松开</del>不会比蝴蝶结不容易掉。所以还是有学习的价值的。</p>
<p><img src="https://zhengzexin.com/archives/yi-en-jie/images/05390.gif" alt="伊恩结"></p>
<p>如何系一个“伊恩结”？简单来说，俩手拇指和食指各拿根鞋绳，一边正转，一边反转，然后一系就可以了。</p>
<blockquote>
<p>豆豆 | 程序猿：推荐个系鞋带的方法，好看不松。就比蝴蝶结多绕一次，系出来还是比较美观的，剧烈运动也不会松。</p>
</blockquote>
<p>上图还是看不懂，没关系，很正常，看看分解步骤：</p>
<p><img src="https://zhengzexin.com/archives/yi-en-jie/images/20071126.IanKnot.png" alt="伊恩结分解步骤"></p>
<p>实测效果熟练后确实会比蝴蝶结要快，但是还是有松开的情况。</p>
<h2 id="reference">Reference:</h2>
<ul>
<li><a href="https://www.zhihu.com/question/20093377#answer-700224">如何防止鞋带松掉？|知乎</a></li>
<li><a href="http://www.amio.cn/blog/2007/11/how-to-tie-an-ian-knot/">伊恩结(Ian Knot)</a></li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[annovar 注释软件]]></title>
            <link>https://zhengzexin.com/archives/annovar-zhu-shi-ruan-jian/</link>
            <guid>https://zhengzexin.com/archives/annovar-zhu-shi-ruan-jian/</guid>
            <pubDate>Thu, 28 Apr 2016 00:18:00 GMT</pubDate>
            <content:encoded><![CDATA[<h2 id="annovar简介">ANNOVAR简介</h2>
<p>ANNOVAR是由王凯编写的一个注释软件，可以对SNP和indel进行注释，也可以进行变异的过滤筛选。</p>
<p>ANNOVAR能够利用最新的数据来分析各种基因组中的遗传变异。主要包含三种不同的注释方法，Gene-based Annotation（基于基因的注释）、Region-based Annotation（基于区域的注释）、Filter-based Annotation（基于筛选的注释）。</p>
<p>ANNOVAR由Perl编写。</p>
<p>优点：提供多个数据可直接下载、支持多种格式、注释直观；</p>
<p>缺点：没有数据库的物种无法注释。</p>
<h2 id="annovar结构">ANNOVAR结构</h2>
<pre><code>ANNOVAR
│  annotate_variation.pl #主程序，功能包括下载数据库，三种不同的注释
│  coding_change.pl #可用来推断蛋白质序列
│  convert2annovar.pl #将多种格式转为.avinput的程序
│  retrieve_seq_from_fasta.pl #用于自行建立其他物种的转录本
│  table_annovar.pl #注释程序，可一次性完成三种类型的注释
│  variants_reduction.pl #可用来更灵活地定制过滤注释流程
│
├─example #存放示例文件
│
└─humandb #人类注释数据库</code></pre><h2 id="annovar下载数据库">ANNOVAR下载数据库</h2>
<p>命令示例</p>
<pre><code class="language-sh">[kaiwang@biocluster ~/]$ Perl annotate_variation.pl -buildver hg19 -downdb -webfrom annovar refGene humandb/
# -buildver 表示version
# -downdb 下载数据库的指令
# -webfrom annovar 从annovar提供的镜像下载，不加此参数将寻找数据库本身的源
# humandb/ 存放于humandb/目录下</code></pre>
<p>ANNOVAR的官方文档列出了可供下载的数据库及版本、更新日期等信息，可用<code>-downdb avdblist</code>参数查看。</p>
<p><img src="https://zhengzexin.com/archives/annovar-zhu-shi-ruan-jian/images/NGS%E5%9B%BE%E7%89%871.png" alt="数据库">
<img src="https://zhengzexin.com/archives/annovar-zhu-shi-ruan-jian/images/NGS%E5%9B%BE%E7%89%872.png" alt="数据库目录"></p>
<h2 id="annovar输入格式">ANNOVAR输入格式</h2>
<pre><code class="language-sh">[kaiwang@biocluster ~/]$ cat example/ex1.avinput
1 948921 948921 T C comments: rs15842, a SNP in 5&#39; UTR of ISG15
1 1404001 1404001 G T comments: rs149123833, a SNP in 3&#39; UTR of ATAD3C
1 5935162 5935162 A T comments: rs1287637, a splice site variant in NPHP4
1 162736463 162736463 C T comments: rs1000050, a SNP in Illumina SNP arrays
1 84875173 84875173 C T comments: rs6576700 or SNP_A-1780419, a SNP in Affymetrix SNP arrays
1 13211293 13211294 TC - comments: rs59770105, a 2-bp deletion
1 11403596 11403596 - AT comments: rs35561142, a 2-bp insertion
1 105492231 105492231 A ATAAA comments: rs10552169, a block substitution
1 67705958 67705958 G A comments: rs11209026 (R381Q), a SNP in IL23R associated with Crohn&#39;s disease
2 234183368 234183368 A G comments: rs2241880 (T300A), a SNP in the ATG16L1 associated with Crohn&#39;s disease
16 50745926 50745926 C T comments: rs2066844 (R702W), a non-synonymous SNP in NOD2
16 50756540 50756540 G C comments: rs2066845 (G908R), a non-synonymous SNP in NOD2
16 50763778 50763778 - C comments: rs2066847 (c.3016_3017insC), a frameshift SNP in NOD2
13 20763686 20763686 G - comments: rs1801002 (del35G), a frameshift mutation in GJB2, associated with hearing loss
13 20797176 21105944 0 - comments: a 342kb deletion encompassing GJB6, associated with hearing loss</code></pre>
<p>ANNOVAR使用.avinput格式，如以上代码所示，该格式每列以tab分割，最重要的地方为前5列，分别是</p>
<ol>
<li>染色体(Chromosome)</li>
<li>起始位置(Start)</li>
<li>结束位置(End)</li>
<li>参考等位基因(Reference Allele)</li>
<li>替代等位基因(Alternative Allele)</li>
<li>剩下为注释部分（可选）。</li>
</ol>
<p>ANNOVAR主要也是依靠这5处信息对数据库进行比对，进而注释变异。</p>
<h2 id="annovar格式转换">ANNOVAR格式转换</h2>
<p>命令示例</p>
<pre><code class="language-sh">$ convert2annovar.pl -format vcf4 example/ex2.vcf &gt; ex2.avinput
# -format vcf4 指定格式为vcf</code></pre>
<p>ANNOVAR主要使用<code>convert2annovar.pl</code>程序进行转换，转换后文件是精简过的，主要包含前面提到的5列内容，如果要将原格式的文件的所有内容都包含在转换后的.avinput文件中，可以使用<code>-includeinfo</code>参数；如果需要分开每个sample输出单一的.avinput文件，可以使用<code>-allsample</code>参数，等等。</p>
<p>ANNOVAR还主要支持以下格式转换：</p>
<ul>
<li>SAMtools pileup format</li>
<li>Complete Genomics format</li>
<li>GFF3-SOLiD calling format</li>
<li>SOAPsnp calling format</li>
<li>MAQ calling format</li>
<li>CASAVA calling format</li>
</ul>
<h2 id="annovar注释功能">ANNOVAR注释功能</h2>
<h3 id="用table_annovarpl进行注释（可一次性完成三种类型的注释）">用<code>table_annovar.pl</code>进行注释（可一次性完成三种类型的注释）</h3>
<p>命令示例</p>
<pre><code class="language-sh">[kaiwang@biocluster ~/]$ table_annovar.pl example/ex1.avinput humandb/ -buildver hg19 -out myanno -remove -protocol refGene,cytoBand,genomicSuperDups,esp6500siv2_all,1000g2014oct_all,1000g2014oct_afr,1000g2014oct_eas,1000g2014oct_eur,snp138,ljb26_all -operation g,r,r,f,f,f,f,f,f,f -nastring . -csvout
# -buildver hg19 表示使用hg19版本
# -out myanno 表示输出文件的前缀为myanno
# -remove 表示删除注释过程中的临时文件
# -protocol 表示注释使用的数据库，用逗号隔开，且要注意顺序
# -operation 表示对应顺序的数据库的类型（g代表gene-based、r代表region-based、f代表filter-based），用逗号隔开，注意顺序
# -nastring . 表示用点号替代缺省的值
# -csvout 表示最后输出.csv文件</code></pre>
<p><img src="https://zhengzexin.com/archives/annovar-zhu-shi-ruan-jian/images/NGS%E5%9B%BE%E7%89%873.png" alt=""></p>
<p>输出的csv文件将包含输入的5列主要信息以及各个数据库里的注释，此外，<code>table_annoval.pl</code>可以<strong>直接</strong>对vcf文件进行注释（不需要转换格式），注释的内容将会放在vcf文件的“INFO”那一栏。</p>
<h3 id="gene-based-annotation基于基因的注释">Gene-based Annotation(基于基因的注释)</h3>
<p>基于基因的注释（gene-based annotation）揭示variant与已知基因直接的关系以及对其产生的功能性影响，需要使用<code>for gene-based</code>的数据库。</p>
<p>命令示例</p>
<pre><code class="language-sh">[kaiwang@biocluster ~/]$ annotate_variation.pl -geneanno -dbtype refGene -out ex1 -build hg19 example/ex1.avinput humandb/
# -geneanno  表示使用基于基因的注释
# -dbtype refGene  表示使用&quot;refGene&quot;数据库
# -out ex1  表示输出文件以ex1为前缀</code></pre>
<p>因为<code>annotate_variation.pl</code>默认使用gene-based注释类型以及refGene数据库，所以上面的命令可以缺省<code>-geneanno -dbtype refGene</code>。</p>
<p>运行命令后将会生成3个文件：</p>
<ol>
<li>ex1.variant_function  注释所有变异所在基因及位置</li>
<li>ex1.exonic_variant_function  详细注释外显子区域的变异功能、类型、氨基酸改变等</li>
<li>ex1.ann.log  log文件，包含运行的命令行及运行提示，所用数据库文件</li>
</ol>
<h4 id="ex1variant_function"><code>ex1.variant_function</code></h4>
<p>第一个文件以<code>.variant_function</code>结尾，主要的内容如下</p>
<pre><code class="language-sh">[kaiwang@biocluster ~/]$ cat ex1.variant_function 
UTR5 ISG15(NM_005101:c.-33T&gt;C) 1 948921 948921 T C comments: rs15842, a SNP in 5&#39; UTR of ISG15
UTR3 ATAD3C(NM_001039211:c.*91G&gt;T) 1 1404001 1404001 G T comments: rs149123833, a SNP in 3&#39; UTR of ATAD3C
splicing NPHP4(NM_001291593:exon19:c.1279-2T&gt;A,NM_001291594:exon18:c.1282-2T&gt;A,NM_015102:exon22:c.2818-2T&gt;A) 1 5935162 5935162 A T comments: rs1287637, a splice site variant in NPHP4
intronic DDR2 1 162736463 162736463 C T comments: rs1000050, a SNP in Illumina SNP arrays
intronic DNASE2B 1 84875173 84875173 C T comments: rs6576700 or SNP_A-1780419, a SNP in Affymetrix SNP arrays
intergenic LOC645354(dist=11566),LOC391003(dist=116902) 1 13211293 13211294 TC - comments: rs59770105, a 2-bp deletion
intergenic UBIAD1(dist=55105),PTCHD2(dist=135699) 1 11403596 11403596 - AT comments: rs35561142, a 2-bp insertion
intergenic LOC100129138(dist=872538),NONE(dist=NONE) 1 105492231 105492231 A ATAAA comments: rs10552169, a block substitution
exonic IL23R 1 67705958 67705958 G A comments: rs11209026 (R381Q), a SNP in IL23R associated with Crohn&#39;s disease
exonic ATG16L1 2 234183368 234183368 A G comments: rs2241880 (T300A), a SNP in the ATG16L1 associated with Crohn&#39;s disease
exonic NOD2 16 50745926 50745926 C T comments: rs2066844 (R702W), a non-synonymous SNP in NOD2
exonic NOD2 16 50756540 50756540 G C comments: rs2066845 (G908R), a non-synonymous SNP in NOD2
exonic NOD2 16 50763778 50763778 - C comments: rs2066847 (c.3016_3017insC), a frameshift SNP in NOD2
exonic GJB2 13 20763686 20763686 G - comments: rs1801002 (del35G), a frameshift mutation in GJB2, associated with hearing loss
exonic CRYL1,GJB6 13 20797176 21105944 0 - comments: a 342kb deletion encompassing GJB6, associated with hearing loss</code></pre>
<p>注释后输出的文件，同样每列以tab分割，第1列为变异所在的类型，如外显子（exonic）、UTR5、UTR3等（官方文档有详细的<a href="http://doc-openbio.readthedocs.io/projects/annovar/en/latest/user-guide/gene/#output-file-1-refseq-gene-annotation">类型列表</a>）。</p>
<p>如果第1列的为外显子、内含子或者非编码RNA，第二行将是对应的基因名（有多个基因名则会以逗号隔开）；否则第二列将会给出相邻的两个基因以及对应的距离。</p>
<p>从第3列开始至第7列为输入的那5列主要信息，剩余为注释信息。</p>
<p>需要注意的是，如果该变异找到多种注释，ANNOVAR将会对它进行比较，以exonic = splicing &gt; ncRNA &gt; UTR5/UTR3 &gt; intron &gt; upstream/downstream &gt; intergenic 的优先权重，取最优的表示，如果你想ANNOVAR列出该变异所有注释，可以使用<code>--separate</code>参数。</p>
<h4 id="ex1exonic_variant_function"><code>ex1.exonic_variant_function</code></h4>
<p>第二个输出文件以<code>.exonic_variant_function</code>结尾，只列出外显子（氨基酸会改变）的变异，主要内容如下</p>
<pre><code class="language-sh">[kaiwang@biocluster ~/]$ cat ex1.exonic_variant_function 
line9 nonsynonymous SNV IL23R:NM_144701:exon9:c.G1142A:p.R381Q, 1 67705958 67705958 G A comments: rs11209026 (R381Q), a SNP in IL23R associated with Crohn&#39;s disease
line10 nonsynonymous SNV ATG16L1:NM_001190267:exon9:c.A550G:p.T184A,ATG16L1:NM_017974:exon8:c.A841G:p.T281A,ATG16L1:NM_001190266:exon9:c.A646G:p.T216A,ATG16L1:NM_030803:exon9:c.A898G:p.T300A,ATG16L1:NM_198890:exon5:c.A409G:p.T137A, 2 234183368 234183368 A G comments: rs2241880 (T300A), a SNP in the ATG16L1 associated with Crohn&#39;s disease
line11 nonsynonymous SNV NOD2:NM_022162:exon4:c.C2104T:p.R702W,NOD2:NM_001293557:exon3:c.C2023T:p.R675W, 16 50745926 50745926 C comments: rs2066844 (R702W), a non-synonymous SNP in NOD2
line12 nonsynonymous SNV NOD2:NM_022162:exon8:c.G2722C:p.G908R,NOD2:NM_001293557:exon7:c.G2641C:p.G881R, 16 50756540 50756540 G comments: rs2066845 (G908R), a non-synonymous SNP in NOD2
line13 frameshift insertion NOD2:NM_022162:exon11:c.3017dupC:p.A1006fs,NOD2:NM_001293557:exon10:c.2936dupC:p.A979fs, 16 50763778 5076377comments: rs2066847 (c.3016_3017insC), a frameshift SNP in NOD2
line14 frameshift deletion GJB2:NM_004004:exon2:c.35delG:p.G12fs, 13 20763686 20763686 G - comments: rs1801002 (del35G), a frameshift mutation in GJB2, associated with hearing loss
line15 frameshift deletion GJB6:NM_001110221:wholegene,GJB6:NM_001110220:wholegene,GJB6:NM_001110219:wholegene,CRYL1:NM_015974:wholegene,GJB6:NM_006783:wholegene, 13 20797176 21105944 0 - comments: a 342kb deletion encompassing GJB6, associated with hearing loss</code></pre>
<p>该文件的第1列为<code>.variant_function</code>文件中该变异所在的行号；第2列为该变异的功能性后果，如非同义SNV、同义SNV、移码插入等（官方文档同样有详细的<a href="http://doc-openbio.readthedocs.io/projects/annovar/en/latest/user-guide/gene/#output-file-2-refseq-gene-annotation">类型列表</a>）；第3列包括基因名称、转录识别标志和相应的转录本的序列变化。第四列开始为输入文件的内容。</p>
<h3 id="region-based-annotation（基于区域的注释）">Region-based Annotation（基于区域的注释）</h3>
<p>基于过滤的注释精确匹配查询变异与数据库中的记录：如果它们有相同的染色体，起始位置，结束位置，REF的等位基因和ALT的等位基因，才能认为匹配。基于区域的注释看起来更像一个区域的查询（这个区域也可以是一个单一的位点），在一个数据库中，它不在乎位置的精确匹配，它不在乎核苷酸的识别。</p>
<p>基于区域的注释（region-based annotation）揭示variant与不同基因组特定段的关系，例如：它是否落在已知的保守基因组区域。基于区域的注释的数据库一般由UCSC提供。</p>
<p>命令示例</p>
<pre><code class="language-sh">[kaiwang@biocluster ~/]$ annotate_variation.pl -regionanno -build hg19 -out ex1 -dbtype phastConsElements46way example/ex1.avinput humandb/
# -regionanno 表示使用基于区域的注释
# -dbtype phastConsElements46way 表示使用&quot;phastConsElements46way&quot;数据库，注意需要使用Region-based的数据库</code></pre>
<p>输出文件是<code>ex1.hg19_phastConsElements46way</code>，可以看到，Region-based 注释将会生成以注释数据库为后缀的注释文件。该文件主要内容有</p>
<pre><code class="language-sh">[kaiwang@biocluster ~/]$ cat ex1.hg19_phastConsElements46way
phastConsElements46way Score=387;Name=lod=50 1 67705958 67705958 G A comments: rs11209026 (R381Q), a SNP in IL23R associated with Crohn&#39;s disease
phastConsElements46way Score=420;Name=lod=68 16 50756540 50756540 G C comments: rs2066845 (G908R), a non-synonymous SNP in NOD2
phastConsElements46way Score=385;Name=lod=49 16 50763778 50763778 - C comments: rs2066847 (c.3016_3017insC), a frameshift SNP in NOD2
phastConsElements46way Score=395;Name=lod=54 13 20763686 20763686 G - comments: rs1801002 (del35G), a frameshift mutation in GJB2, associated with hearing loss
phastConsElements46way Score=545;Name=lod=218 13 20797176 21105944 0 - comments: a 342kb deletion encompassing GJB6, associated with hearing loss</code></pre>
<p>输出的注释文件第1列为“phastConsElements46way”，对应注释的类型，这里的phastCons 46-way alignments属于保守的基因组区域的注释；第二列包含评分和名称，评分来自UCSC，可以使用<code>--score_threshold</code>和<code>--normscore_threshold</code>来过滤评分低的变异，“Name=lod=x”名称表示该区域的名称；剩余的部分为输入文件的内容。</p>
<h3 id="filter-based-annotation（基于过滤的注释）">Filter-based Annotation（基于过滤的注释）</h3>
<p>filter-based和region-based主要的区别是，filter-based针对mutation（核苷酸的变化）而region-based针对染色体上的位置。例如region-based比对chr1:1000-1000而filter-based比对chr1:1000-1000上的A-&gt;G。</p>
<p>基于过滤的注释，使用不同的过滤数据库，可以给出这个variant的一系列信息。如在全基因组数据中的变异频率，可使用1000g2015aug、kaviar_20150923等数据库；在全外显组数据中的变异频率，可使用exac03、esp6500siv2等；在孤立的或者低代表人群中的变异频率，可使用ajews等数据库。（在ANNOVAR官方文档中也有<a href="http://doc-openbio.readthedocs.io/projects/annovar/en/latest/user-guide/filter/#summary-of-databases">详细的介绍</a>）</p>
<p>命令示例</p>
<pre><code>[kaiwang@biocluster ~/]$ annotate_variation.pl -filter -dbtype 1000g2012apr_eur -buildver hg19 -out ex1 example/ex1.avinput humandb/
# -filter 使用基于过滤的注释
# -dbtype 1000g2012apr_eur 使用&quot;1000g2012apr_eur&quot;数据库</code></pre><p>运行命令后，已知的变异会被写入一个<code>*dropped</code>结尾的文件，而没有在数据库中找到的变异将会被写入<code>*filtered</code>结尾的文件，<code>*dropped</code>文件是我们所需要的结果。这个文件内容如下</p>
<pre><code>[kaiwang@biocluster ~/]$ cat ex1.hg19_EUR.sites.2012_04_dropped
1000g2012apr_eur 0.04 1 1404001 1404001 G T comments: rs149123833, a SNP in 3&#39; UTR of ATAD3C
1000g2012apr_eur 0.87 1 162736463 162736463 C T comments: rs1000050, a SNP in Illumina SNP arrays
1000g2012apr_eur 0.81 1 5935162 5935162 A T comments: rs1287637, a splice site variant in NPHP4
1000g2012apr_eur 0.06 1 67705958 67705958 G A comments: rs11209026 (R381Q), a SNP in IL23R associated with Crohn&#39;s disease
1000g2012apr_eur 0.54 1 84875173 84875173 C T comments: rs6576700 or SNP_A-1780419, a SNP in Affymetrix SNP arrays
1000g2012apr_eur 0.96 1 948921 948921 T C comments: rs15842, a SNP in 5&#39; UTR of ISG15
1000g2012apr_eur 0.05 16 50745926 50745926 C T comments: rs2066844 (R702W), a non-synonymous SNP in NOD2
1000g2012apr_eur 0.01 16 50756540 50756540 G C comments: rs2066845 (G908R), a non-synonymous SNP in NOD2
1000g2012apr_eur 0.01 16 50763778 50763778 - C comments: rs2066847 (c.3016_3017insC), a frameshift SNP in NOD2
1000g2012apr_eur 0.53 2 234183368 234183368 A G comments: rs2241880 (T300A), a SNP in the ATG16L1 associated with Crohn&#39;s disease</code></pre><p><code>*dropped</code>文件第1列如region-based注释的结果一样以数据库命名；第二列为等位基因频率，我们可以用<code>-maf 0.05</code>参数来过滤掉低于0.05的变异，；第三列开始同样是输入文件的内容。</p>
<p>需要注意的是，我们也可以使用<code>-maf 0.05 -reverse</code>过滤掉高于0.05的变异；但是过滤ALT等位基因的频率，我们更提倡使用<code>-score_threshold</code>参数。</p>
<h2 id="annovar其他程序">ANNOVAR其他程序</h2>
<p>ANNOVAR包里还有</p>
<ul>
<li><strong>Variants_Reduction</strong>: prioritizing causal variants</li>
<li><strong>Coding_Change</strong>: Infer mutated protein sequence</li>
<li><strong>Retrieve_Seq_from_FASTA</strong>: Retrieve nucleotide/protein sequences</li>
</ul>
<p>三个程序没有介绍，可以参考官方文档的<a href="http://doc-openbio.readthedocs.io/projects/annovar/en/latest/misc/accessory/">Accessory Programs</a>自行了解。</p>
<h2 id="reference：">Reference：</h2>
<ul>
<li><a href="http://nar.oxfordjournals.org/content/38/16/e164">Wang K, Li M, Hakonarson H. ANNOVAR: Functional annotation of genetic variants from next-generation sequencing data Nucleic Acids Research, 38:e164, 2010</a></li>
<li><a href="http://annovar.openbioinformatics.org/en/latest/">ANNOVAR Documentation</a></li>
<li><a href="http://blog.csdn.net/u013816205/article/details/51262289">annovar对人类基因组和非人类基因组variants注释流程</a></li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Pileup Format 学习笔记]]></title>
            <link>https://zhengzexin.com/archives/pileup-format-xue-xi-bi-ji/</link>
            <guid>https://zhengzexin.com/archives/pileup-format-xue-xi-bi-ji/</guid>
            <pubDate>Sun, 17 Apr 2016 22:25:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>Pileup format is first used by Tony Cox and Zemin Ning at the Sanger Institute. It desribes the base-pair information at each chromosomal position. This format facilitates SNP/indel calling and brief alignment viewing by eyes. </p>
<p>Pileup 格式是桑格中心（Tony Cox and Zemin Ning）提出，描述可用肉眼观察的某一个区域所有reads匹配的情况。</p>
<p>The pileup format has several variants. The default output by SAMtools looks like this:</p>
<pre><code>seq1    272    T    24    ,.$.....,,.,.,...,,,.,..^+.    &lt;&lt;&lt;+;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;=&lt;;&lt;;7&lt;&amp;
seq1    273    T    23    ,.....,,.,.,...,,,.,..A    &lt;&lt;&lt;;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;3&lt;=&lt;&lt;&lt;;&lt;&lt;+
seq1    274    T    23    ,.$....,,.,.,...,,,.,...    7&lt;7;&lt;;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;=&lt;;&lt;;&lt;&lt;6
seq1    275    A    23    ,$....,,.,.,...,,,.,...^l.    &lt;+;9*&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;=&lt;&lt;:;&lt;&lt;&lt;&lt;
seq1    276    G    22    ...T,,.,.,...,,,.,....    33;+&lt;&lt;7=7&lt;&lt;7&lt;&amp;&lt;&lt;1;&lt;&lt;6&lt;
seq1    277    T    22    ....,,.,.,.C.,,,.,..G.    +7&lt;;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&amp;&lt;=&lt;&lt;:;&lt;&lt;&amp;&lt;
seq1    278    G    23    ....,,.,.,...,,,.,....^k.    %38*&lt;&lt;;&lt;7&lt;&lt;7&lt;=&lt;&lt;&lt;;&lt;&lt;&lt;&lt;&lt;
seq1    279    C    23    A..T,,.,.,...,,,.,.....    ;75&amp;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;=&lt;&lt;&lt;9&lt;&lt;:&lt;&lt;</code></pre><p>where each line consists of </p>
<ol>
<li>chromosome,  染色体</li>
<li>1-based coordinate,  染色体上的位置</li>
<li>reference base,  该位点参考序列上的碱基</li>
<li>the number of reads covering the site,  覆盖度（测得reads的数目）</li>
<li>read bases and base qualities.  该位点的每条reads与该位点的匹配方式</li>
<li>mapping quality 匹配质量 (<a href="http://en.wikipedia.org/wiki/Phred_quality_score">Phred quality score</a> from 0 to 93 using <a href="http://en.wikipedia.org/wiki/ASCII">ASCII</a> 33 to 126 (although in raw read data the Phred quality score rarely exceeds 60, higher scores are possible in assemblies or read maps))</li>
</ol>
<h2 id="read-bases-column">read bases column</h2>
<ul>
<li><code>.</code> stands for a match to the reference base on the forward strand 
代表匹配到正链</li>
<li><code>,</code> for a match on the reverse strand 
代表匹配到负链</li>
<li><code>ACGTN</code> for a mismatch on the forward strand 
大写的<code>ACGTN</code>代表与reference的正向链上不同的实际碱基的5种情况</li>
<li><code>acgtn</code> for a mismatch on the reverse strand 
小写的<code>acgtn</code>代表与reference的反向链上不同的实际碱基的5种情况</li>
<li>A pattern <code>\+[0-9]+[ACGTNacgtn]+</code> indicates there is an insertion between this reference position and the next reference position. The length of the insertion is given by the integer in the pattern, followed by the inserted sequence. <ul>
<li><code>seq2 156 A 11  .$......+2AG.+2AG.+2AGGG    &lt;975;:&lt;&lt;&lt;&lt;&lt;</code>中的<code>+2AG</code>有3处，代表有3个read上有<code>AG</code>的2个bp的插入</li>
</ul>
</li>
<li>Similarly, a pattern `-[0-9]+[ACGTNacgtn]+&#39; represents a deletion from the reference. <ul>
<li><code>seq3 200 A 20 ,,,,,..,.-4CACC.-4CACC....,.,,.^~. ==&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;::&lt;;2&lt;&lt;</code>同理，此处的<code>-4CACC</code>有2处，代表有2个read上有<code>CACC</code>的4个bp的缺失</li>
</ul>
</li>
<li>a symbol <code>^</code> marks the start of a read segment which is a contiguous subsequence on the read separated by <code>N/S/H</code> CIGAR operations.<br><code>^</code>代表刚好是read的开头</li>
<li>The ASCII of the character following <code>^</code> minus 33 gives the mapping quality. 
<code>^</code>后面跟着的符号表示比对的质量（ASCII码减33）</li>
<li>A symbol <code>$</code> marks the end of a read segment. 
<code>$</code>代表刚好是read的结尾</li>
</ul>
<h2 id="reference">reference</h2>
<ul>
<li><a href="http://samtools.sourceforge.net/pileup.shtml">Pileup Format | SAMtools</a></li>
<li><a href="https://en.wikipedia.org/wiki/Pileup_format">Pileup format | Wikipedia</a></li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SAM 文件学习笔记]]></title>
            <link>https://zhengzexin.com/archives/sam-wen-jian-xue-xi-bi-ji/</link>
            <guid>https://zhengzexin.com/archives/sam-wen-jian-xue-xi-bi-ji/</guid>
            <pubDate>Sat, 02 Apr 2016 07:28:00 GMT</pubDate>
            <content:encoded><![CDATA[<h2 id="the-sam-format-specification">The SAM Format Specification</h2>
<p>SAM stands for Sequence Alignment/Map format. It is a TAB-delimited text format consisting of a header section, which is optional, and an alignment section. If present, the header must be prior to the alignments. Header lines start with ‘@’, while alignment lines do not. Each alignment line has 11 mandatory fields for essential alignment information such as mapping position, and variable number of optional fields for flexible or aligner specific information.</p>
<h3 id="an-example">An example</h3>
<p><img src="https://zhengzexin.com/archives/sam-wen-jian-xue-xi-bi-ji/images/btp352f1.jpg" alt="示例"></p>
<h3 id="terminologies-and-concepets名词术语和概念">Terminologies and Concepets/名词术语和概念</h3>
<ul>
<li>Template</li>
<li>Segment  </li>
<li>Read  </li>
<li>Linear alignment  线性比对</li>
<li>Chimeric alignment  嵌合比对</li>
<li>Read alignment</li>
<li>Multiple mapping</li>
<li>1-based coordinate system</li>
<li>0-based coordinate system</li>
<li>Phred scale</li>
</ul>
<h3 id="the-header-section头部注释部分">The header section/头部注释部分</h3>
<p>header lines match <code>/^@[A-Z][A-Z](\t[A-Za-z][A-Za-z0-9]:[ -~]+)+$/ or /^@CO\t.*/</code></p>
<h2 id="the-alignment-section比对结果部分">The alignment section/比对结果部分</h2>
<h3 id="mandatory-fields必需字段">mandatory fields/必需字段</h3>
<table>
<thead>
<tr>
<th align="center">Col</th>
<th align="center">Field</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody><tr>
<td align="center">1</td>
<td align="center">QNAME</td>
<td align="left">比对片段的（template）的编号</td>
</tr>
<tr>
<td align="center">2</td>
<td align="center">FLAG</td>
<td align="left">位标识，templatemapping情况的数字表示，每一个数字代表一种比对情况，这里的值是符合情况的数字相加总和</td>
</tr>
<tr>
<td align="center">3</td>
<td align="center">RNAME</td>
<td align="left">参考序列的编号，如果注释中对SQ-SN进行了定义，这里必须和其保持一致，另外对于没有mapping上的序列，这里是‘*’</td>
</tr>
<tr>
<td align="center">4</td>
<td align="center">POS</td>
<td align="left">比对上的位置，注意是从1开始计数，没有比对上，此处为0</td>
</tr>
<tr>
<td align="center">5</td>
<td align="center">MAPQ</td>
<td align="left">MAPpingQualitymapping的质量</td>
</tr>
<tr>
<td align="center">6</td>
<td align="center">CIAGR</td>
<td align="left">简要比对信息表达式（CompactIdiosyncraticGappedAlignmentReport），其以参考序列为基础，使用数字加字母表示比对结果，比如3S6M1P1I4M，前三个碱基被剪切去除了，然后6个比对上了，然后打开了一个缺口，有一个碱基插入，最后是4个比对上了，是按照顺序的</td>
</tr>
<tr>
<td align="center">7</td>
<td align="center">RNEXT</td>
<td align="left">下一个片段比对上的参考序列的编号，没有另外的片段，这里是‘*’，同一个片段，用‘=’</td>
</tr>
<tr>
<td align="center">8</td>
<td align="center">PNEXT</td>
<td align="left">下一个片段比对上的位置，如果不可用，此处为0</td>
</tr>
<tr>
<td align="center">9</td>
<td align="center">TLEN</td>
<td align="left">TemplateLengthTemplate的长度，最左边得为正，最右边的为负，中间的不用定义正负，不分区段（single-segment)的比对上，或者不可用时，此处为0</td>
</tr>
<tr>
<td align="center">10</td>
<td align="center">SEQ</td>
<td align="left">序列片段的序列信息，如果不存储此类信息，此处为’*‘，注意CIGAR中M/I/S/=/X对应数字的和要等于序列长度</td>
</tr>
<tr>
<td align="center">11</td>
<td align="center">QUAL</td>
<td align="left">queryQUALity序列的质量信息，格式同FASTQ一样</td>
</tr>
<tr>
<td align="center">12</td>
<td align="center">OPT</td>
<td align="left">可选字段（optionalfields)，格式如：TAG:TYPE:VALUE，其中TAG有两个大写字母组成，每个TAG代表一类信息，每一行一个TAG只能出现一次，TYPE表示TAG对应值的类型，可以是字符串、整数、字节、数组等</td>
</tr>
</tbody></table>
<ol>
<li>QNAME  (Query template NAME)  <strong><em>string</em></strong>
<code>[!-?A-~]{1,254}</code></li>
<li>FLAG <strong><em>int</em></strong>
<code>[0,216-1]</code></li>
<li>RNAME (Reference sequence NAME of the alignment) <strong><em>string</em></strong>
<code>*|[!-()+-&lt;&gt;-~][!-~]*</code></li>
<li>POS (1-based leftmost mapping POSition of the first matching base. ) <strong><em>int</em></strong>
<code>[0,231-1]</code></li>
<li>MAPQ (MAPping Quality) <strong><em>int</em></strong>
<code>[0,28-1]</code></li>
<li>CIGAR(CIGAR string) <strong><em>string</em></strong>
<code>*|([0-9]+[MIDNSHPX=])+</code></li>
<li>RNEXT( Reference sequence name of the primary alignment of the NEXT read in the template) <strong><em>string</em></strong>
<code>*|=|[!-()+-&lt;&gt;-~][!-~]*</code></li>
<li>PNEXT(Position of the primary alignment of the NEXT read in the template) <strong><em>int</em></strong>
<code>[0,231-1]</code></li>
<li>TLEN(signed observed Template LENgth.) <strong><em>int</em></strong>
<code>[-231+1,231-1]</code></li>
<li>SEQ(segment SEQuence) <strong><em>string</em></strong>
<code>*|[A-Za-z=.]+</code></li>
<li>QUAL(ASCII of base QUALity plus 33 (same as the quality string in the Sanger FASTQ format)) <strong><em>string</em></strong>
<code>[!-~]+</code></li>
</ol>
<h3 id="optional-fields可选字段">optional fields/可选字段</h3>
<p>All optional fields follow the <strong>TAG:TYPE:VALUE</strong> format where TAG is a two-character string that matches
<code>/[A-Za-z][A-Za-z0-9]/</code>. Each TAG can only appear once in one alignment line. A TAG containing lowercase
letters are reserved for end users. In an optional field, TYPE is a single case-sensitive letter which defines the
format of VALUE:</p>
<h2 id="参考：">参考：</h2>
<ul>
<li><a href="https://samtools.github.io/hts-specs/SAMv1.pdf">Sequence Alignment/Map Format Specification</a></li>
<li>==<a href="http://boyun.sh.cn/bio/?p=1890">SAM格式定义</a>==</li>
<li><a href="http://www.plob.org/2013/06/03/5870.html">SAM格式-Bowtie2（简要介绍）</a></li>
<li><a href="http://www.plob.org/2012/09/02/4540.html">Bowtie2使用方法与参数详细介绍</a></li>
<li><a href="http://blog.qiubio.com:8080/archives/3050">NGS分析入门：操作SAM/BAM文件</a></li>
<li><a href="http://bowtie-bio.sourceforge.net/manual.shtml#sam-bowtie-output">SAM bowtie output</a></li>
<li><a href="http://search.cpan.org/~lds/Bio-SamTools/lib/Bio/DB/Sam.pm">Bio::DB::Sam -- Read SAM/BAM database files</a></li>
<li><a href="http://davetang.org/wiki/tiki-index.php?page=SAM">SAM format specification</a></li>
<li><a href="http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2723002/">The Sequence Alignment/Map format and SAMtools</a></li>
<li><a href="http://asia.ensembl.org/common/Help/Glossary?db=core">Glossary</a></li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Github 万圣节彩蛋]]></title>
            <link>https://zhengzexin.com/archives/github-mo-sheng-jie-cai-dan/</link>
            <guid>https://zhengzexin.com/archives/github-mo-sheng-jie-cai-dan/</guid>
            <pubDate>Sat, 31 Oct 2015 02:38:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>今天是万圣节，西方自然很重视，Github也奉上了自己的彩蛋，所有人的Profile页面的Contribution都变成了黄色，也是别有一方风味。</p>
<p><img src="https://zhengzexin.com/archives/github-mo-sheng-jie-cai-dan/images/ryuzheng.jpg" alt=""></p>
]]></content:encoded>
        </item>
    </channel>
</rss>