普通视图

发现新文章,点击刷新页面。
昨天以前郑泽鑫的博客

使用 Github Actions 自动更新 ANNOVAR 的 Clinvar 数据库

2021年6月15日 06:20

前段时间,看到ANNOVAR在文档里更新了一个可以自行更新Clinvar数据库的脚本,ANNOVAR更新Clinvar的频率,一般是半年到一年才更新一次。

ANNOVAR文档

恰好又看到Github新推出了“Flat Data”,就想着是不是能够像Flat Data一样,抓取Clinvar数据库,然后定期更新成ANNOVAR数据库;可惜研究了一圈,Flat Data的示例都是使用JavaScript或者Typescript脚本的。 ​ 此路不通,那就换一条路,使用David Baux的脚本和Github Actions来实现以下目的: ​

  1. 定时从NCBI抓取Clinvar的VCF更新(Github在国外,下载快);
  2. 转换成ANNOVAR的数据库文件(省却下载到服务器再处理的步骤);
  3. 发布到Github repo和打包成release,使用CDN加速下载

正好Clinvar的数据库压缩后的文件为15Mb左右,不会超过大小限制;其他ANNOVAR的数据库,也可以使用相同的实现方法。

建立Github repo

首先我们建立一个repo,如ryuzheng/clinvar_db_for_annovar,主要存放生成的Clinvar数据库文件、release和Github Actions脚本; ​ 然后为了整洁,我另外建立2个repo,分别存放

  1. 需要用到的ANNOVAR脚本,如ryuzheng/ANNOVAR_script,版权问题,设置为私有repo,请自行到ANNOVAR官网下载
    • convert2annovar.pl
    • index_annovar.pl
  2. 修改过的脚本,如ryuzheng/update_annovar_db,修改为下载weekly更新的VCF与其他一些更适合Github Actions的改动,这里不赘述

然后我们通过submodule,将这2个repo与原来的主repo连接起来,

# 进入主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

我们整个目录的结构如图

目录结构

这样做的好处是,

  • 主repo看起来很干净,只存放生成的文件,并且commit的记录也很干净;
  • 后期如果需要更新代码,我们只需要单独修改submodule的链接,submodule项目的其他代码修改不会影响这个项目;
  • 由于部分代码不能公开,submodule可以引入私有repo

编写Github Actions

我们在repo文件夹下建立.github/workflows文件夹,用来存放Github Actions的yml文件,Github会自动识别该文件夹下的yml文件。 ​ 在.github/workflows下新建一个update_clinvar.yml文件,内容如下:

name: Update Clinvar database for ANNOVAR # 设置该action的名称

on:
  schedule:
    - cron: "0 0 */3 * *" # 由于Clinvar一周更新一次,这里设置为每3天一次
  workflow_dispatch: # 用于手动执行

然后我们先建立第一个任务(jobs),将这个任务命名为build,运行我们修改后脚本,将clinvar的VCF文件转换成ANNOVAR的数据库,并上传结果到artifacts,用于下一步。

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        genome: ["hg19", "hg38"] # 设置一个matrix,分别为hg19和hg38 2个基因组版本的任务

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

      - 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 == 'hg19'
        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 == 'hg38'
        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 }}

然后我们建立第二个任务,将这个任务命名为release,用于当clinvar更新时,存放我们更新后的文件,以及打包成release发布。

  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: "hg19"
          path: ./Clinvar_build/hg19

      - name: Download artifacts for GRCh38 # 将hg38的artifact下载到指定路径
        uses: actions/download-artifact@v2
        with:
          name: "hg38"
          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 "::set-output name=date::$(date +'%Y-%m-%d')"

      - name: Create Github Release # 只有新的commit,才打包发布新版本
        if: steps.auto-commit-action.outputs.changes_detected == 'true'
        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 == 'true'
        uses: csexton/release-asset-action@v2
        with:
          pattern: "Clinvar_build/*/*.gz"
          github-token: ${{ secrets.GH_TOKEN }}
          release-url: ${{ steps.create_release.outputs.upload_url }}

完整的yml文件请查看update_clinvar.yml。 ​

配置Github token

​ 在上一步的yml文件里,相信大家多次看到类似github_token: ${{ secrets.GH_TOKEN }}这样的配置,这是因为Github在执行诸如commit、checkout、push等git操作时,都需要权限,因此我们需要配置一个token。而这个token,我们放在secrets里,别人是无法看到的。

打开Personal access tokens,点击右上角的Generate new token,输入一个名字用于识别,然后勾选上repo的框(允许repo的操作,视乎你所需的权限),然后点击Generate token,将生成的token复制好。

Generate new token

再打开你的repo的Settings选项卡,然后选择Secrets该项,点击右上角的New repository secret,填入名称,如GH_TOKEN,这个名称要与yml里的${{ secrets.GH_TOKEN }}相同,然后将刚才复制好的token填入下面的value里。

repository secret

这样我们就配置好了token;如果大家有其他密钥或者需要保密的内容,也可以设置在secrets里。 ​

运行Github Actions

我们点击repo的Actions选项卡进入该repo的Actions,第一次进去,可能会提示Get started with GitHub Actions,我们点击“Skip this and set up a workflow yourself”就行。 ​ 然后我们在All workflows下会看到我们刚才命名为Update Clinvar database for ANNOVAR的action,点击进入,点击右边的run workflow就可以手动执行。

run workflow

如果执行成功,我们可以看到不同的jobs运行结果以及生成的artifacts。

运行结果

CDN加速下载

打开https://github.com/ryuzheng/clinvar_db_for_annovar/releases/latest,就能看到最新的release,我们可以FastGit或者jsDelivr来作为CDN,示例如下

# 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

至此,我们的目的已经达成,如无意外,Github Actions会每3天去抓取Clinvar最新的VCF文件,并转换成ANNOVAR的文件形式。 ​

一个小讨论

ANNOVAR在进行VCF注释之前,需要先对VCF文件进行split以及left-normalization(详见VCF Processing Guide),因为ANNOVAR的注释文件,都是left-normalization的。

VCF文件处理

那么Clinvar的VCF文件,是否需要进行split和left-normalization,然后再转换成ANNOVAR的注释文件?这个问题David Baux也提到了

David Baux

我对Clinvar的VCF文件进行了测试,发现它已经是split和left-normalization的了。由此验证了我以前看过某篇博客,上面说Clinvar的突变描述格式,在基因组注释,是left-normalization,而在cDNA注释和氨基酸注释上,则遵循HGVS的标准。这或许能作为我们处理突变描述格式时的一个参考。 ​ 截止该篇博客发布,这个repo已经运行了将近一个月,目前已经较为稳定,欢迎大家使用。

2020 年终总结

2021年1月1日 00:00

图 1. 南都的记疫

与上述信息同样高度契合的,是微信公号 “小山狗” 1 月 28 日曾发布过的一篇题为 “记录一下首次发现新型冠状病毒的经历” 的文章。作者在留言区自称就职于位于广州黄埔的一家民营企业,文中记录:“2019 年 12 月 26 日刚上班,还是如往常一样先大概浏览一下这一天的 mNGS 病原微生物自动解读结果。意外的是,发现有一个样本报出了敏感病原体 ——SARS 冠状病毒,有几十条的序列,且这个样本只有这么一个有意义的病原体。心头一紧,赶紧后台查看详细的分析数据,发现相似度并不算很高,只有大约 94.5%。为了确认结果的可靠性,开始了详细分析。探索版的分析结果提示这个病原体跟 Bat SARS like coronavirus(蝙蝠类 SARS 冠状病毒)最相似,整体相似度在 87% 左右,而跟 SARS 的相似度是约 81%。”

——《财新 | 独家 | 新冠病毒基因测序溯源:警报是何时拉响的》

今年年初时小山狗的那篇文章在群里转发开来,一方面,我惊讶于他们的速度(24日收到样品,27日口头报告新冠病毒,而到了30日,已经有3家公司报告了这个病毒);另一方面,我对于自己工作于生物这个行业而感到荣幸,虽不如这些大佬那么牛逼,但是无论是从事肿瘤药物检测、遗传病,还是病原体检测等,生物行业对群众都是有用的,而且生物行业的成熟,检测到病毒,短时间内就组装好了病毒序列,分享给全世界(参考科技爱好者周刊(第 139 期):生物学的可怕进展这一期的本周话题),以及后来的检测试剂盒开发,我认为在这一次疫情中,生物行业的反应速度和表现,可以说满分不为过。

工作

有一个之前听说过的故事,最近又听了一次,对我有些触动:

有一个人问一个得道的老和尚:“得道前干啥?”老和尚说:“挑水、扫地、做饭。”这个人又问得道后呢。回答依然是挑水、扫地、做饭。那人又问区别在哪里。老和尚回答说:“不得道前挑水时想着扫地,扫地时想着做饭。现在挑水时想着挑水,扫地时想着扫地,做饭时想着做饭。”

有时候我们工作久了,想达到的目标就多,所以我们工作时就会做着这件事情时就想着下一件,比如做着RNA分析时,就想着要是我去学机器学习,将一些机器学习的方法应用到分析中,是不是能达到更好的效果。

而且我们做生信分析时,有时候就是要等程序运行完,才能得到结果,而等结果这段时间,又想着给自己安排一些其他工作,结果边做着其他工作,边时不时看看程序跑完没有,最后就是三心两意。

所以工作越久,越觉得自己专注力不行,效率下降。看到这个故事之后,我忽然明白,心里装的事情越多,越不可能把当前的事情做好。

学习

今年在看了一些别人的源码后,突然理解一个包/项目应该是怎么写的,感觉Python的水平提高了不少(只是自我感觉良好哈哈哈);然后今年由于项目要用到R,终于在自己默默学习了R很久之后,会写一些R脚本了,果然实践是检验真理的唯一标准。

不过由于搬家后是地铁通勤,所以没有再像以前一样,上班途中看视频学习,略有遗憾。

今年终于报考驾考了,目前进度是科目一。。。

消费

  • 跟着mjj,屯了几台vps,自己搭了TTRSS,非常好用,之前想搞Emby/Jellyfin之类,最终放弃了
  • 给自己换了iPhone 11,给女友换了12
  • 投影仪(女朋友先斩后奏送的礼物)
  • 健身环大冒险、动森,还有疫情在家时,买了很多switch卡带玩,比如巫师3,路易基鬼屋等,强烈推荐鬼屋,女友通关后又将所有宝石收集完
  • 小熊料理锅,自己在家烤肉/烤鱼,搬家后还请爸妈来吃了一顿烤肉,二老也很喜欢这个锅

图 2. 小熊料理锅

输出

我在语雀上建了个“好物分享”的知识库,用来分享自己觉得好的、值得分享的网站、软件等,特别是在分享轻芒杂志的邀请码后,竟然有很多朋友使用了我的邀请链接,所以分享还是有价值的;来年我会继续更新。

今年也参与了思考问题的熊举办的“素材学习分享周刊”小组,贡献了自己的一期,也收获了很多大佬分享的干货。

生活里很多内容都是在工作中学习到的,但由于工作内容保密的原因,之前很多想写的博客都没有动手,拖的时间久了,自然就觉得可写可不写了;但今年把语雀当作自己的wiki后,确实很方便,一些工作上遇到的问题,可以及时地记录下来,由于是私人wiki,也不用像博客一样要原创才行,大胆地摘录下别人的方法就好;而且过一段时间后,如果有价值,还可以修改修改,放到博客上。

图 3. Google Analytics 的统计

今年博客只更新了4篇博客,慢慢地我也不强求自己每年更新多少篇,只希望自己之后有更多有价值的想法和经验可以分享给大家。今年没有参加到farbox 2.0的内测,然后自己抄了spencerwoo的博客,搬到Vercel上用Gridsome来生成。

生活

今年又搬了一次家,年初的时候,由于疫情的关系,所住的城中村管得比较严,想要回去,便要在村口的关卡,找本地房东来签责任书,但我租的是二手房东那种公寓,二手房东也在外省回不来,本地一手房东也不愿意出面来担责,而我当时已经拿着行李回到村口了,那些工作人员根本不理会任何解释,只会机械重复地说,让房东出来接你回去;类似的情形,大家在年初返京的新闻同样可以了解到;

正是这种政策,城中村让我觉得毫无人权,所以今年我搬家的时候,就选择了住宅小区,同时也满足了自己想要一个有飘窗的卧室和屋子有个阳台的心愿。但是房租也涨了2倍,而且物价水平也比以前在城中村里高。

今年由于把mbp拿到公司了,所以就用女友的旧笔记本的内存+SSD,捡垃圾组了一台戴9020m的小主机,加上网卡,花了700块钱左右,装上黑苹果,用起来也很舒服;特别是有时候拿去插在投影仪和电视上,当个没广告的电视盒子,因为小机箱,所以特别轻。

图 4. 刘德华的造型

今年看到了《扫毒2》里刘德华的发型,很喜欢那种辫子发型,突发奇想留了一段时间长头发,留的过程自然度过一段时间的尴尬期。但是最近又剪掉了,当然是因为我不够帅,而且留这种发型的人忽然多了起来,就一点都不个性了。

最后是今年的一点小感悟:

  1. 没有什么是永久的,做好准备,拥抱变化
  2. 适合自己的才是最好的
  3. 勿忘本心

2021

明年的目标,

  • 都买健身环了,当然是减肥、减肥再减肥
  • 早日写出自己想要做的那个软件
  • 顺利拿到驾照

最后,祝大家新年快乐,心想事成!

解包一个 PAR 打包的 perl 程序源码

2020年10月18日 15:00

最近在流程debug时,和同事发现一个perl脚本有问题;然后发现这个perl脚本是别人打包好的,所以看不到源码。我就想把这个perl脚本给解包(不敢称为反编译,因为实际上也没做反编译)了。因为打包perl脚本这事,我以前也做过,所以我觉得应该可行。

如何用PAR来打包perl程序

首先,一般打包perl程序,现在应该是使用PAR::Packer打包perl程序,具体参数参考http://search.cpan.org/~rschupp/PAR-1.015/lib/PAR/Tutorial.pod。打包的命令如下:

pp -g -B -o xxx xxx.pl # -g 生成二进制程序, -B 将各种依赖项打包进去, -o 生成的文件名

解包PAR打包的perl程序

首先运行一次程序,然后在 /tmp/ 目录下,查看是否有 par- 开头的文件夹,PAR打包的程序有个特点,就是会将程序解压到 /tmp 目录下,然后再运行。

tmp目录下的文件

如果有这样子的目录,应该就是PAR打包的了。然后我们使用 unzip -d unarchive xxx,xxx是你的程序的名称,这样子我们就能得到解压的目录。(xxx.zip,语雀对上传文件的后缀有限制,大家自行解压,然后执行exe文件测试)

发现是Bleach加密过的源码

一般解压后我们就能得到脚本的原始.pl 文件,但是这次,我打开 xxx.pl 文件,却只看到一行很奇怪的代码,而文件的大小却很大。这里上传一个xxx.pl给大家玩一下😄️。

$_=<<'';y;\r\n;;d;y; \t;01;;$_=pack'b*',$_;$_=eval;$@&&die$@;$_

是的,整个文件,我wc了一下,足足有2000多行,但是打开来看,却只看到一行代码,这时,我就猜想,这里应该是使用了什么方法来加密的代码,将代码替换成不可见的字符。

于是我使用 cat -vet xxx.pl| less -SN 来查看该文件,发现这个文件只有这种类似与tab的字符,

$_=<<'';y;\r\n;;d;y; \t;01;;$_=pack'b*',$_;$_=eval;$@&&die$@;$_$
^I^I   ^I  ^I$
^I  ^I^I$
^I^I ^I  ^I ^I$

幸运的是,当我将 $_=<<'';y;\r\n;;d;y; \t;01;;$_=pack'b*',$_;$_=eval;$@&&die$@;$_$ 这串字符串拿去google之后,很快发现了A Beginner’s Guide to Compiling Perl Scripts这篇文章,原来这种源码是经过Bleach这种方法加密过的。

当然,这里我还在stackoverflow查到这种方法是如何生效的。

  • $_ = << ''; reads the rest of the file into the accumulator.
  • y;\r\n;;d; strips carriage returns and line feeds.
  • $_ = pack 'b*', $_; converts characters to bits in $_, LSB first.
  • $_ = eval; executes $_ as Perl code.
  • $@ && die $@; $_ handles exceptions and the return code gracefully.

解密Bleach加密的源码

明白是怎么加密之后,我就开始找如何解密的方法,一开始我找到一个unbleach.pl的代码,但是运行了之后,可能是这个代码太老了,并不能解码。

然后我看到How does this obfuscated Perl script work?bleach question,一下子就醒悟过来,上面的原理解释里不是说了吗,用 eval 来执行 $_里的perl代码,那将 eval 修改为 print,就变成了将代码都打印出来😄️。

原来那么简单!

最后我修改文件头一行为

$_=<<'';y;\r\n;;d;y; \t;01;;$_=pack'b*',$_;$_=print;$@&&die$@;$_

然后执行 perl xxx.pl | less -SN,终于看到源码了。

讨论

其实,我在几年前,也做过加密打包perl代码的工作,然后当时就发现,这个打包然并卵。首先会解压到 /tmp 目录下,其次 unzip 一下也能解包,当时我也有看到 PAR::Filter::BleachPAR::Filter::Bytecode 等加密方法,以为加上这个参数应该就可以,但现在发现这种方法还是不安全的。

另外,我看了A Beginner’s Guide to Compiling Perl Scripts里面加上 PAR::Filter::Crypto 的方法,我看到程序要解密加密后的代码,代码必须将密钥也写在代码里,所以应该也是然并卵的。

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 = {
 'second' => 2,
 'first' => 1,
 'third' => 3
 };

最好的方法,还是将perl代码转换为c代码,甚至是c代码的模块的形式,增加反编译的难度。

参考

VPS装机记录(3):任务机器人

2020年6月27日 15:52

VPS基本设置好后,开始想在上面放一些自动化的东西,那么我们就需要一个机器人,设想的目的是,我们在常用的社交软件发送一条命令或者设置好的指令,机器人就会在VPS上自动执行,并返回结果。

这种机器人,最好的示例可以参考湾区日报是如何运作的?湾区日报的第一个 “员工”:Slack/Hubot

但是我们暂时实现不了定制化那么高的任务机器人,刚好我在telegram上看到有一个机器人,也比较简单,那么我们就用它来搭建在telegram上的机器人。效果参考下图:

image.png 

image.png

搭建shell-bot机器人

该机器人的repo在botgram/shell-bot,参照作者给的安装流程

创建机器人帐号

点击此链接与Telegram的BotFather聊天,发送 /newbot 指令,然后依照提示给机器人帐号起名字和账号名,然后获得一串HTTP API的token,如:

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.

安装依赖项

首先,shell-bot是依赖Node.js的,因此先确定你的VPS上安装好了Node.js,使用 npm -v,确认是否已经安装。

然后,如果你是Ubuntu的系统:

sudo apt-get install build-essential git

如果你跟我一样,是CentOS的系统:

sudo yum install make automake gcc gcc-c++ kernel-devel git

安装并运行shell-bot

clone shell-bot的repo,并使用npm安装依赖的包

git clone https://github.com/botgram/shell-bot.git
cd shell-bot
npm install

然后首次运行shell-bot,它会要求你提供token,并且在Telegram的BotFather帐号,会要求你确认是否是你在连接该机器人,最后生成设置文件

node server

当shell-bot运行起来后,在你的telegram,对话你设置好的机器人,如 /help 或者需要执行的命令前加 /run,如 /run uname -a

持久化运行shell-bot

然后我们安装 forever 来持久化运行shell-bot,使用 -g 来全局安装

sudo npm install -g forever

然后在你的 /etc/rc.local 或者开机执行文件里,加入调用的命令,如:

forever start /path/to/shell-bot/server.js

至此,我们的任务机器人就搭建好了,当需要执行某些任务的时候,我们就打开telegram,然后 /run 命令,机器人就会自动帮我们在VPS上执行命令,如果是运行较久的命令,我们则静静等待机器人返回执行结果就好了。该机器人支持的命令,可以使用/help命令,或者在该文件中查看到。

下一篇文章,我会介绍一些服务器监控的APP。


npm install一直报错的解决方法

可能是由于你的Node.js版本太久导致,因此更新Node.js到最新版本,如果你跟我一样是CentOS,需要先更新内核(注意更新内核该操作比较危险,请查清楚后再做,特别是更新后开机项要设置好,不然可能无法开机),然后更新Node.js版本。

更新内核

载入公钥

 rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org

安装ELrepo

yum install https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm # CentOS 7,其他版本不一样

载入 elrepo-kernel 元数据

 yum --disablerepo=\* --enablerepo=elrepo-kernel repolist

更新内核

 yum --disablerepo=\* --enablerepo=elrepo-kernel install  kernel-ml.x86_64  -y

删除旧工具包

yum remove kernel-tools-libs.x86_64 kernel-tools.x86_64  -y

安装新版本工具包

yum --disablerepo=\* --enablerepo=elrepo-kernel install kernel-ml-tools kernel-ml-devel kernel-ml-headers -y

查看内核插入顺序

默认新内核是从头插入,默认启动顺序也是从 0 开始。

grep "^menuentry" /boot/grub2/grub.cfg | cut -d "'" -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)

查看当前实际启动顺序

grub2-editenv list

saved_entry=CentOS Linux (3.10.0-1127.10.1.el7.x86_64) 7 (Core)

设置默认启动

grub2-set-default 'CentOS Linux (5.7.2-1.el7.elrepo.x86_64) 7 (Core)'

重启并检查

reboot
uname -r

更新Node.js

yum remove nodejs npm -y
yum install -y nodejs

Reference

VPS装机记录(2):使用mosh

2020年4月16日 22:43

家里的网络有点差,之前买的VPS,直接连接SSH,输命令时有时卡卡的,于是就想到之前看到过的mosh。引用维基百科的话来介绍一下mosh的特性。

mosh不绑定使用者端的 IP address,这使得使用者从移动网络(像是 3G、4G)与 WiFi 之间切换时,不会造成连线中断。 mosh保持连线开启,当此用者断线时,服务器端只会认定为暂时离线(sleep)让使用者可以稍候连回来。相对的,SSH 因为透过 TCP,在使用者断线时会造成连线中断。 mosh会试着在本地端马上显示使用者所输入的按键,这使得使用者会感觉到更少的延迟。

CentOS安装mosh

CentOS安装mosh比较简单,使用yum install mosh就可以。如果你提示错误,参考Reference里的文章,可能需要先添加源。

另外,如果你之前参考我的文章,服务器的防火墙关闭了多余的端口,那么这时候就要手动打开端口。

因为mosh默认是走UDP协议的,然后默认使用的端口是60000-61000,第一个连接时用的是60000,第二个连接使用的就是60001,以此类推。当然,你也可以手动指定。

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表示未添加成功

使用管理员权限执行上面的命令,打开防火墙的端口就可以了,不要相信网上某些文章,将整个防火墙都关掉那种,简直饮鸩止渴。

Mac使用mosh连接服务器

macOS默认是没有安装mosh的,类似于ssh,我们需要mosh连接,要首先安装好mosh,在mac下直接用brew安装。

brew update # 可以不更新
brew install mosh

如果没有修改过服务器的ssh端口,直接以下命令就可以连接;如果参考我的文章,修改过服务器的ssh默认端口的,参考第二条命令来连接;如果你连防火墙的udp端口也修改了,那么参考第三条命令,指定mosh走的udp端口。

mosh username@server_ip # 默认情况下的命令
mosh username@server_ip --ssh="ssh -p 245" # 修改ssh端口为你设置的端口
mosh username@server_ip -P 60011 # -P 指定mosh走的udp端口,如果你只打开了某个udp端口的话

Win使用mosh连接服务器

Win下我习惯使用Termius来登录mosh连接,当然如果你有其他终端软件也可以,如图将mosh的开关打开,然后填入你自己定义的SSH端口,如2222;填入用户名和密码,保存即可。

后言

mosh有其优点,比如对ssh支持很好,安全性也很好;但是也有一些缺点,比如只能刷新一个屏幕,如果你的运行结果超出一个屏幕,无法滚动看回,只能用less来捕获来看了。

另外,我查看mosh的官网,发现mosh在很多不同的平台,都有支持,所以真的很优秀。

Reference

2019 年终总结

2019年12月31日 18:00

“听到一个段子:2019 年可能会是过去十年里最差的一年,但却是未来十年里最好的一年。” ——美团 王兴

图1. 美团王兴:2019年,是未来十年最好的一年

好像离18年年终总结,才没过几个月的时间,19年就悄然结束了。相比上一年,今年做出了很多第一次的尝试,因此也多了很多跟其他同龄人的交流,收获了不少大家处于相似阶段的体会。

工作

去年年底裸辞,就连社保都断交了,过年后,在面试了好几家公司后,挑选了一个符合自己意愿的offer,继续从事NGS的生物信息学数据分析的工作,不过相比以前,反而专注生物信息学和程序本身,有和团队一起开发生信的软件,也有捡起HTML+CSS+JavaScript来开发工具。

若论影响最大的,莫过于机器学习。以前我对于机器学习只处于稍微读过公众号的阶段,觉得机器学习在目前的生活和工作中用不上,而且深度学习需要的成本也颇高,对于个人,是没有条件去学习或者实践的。机缘巧合的条件下,今年更加深入地了解机器学习,同时由于自己也在学习各种算法,对我造成的震撼还是很大的。我认为机器学习,不需要牵涉到大数据那么高的层面,反而是一类新的算法,用于辅助人们在有限的成本下,找到近似最优解。

学习

今年,给自己定了许多学习计划,有一些还未完成;有成就感的是,将北京大学的《生物信息学导论》重新刷了一遍。在我刚毕业那会,其实就看过一次,但是当时刚入行,里面有很多不会用到的、太过深奥的,自己就跳过了,所以今年才要求自己完完全全重新学习一遍。我是在Coursera上学习的,在ipad上缓存好,然后就在通勤的时间里一点一点看完。

图2. 北京大学-生物信息学导论

消费

2019年的消费,依旧是一些订阅服务,费用与去年差不多。强力推荐Office 365的订阅,1T的Onedrive存储,真的很好用!

图3. Bobby 的订阅统计

  • 终于购入了年轻人的第一台macbook pro,生产力,不需要解释;
  • iPad Pro 10.5寸 + Apple Pencil,我在通勤路上,看了很多视频教程,也用MarginNote来看文献;
  • 雅马哈 F600,学了一首生日歌唱给女友听,不过目前闲置ing🤦‍♂️

输出

今年博客较去年多更了一些,总共7篇日志,还是不理想。不过今年发的大部分都是较长的一些经验记录,所以也不算水,还要督促自己,有什么好的想法,就要及时记录,不要拖延到忘记。

博客的阅读量相比上年,其实是差不多的;今年尝试过重新用Typecho来搭建博客,感觉还不错;现在则是Github Page + Maverick来生成静态博客,希望来年能多输出有价值的文章给大家。

图4. Google Analytics 的统计

生活

今年搬了一次家,换了一个更好的环境,虽然通勤时间长了些,却也正好我可以沿途听听播客、看看视频。

今年还试过去野餐,铺上一张野餐布,躺在上面吃点心,2个人一起玩switch,原来在大城市里还有那么闲暇的下午时光。

2020

最后,这几天我常常在想, 这个十年只剩下了最后一个月,二十一世纪 10 年代马上就要过去了,这个十年期我到底做了哪些事情,达到了十年前我对自己的期望吗。 ——科技爱好者周刊:第 83 期(20191122)

前几天,在V2EX,看到这篇2010-2020 我错过的黄金十年,如果有什么新兴的事物,你想去做,就抓紧时间去做,10年里新兴的事物太多,你能赶上抓住的太少。

2020年的目标,

  • 用Python写一个包,开源在Github上
  • 从头到尾地看完几本书,并做好笔记
  • 掌握R等语言
  • 养成锻炼的习惯,减掉一身的肥肉

前几天和同事吃饭才说起,以前过年时,试过大年三十晚上出门给我爸找手机充值,那时候还没有支付宝充值这些,大家过年也是互相发短信祝福。其实现在想想,也就是几年前的事,但是智能手机和移动支付的时代来得是如此迅猛;十年后,2029年时我写的年终总结会是什么样。。。。。。

VPS装机记录(1):SSH篇

2019年12月14日 20:07

前段时间趁黑五折扣,买了个小鸡[^1台独立服务器开出来的多台虚拟机,叫作小鸡]来玩,由于是什么都没有的centos系统,因此一切装机都要靠自己来,也顺便记录一下自己的心得。

首先,开启一台VPS后,第一步肯定是登录上去,才能进行后续的操作,而我们的VPS平时放在网上,肯定有一堆无聊的人会去扫端口,密码爆破这种无聊的事情,所以我们第一步是保证服务器的登录安全。

我想要达到的目的是这样的,以下方法均是在centos7上:

  1. 修改SSH默认的22端口
  2. 使用fail2ban去屏蔽多次尝试密码的IP
  3. 禁止root用户直接登录
  4. 使用密码加 Google Authenticator 2步验证进行登录
  5. 或使用有密码的SSH密钥进行登录

1. 修改SSH端口

修改ssh端口需要修改ssh配置、修改firewall配置、修改SElinux配置三个文件,以下均是使用管理员权限执行。

1.1 修改/etc/ssh/sshd_config文件

vi /etc/ssh/sshd_config进入该文件,找到Port 22这一行,然后在下面添加一行如Port 43作为新的端口,注意在确定可以使用新端口登录前,不要注释Port 22这一行,以免无法登录。

1.2 修改firewall配置

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表示未添加成功

1.3 修改SELinux配置

这一步有的VPS可能是关闭SELinux的,就不需要修改;但是默认应该是打开了SELinux的,因此推荐修改。

semanage port -l | grep ssh # 查看当前SELinux允许的ssh端口

如果显示semanage command not found,则

yum provides semanage # 或 yum whatprovides semanage
yum -y install policycoreutils-python # 安装
/usr/sbin/sestatus -v # 查看SELinux状态,enabled即为开启状态

若未开启,则vi /etc/selinux/config,将SELINUX=disabled修改为SELINUX=enforcing,需要重启。

semanage port -a -t ssh_port_t -p tcp 443 # 添加ssh端口
semanage port -l | grep ssh # 再执行一次查看是否添加成功

1.4 重启服务,并测试是否成功

systemctl restart sshd  
systemctl restart firewalld.service  
shutdown -r now # 重启机器,最好重启一下

重启后使用新端口进行ssh登录,测试是否添加成功。

ssh usrname@server -p 43 # 使用-p指定端口

登录成功后vi /etc/ssh/sshd_configPort 22这一行注释,并继续重启服务以生效。

2. 使用fail2ban去屏蔽多次尝试密码的IP

修改默认ssh端口后已经可以防御很多只扫描特定端口的脚本,但是还是有被密码爆破的风险,因此我们安装fail2ban来屏蔽多次尝试密码的坏人。

yum -y install epel-release # CentOS内置源并未包含fail2ban,需要先安装epel源
yum -y install fail2ban # 安装fail2ban

vi /etc/fail2ban/jail.local来新建fail2ban的配置,复制以下配置作为默认规则:

[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

上面的配置为十分钟内,如果连续错误超过5次,就ban掉这个IP。

输入systemctl start fail2ban启动fail2ban。fail2ban-client status sshd显示fail2ban的状态,查看是否有被攻击的记录。

3. 禁止root用户直接登录

前面由于要修改、安装各种服务,因此使用root账户比较方便。但在VPS的实际使用中,首先我们要避免被坏人攻陷,直接root登录;其次我们要避免使用root用户执行危险的操作,发生意外,所以我们禁止root用户直接登录,新建一个拥有sudo权限的用户,平时使用其来登录和执行操作,减低风险。

useradd newone # 新建名为newone的用户
passwd newone # 设置newone的密码

注意!!!该步骤非常重要,否则新用户可能无法登录。输入vi /etc/ssh/sshd_config,使用AllowUsers newone添加可以ssh登录的用户,systemctl restart sshd重启ssh服务。

修改上一步后,保留一个终端窗口,测试新用户是否能成功登录,如果能成功登录,则禁用root用户登录。vi /etc/ssh/sshd_config修改其中PermitRootLogin yesPermitRootLogin nosystemctl restart sshd重启ssh服务。此时root账户已经无法登录。

4. 使用密码加 Google Authenticator 2步验证进行登录

比较安全的SSH登录方式,一种是禁止密码且只允许密钥登录,只要保证密钥的安全,就能保证登录的安全;而另外一种2步验证的方法了。这里我们会用到Google Authentication,其实很多网站/App已经运用到2步验证了。

4.1 安装Google Authenticator

yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
yum install google-authenticator

切换到要使用Google Authenticator的用户,然后输入google-authenticator,屏幕会显示一个超大的二维码,你需要使用支持Google Authenticator的软件,扫描该二维码或者输入“secret key”以生成动态的验证码。

红色方框就是“secret key”,而绿色方框中是临时密码,这几个密码使用一次就会失效;后面的选择可以参考我的设置;另外,Google Authenticator会在当前用户的home目录生成.google_authenticator文件,如果你需要更换,删掉该文件,然后重新生成即可。

4.2 修改配置

修改pam配置文件,vi /etc/pam.d/sshd,在首行加入auth required pam_google_authenticator.so,这样子在输入密码登录之前,会先要求输入Google Authentication的验证码,如果是希望反过来,则将这行代码写入到pam配置文件的最后则可;

修改ssh配置文件,vi /etc/ssh/sshd_configChallengeResponseAuthentication no修改为ChallengeResponseAuthentication yes

检查系统时间,

#查看下服务器时间
date
#如果时区不一样,再使用命令修改为本地时间
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

最后,在保留一个活动的终端窗口的前提下,重启ssh服务,systemctl restart sshd,然后重新登录该用户测试是否成功(登录失败也有可能是因为终端软件的问题,比如,尝试更换软件)。

5. 使用有密码的SSH密钥进行登录

其实,使用密钥进行登录已经算非常安全了,但是为了更加安全,我们还可以给密钥文件添加密码。建议在自己的常用工作电脑上使用密钥登录服务器,而在其他电脑上则保留使用密码登录的方式。

使用密钥登录,我们会生成非对称加密的一对密钥(不清楚非对称加密是什么?看看阮一峰老师的这篇文章),分别称之为“私钥”和“公钥”。如果公钥加密的信息只有私钥才能解开,那么只要私钥不泄露,通信就是安全的。

(1)乙方生成两把密钥(公钥和私钥)。公钥是公开的,任何人都可以获得,私钥则是保密的。

(2)甲方获取乙方的公钥,然后用它对信息加密。

(3)乙方得到加密后的信息,用私钥解密。

而我们使用密钥来进行登录也是这样,将公钥放在远程要登录的服务器上,从远程发送过来的数据,只有我们在本地的私钥才能解读,从而保证两者之间的通信是安全的。

5.1 生成密钥对

在终端输入ssh-keygen来生成密钥,默认会保存在~/.ssh/id_rsa,可以自定义该文件的地址和名称,例如~/.ssh/remote_server。然后会询问是否添加密钥,默认是不设置密码的,这里我输入了设定的密码。然后会生成密钥文件,其中你指定的路径就是私钥文件,而.pub结尾的就是公钥文件。

然后在本地的~/.ssh/config中添加以下代码,用于指定密钥

Host RemoteServer # 随意自己起,但是要用到
    HostName 102.133.250.111 # 修改为服务器的地址,域名或IP
    User newone # 指定登录的用户
    PreferredAuthentications publickey
    IdentityFile ~/.ssh/remote_server # 指定私钥的地址
    Port 43 # 默认端口为22,如果你修改了端口,则修改为对应的端口

5.2 将公钥存放到目标服务器上

打开目标服务器的目标用户的~/.ssh路径,然后将.ssh/remote_server.pub文件的内容复制到~/.ssh/authorized_keys里,如果没有~/.ssh文件夹则参考以下代码,先localhost登录一次。

$ ssh localhost # 输入密码登录
The authenticity of host 'localhost (::1)' can'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 'localhost' (ECDSA) to the list of known hosts.
newone@localhost's password: 
Last login: Sat Dec 14 19:49:07 2019 from localhost
$ exit

登录过后就会生成~/.ssh文件夹了。注意~/.ssh目录权限必须为700,~/.ssh/authorized_keys权限必须为600。

5.3 修改配置文件

又来到熟悉的配置文件,输入vi /etc/ssh/sshd_config,将该文件添加以下3行,如果已有则改成一样的。

RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

然后systemctl restart sshd重启ssh服务。

在本地使用类似ssh newone@RemoteServer的命令进行登录,如果登录成功则说明设置生效了。

至此,我们所希望的5个目标已经完全实现了。

Reference

记录 VEP 关于 COSMIC 注释的一个坑

2019年6月30日 23:22

工作中有用到VEP,确实是一款出色的注释软件。相比ANNOVAR,最大的优点是支持HGVS标准的注释。

可能由于ANNOVAR面世比较早,当时很多变异描述的标准还没有通行,ANNOVAR采取的是按照基因组来left-normalization的方法,而HGVS的标准,则是根据基因/转录本的方向来left-normalization,因此有可能有的基因与ANNOVAR注释的方向相反。在某些地方,如delins的突变,ANNOVAR与VEP的注释也会不相同,当然,我们还是认为两者都是很出色的注释软件。(关于注释软件的比较,可以看看Golden Helix的这篇文章,http://blog.goldenhelix.com/goldenadmin/the-sate-of-variant-annotation-a-comparison-of-annovar-snpeff-and-vep/)

这次,主要是记录一个VEP关于COSMIC注释的坑,避免大家以后踩到。事情的缘由,还是Ryu的一个同事,发现在一个Somatic突变上,VEP注释了多个COSMIC记录,而查证后却发现,很多事不正确的。

比如,我们用编号为COSM476BRAF:V600E来举例:

可见,VEP确实注释了多个COSMIC ID,但只有COSM476才是正确的。What?这是怎么发生的。

于是Ryu就去查VEP的文档,终于被我发现了原因。VEP注释是可以注释COSMIC的记录的,但是这个注释,主要是根据染色体坐标而进行的co-located variants注释,没有判断这个突变是什么碱基变化的。

那么为什么要这么做呢?VEP明显是可以实现分辨碱基突变的功能的。援引VEP的原文,原来Ensembl并没有COSMIC、HGMD等数据库的精细到碱基突变的使用许可协议,因此这些数据能够被注释,但是却是换了一个方法,只能精细到染色体位置的层级。

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.

看到这里,不禁感叹外国人对于版权的意识。在国内,可能COSMIC的注释,分分钟就被人注释上去了,也不会有人追究。其实ANNOVAR的COSMIC注释也止步更新于V70,而现在的COSMIC版本都已经快V90了。

大家以后使用VEP的时候,不要直接使用注释其中的COSMIC记录哦。

记录一次 Name.com 自动续费成功退款的经过

2019年5月4日 23:22

上个月的某天,我收到 Name.com 的邮件提示,告诉我的一个网站自动续费了;之前我已经收到关于这个域名快要到期的邮件了,但是没想到在域名有效期还剩下一个月左右的时候,Name.com 就帮我自动续费了。

本来我是打算在 Name.com 上续费的,因为 Name.com 续费可以使用优惠码进行打折,而且 WHOIS 隐私服务也可以使用优惠码来兑换,算是挺实惠的。

但是没想到 Name.com 抢先在我之前就自动续费了,而且还是按着全额的价格来续费(可以看到,本来 10.99 刀,而现在 12.99+4.99 刀,多花了将近 7 刀)。

于是我想,不能吃了这个哑巴亏呀,我要尝试一下能不能退款。毕竟 7 刀也差不多够我再买一个新的.com 域名了(Name.com COM 注册为 8.99 刀)。于是我到网上 Google,没想到大部分人说的都是,这是不能退款,有的人说这钱是交给注册局的,有的说域名注册能退但续费不能退,也有的说能退款,但是必须删除掉你的域名,这样注册局才能退钱之类云云。但是我也在网上搜到极少数的说成功退款的经历,主要还是域名注册的。

不管怎么说,不试试怎么知道呢,于是我 Google 了一下退款的工单的例子,然后提交了一份工单。一般外国的服务商上班时间都是国内的晚上,所以提交工单之后,就需要耐心地等待那边上班了。

隔了差不多一天,Name.com 给我回复了,

其中有几个需要注意的点,:

  1. 退款需要在交易的 5 天内完成;
  2. 需要删除我的域名;

同时他也提到,需要我回复确认是否删除域名;另外删除后我可以提交退款单,退款就会打到我的邮箱。

这时我就有点懵逼了,真的如网上所说的,需要删掉我的域名才能给我退款?但是邮件里他的表达又有点含糊其辞,没有表达清楚这个删除是什么意思?是向注册局提交我放弃我的域名(我的域名还有 1 个月左右的有效期)?还是在 Name.com 上删除我的域名?于是我给他回了邮件,希望他再次解释清楚,并且询问是否能不删除域名,只是取消续费的操作。

很快又收到 Name.com 工作人员的回复了,这次他的回复再次表达到,如果需要退款,必须先删除掉我的域名。

但是后面的第二段内容则有点意思了,他说到我可以选择转移域名或者将域名留在这里。这是否意味着,我将域名转移走,也属于在 Name.com 删除我的域名的操作?于是我怀着希望,再次给他回复邮件了。

很快,我又收到了回复,

没错,这次他肯定地答复,如果我在自动续费交易发生的 5 天内完成域名的转移,那么将能够退款给我。OK,那么其实这个时候已经距离自动续费的交易过了有 3、4 天了,而我则需要尽快完成域名转移。

这时候就要使用 domcomp 这个神器了,这个网站,可以查询不同后缀的域名,注册、续费、转移的最便宜的价格的域名服务商有哪些。于是我搜索了.com 转移的最便宜的服务商。

没错,我们能看到,.com 最便宜的转移价格在 1&1 这个网站,价格为 1 刀,其实这里可能由于 domcomp 这个网站的数据有些错误,所以 1&1 的转移价格并不是 1 刀,只是新注册.com 的价格为活动价 1 刀。

但是我之前也有域名在 1&1 上面,于是正好,也免得注册别的了,就转移到 1&1 上面吧,这里不得不夸奖 Name.com 的服务,还有 ** 加速转移域名 ** 的按钮,于是很快我的域名就提交了加速转移了。

接着我就直接提交了退款单,等待 Name.com 的退款了,这时还是有点紧张的,因为已经接近 5 天的限期,而且不知道 Name.com 的工作人员上班处理时间是什么时候,也不知道域名是否已经完全转移成功。

接着我就收到与之前几乎一模一样的回复,于是这次我就回复确认删除且退款。

然后,我就收到了确认退款的回复了,大概需要 3-5 天的时间,退款将会退回到我的信用卡。

最后耐心地等待,就收到银行的退款确认了。可以看到,从自动续费到退款,整个事件在 5、6 天左右。最后称赞一下,Name.com 的服务还是很棒的,工单回复也算及时,而且域名服务有免费的 WHOIS 隐私赠送。

macOS Case Sensitive to Case Insensitive(使用 Carbon Copy Cloner)

2019年2月2日 12:33

最近,入手了 MBP 2018,就想着将旧电脑的数据使用“迁移助理”迁移到新 macbook,但是打开迁移助理后却提示由于旧电脑的文件系统格式是“Mac OS 拓展(区分大小写,日志式)”(Case-sensitive, Journaled),而新 macbook 则是默认“Mac OS 拓展(日志式”(without the Case-sensitive),因此不支持数据迁移。

这可难倒我了,旧电脑使用了很久,里面有很多购买的软件,也有很有程序的设置和文件,如果要手动拷贝到新 macbook 上,无疑是很低效,而且效果也不好的。

初步搜索结果

于是我初步 Google 了一下,先是找到了2种方法:

  • 将新 macbook 格盘成大小写敏感重装系统,再数据迁移(缺点是新 macbook 的文件系统格式变成了大小写敏感)
  • 将旧电脑修改所有大小写重名的文件,做一个 TimeMachine,然后旧电脑格盘成大小写不敏感,再使用 TimeMachine 恢复,最后数据迁移(缺点是较繁琐,且旧电脑的数据被格掉,方法来自 https://github.com/cr/MacCaseSensitiveConversion

先说一下2个方法,第一个方法肯定可行,但是 macOS 默认大小写不敏感是有道理的,很多软件默认不支持大小写敏感的文件系统,比如我装 steam 平台时就遇到过。且目前而言,大小写不敏感的文件系统利大于弊,因此我决定使用大小写不敏感的文件系统,第一个方法被否掉。

第二个方法,其实也算比较冒险且繁琐,需要经历查找-重命名-备份-格盘-恢复-迁移的步骤,而且万一格盘后不能恢复(网上曾见过大小写敏感的 TimeMachine 不能被恢复成大小写不敏感),原始文件都没了。如果没有找到第三个方法,那么我可能被迫只能使用第二个方法了。

另外在Google 过程中,找到一个名为“iDefrag”的软件(旧名称为“iPartition”),有人称是可以进行大小写敏感的转换的,遗憾的是,该软件预计在19年7月份才更新到支持 macOS 10.10以上,因此同样放弃。

解决方法

碰巧的是,当我过了几天,再 Google 搜索时,居然找到有人使用 Carbon Copy Cloner 将文件系统转换成大小写不敏感的经历,虽然是16年的帖子,但是有成功的经历,且我自己看了整个流程后,发现不用格盘,因此信心倍增。

流程如下:

  1. 下载 Carbon Copy Cloner(以下简称 CCC),安装,有30天的试用期,因此完全够用了;

  2. 使用 CCC 将 Mac 系统盘备份到一个大小写不敏感的分区(此步我是在旧电脑的硬盘上分出1个足够大小的大小写不敏感分区,读者使用移动硬盘或者足够大小的 U 盘也是可以的) 磁盘工具 Carbon Copy Cloner

  3. 检查备份是否成功,下图可见大小写重名冲突只是少量文件,因此我推测可以成功 Carbon Copy Cloner Carbon Copy Cloner

  4. 挂载备份盘(备份盘分区时命名为 Recovery HD)

  5. 在“系统偏好设置”中,进入“启动磁盘”,并选择Recovery HD,重新启动 系统偏好设置 系统偏好设置

  6. 以 Recovery HD 重启 mac 系统,登录进入(会发现克隆了一个一模一样的环境,CCC 真强大)

  7. 此时我们已经拥有了一个大小写不敏感的 Mac 系统了,启动迁移助理,成功完成数据迁移!(最后需要提醒,使用数据迁移,尽量使用雷电数据线或者网线进行数据传输,速度将会快很多,70G 的数据迁移,WIFI 下需要12h 以上,网线情况下我只使用了约2h)

参考网页

  1. https://discussions.apple.com/thread/7546003
  2. https://forums.macrumors.com/threads/case-sensitive-to-normal.1969880/
  3. macOS 文件系统的大小写敏感转换

ANNOVAR (3): 更新 COSMIC 数据库 (v70+)

2018年4月28日 16:52

由于 COSMIC 更新了许可限制,因此 ANNOVAR 提供的 COSMIC 数据库注释最后一版是 v70,之后的版本虽然 ANNOVAR 没有提供,但是 Kai Wang 却很贴心地提供了更新的脚本,用户可以根据文档,自己将 v70之后版本的 COSMIC 转换成 ANNOVAR 的注释数据库。

所需原始数据及程序

COSMIC 数据库 V83 后,以下文件可以直接通过官网点击 Data -> Downloads 下载,不需要再使用 SFTP 下载了。

  • COSMIC的VCF文件,可以分为 Coding Variant 或者 Non Coding Variant 两种,如CosmicCodingMuts.vcf.gzCosmicNonCodingVariants.vcf.gz

  • COSMIC MutantExport file,也可以分为 Coding Variant 和 Non Coding Variant 两种,如CosmicMutantExport.tsv.gzCosmicNCV.tsv

  • ANNOVAR的转换脚本,如prepare_annovar_user.pl

  • ANNOVAR数据库的index脚本 Annovar_index.pl (该脚本在官方文档里面是没有的,by 张求学&周在威)

处理过程

prepare_annovar_user.pl -dbtype cosmic CosmicMutantExport.tsv -vcf CosmicCodingMuts.vcf > hg38_cosmic81_coding.txt # 生成 Coding Variant 的注释文件
prepare_annovar_user.pl -dbtype cosmic CosmicNCV.tsv -vcf CosmicNonCodingVariants.vcf > hg38_cosmic81_noncoding.txt # 生成 Non Coding Variant 的注释文件

## 以下步骤是我自行添加的,可以忽略 ##
sort -k1 -V -s -t '    ' hg38_cosmic81_coding.txt > 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

ANNOVAR 原文引用

Note that the prepare_annovar_user.pl file can be downloaded from here. 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).

Recently, COSMIC changed their data formats so non-coding mutations are no longer in the MutantExport file, so we can no longer calculate their occurrences in various tumors. COSMIC now provides a CosmicNCV.tsv file, but it is not really that informative as the cancer tissue information is missing from this file.

However, as of 2017, in more recent versions of COSMIC, the noncoding variants are now included in CosmicNCV.tsv file, so that we can use this file to annotate noncoding variants. In early 2017, the prepare_annovar_user.pl script was updated to handle noncoding variants in COSMIC. An example is given below for cosmic81:

prepare_annovar_user.pl -dbtype cosmic CosmicMutantExport.tsv -vcf CosmicCodingMuts.vcf > hg38_cosmic81_coding.txt
prepare_annovar.pl -dbtype cosmic CosmicNCV.tsv -vcf CosmicNonCodingVariants.vcf > hg38_cosmic81_noncoding.txt

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.

Reference

ANNOVAR (2): 关于注释数据库

2018年4月28日 16:17

使用 ANNOVAR 来注释基因组中的突变,首先要下载 ANNOVAR 的注释数据库。如果你需要经常地更新注释数据库,又或者你是“不更新会死星人”,想使用最新的数据库,那么这篇文章也许对你有帮助。

除此之外,ANNOVAR 的注释数据库更新一般会改正一些错误,比如17年10月的一次数据库更新,改正了以前长期存在的 Clinvar 数据库中,同一个 SNP 多种 allele 都注释到同一个突变中的问题,因此使用新的数据库有时也是必要的。

如何下载 ANNOVAR 注释数据库

ANNOVAR 中自带下载注释数据库的程序,使用的方法是:

  1. 先到Download ANNOVAR查找自己需要的数据库,例如Clinvar,找到最新的clinvar_20170905
  2. 然后使用命令annotate_variation.pl -buildver hg19 -downdb -webfrom annovar clinvar_20170905 humandb/
  3. 程序会自动下载该数据库以及索引并解压到humandb文件夹

这样做的好处是 ANNOVAR 会自动将下载好的数据库进行解压,并放到指定的文件夹;但是注释数据库文件的服务器在国外,如果遇到网络不好的情况,经常性地会断开,又要重新下载一遍;并且 ANNOVAR 的程序下载注释数据库是一条命令一个的,十分不方便。

手动下载 ANNOVAR 注释数据库

前面提到过,ANNOVAR 下载注释数据库的命令是一次一个,非常不友好;而且身处国内,有时网络又不好,可不可以手动批量下载 ANNOVAR 的注释数据库,答案是当然的。

ANNOVAR 可以使用命令annotate_variation.pl -buildver hg19 -downdb -webfrom annovar avdblist humandb/来获得可供下载的注释数据库的清单,运行该命令后我们可以获得名为hg19_avdblist.txt的文件,查看该文件我们可以看见所有 hg19版本的注释数据库。该文件分为3列,分别为数据库文件名称、发布日期以及文件大小。

我们观察 ANNOVAR 下载注释数据库时的log如下

可以看见,ANNOVAR的注释数据库下载地址都是http://www.openbioinformatics.org/annovar/download/后面接上需要下载的注释数据库名称(在上图所示的hg19_avdblist.txt文件可以获得),之所以需要下载hg19_avdblist.txt文件是因为http://www.openbioinformatics.org/annovar/download/这个地址无法直接 wget 镜像全站。

由此,我们可以使用 wget或 curl 手动下载注释数据库,例如

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

或者直接将需要下载的地址写到一个文件中,然后运行wget -c -i download.txt来批量下载。

订阅 ANNOVAR 更新

ANNOVAR 的注释数据库一般更新得比较慢,而且不定期,如果我们想定期了解 ANNOVAR 注释数据库更新了哪些,甚至是 ANNOVAR 的更新,是不是需要每隔一段时间去查看一次呢?

当然不需要,我们可以使用第三方的服务,只要Kai Wang更新,我们就能收到提醒。

上图我们可以清晰地看到,ANNOVAR 更新了 Clinvar 数据库的注释数据库,从2016年的03月份的版本更新到了17年的10月份的版本,时间跨度这么久,如果人力去监控,肯定费时费力。

但是我们可以使用Follow That Page这个服务,注册该网站后,填写需要监控的页面如http://annovar.openbioinformatics.org/en/latest/user-guide/download/(ANNOVAR 的注释数据库页面)以及扫描频率(一天一次足矣),我们就可以接收邮件提醒,及时了解 ANNOVAR 的更新。

Follow That Page 这个服务免费而且非常稳定,我已经使用了这个服务3年多时间,用来追踪 ANNOVAR 的更新也已经1年多,只要 ANNOVAR 更新,我就能收到提醒;而且这个网站同理可以用来追踪其他的网站,比如某些政府网站的政策公布,这种不定期、没有RSS源而又十分重要的资讯,Follow That Page 可谓屡试不爽。

脚本自动更新

前面我们提到 ANNOVAR 的程序不友好,一次下载一个注释数据库;后面订阅了数据库更新后还是要手动去更新。

为了解决这个问题,我们可以设置一个定时任务,让服务器自动去更新注释数据库了;实现的原理通过比对新旧两者的hg19_avdblist.txt内容,我们能够得到修改的数据库;实现方式类似于Git diff,我是用了 Linux 系统自带的 diff 命令。以下代码仅为演示,请大家根据需求进行优化。

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 '^\+|^\!' | cut -f1 \
| sed "s/\! /http\:\/\/www\.openbioinformatics\.org\/annovar\/download\//g;s/\+ /http\:\/\/www\.openbioinformatics\.org\/annovar\/download\//g" > download.txt #获取修改过的数据库,写入 download.txt
wget -c -i download.txt #下载数据库

将以上命令设置为定时执行,就可以自动更新 ANNOVAR 的注释数据库了。

以上内容,如果有误或者有好的 idea,欢迎大家留言,谢谢。

用 youtube-dl 下载油管视频

2016年9月17日 11:23

最近在上油管看各类视频,因为有些视频不错,而网络条件又不是每时每刻都那么好。所以就想趁着在网络好的地方,先离线好油管的视频,那走到哪还是能接着看啦。

说干就干,立马就Google,虽然找到类似4K Video Downloader这种比较傻瓜式的软件,但是不知为啥,使用proxifier设置它走代理还是下载不动;有的人说,直接用IDM下载就可以啦,但是我的IDM设置代理不知道为啥也不成功,无奈之下,只好找其他方法了;又尝试过直接使用网上那些转换油管视频的网站,例如clipconverter,网站本身是十分好的,奈何直接在浏览器下载速度还是太慢了。

虽然尝试了那么多都失败了,但是技术改变生活,幸好我尝试了Youtube-dl,本来以为Youtube-dl很难布置,但是看到了知乎上的一个回答《如何下载Youtube的视频》,发现十分简单。于是就自己尝试了一下,请注意,以下布置是于2016年9月17日尝试成功的,前提是你有一个能上youtube的网络环境,以及Ubuntu操作环境,如果是Windows,请自行Google在win下的布置方法。

布置ffmpeg + youtube-dl##

首先,启动你的Ubuntu系统,或者你可以在你的VPS上操作: 首先安装ffmpeg,打开终端:

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

然后安装youtube-dl:

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

这样子就布置成功了,然后是抓取视频:

youtube-dl -F https://www.youtube.com/watch?v=5UB4J_HEHZU #可以是视频链接或者是播放列表链接

返回类似这样的结果,其实是该视频的每种格式的详细情况——

youtube-dl

第一列是格式的代号,第二列是文件格式,第三列是音频和视频分辨率等,第四列是视频/音频编码格式及文件大小等详情。

然后我们使用youtube-dl -f下载选中的格式的代号,例如

youtube-dl -f 22 https://www.youtube.com/watch?v=5UB4J_HEHZU #要下载播放列表也是同样,会自动下载列表中所有视频

下载油管字幕##

youtube-dl是有字幕选项的,但是博主没有认真去研究过,也许以后有时间,再写一篇详细的youtube-dl的blog,但是有一个网站用来下载油管的字幕还是很方便的,就是downsub了,直接输入视频链接,然后选择下载的语言。


2016.11.20更新 油管下载字幕也非常简单

$ 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: "srt" or "ass/srt/best"
    --sub-lang LANGS                 Languages of the subtitles to download (optional) separated by commas, use --list-subs for available language tags
... #以下省略非字幕部分

可以看到,youtube-dl是支持字幕下载的,其中:

  • write-sub 下载up主自己上传的字幕(非youtube自动生成)
  • write-auto-sub 下载youtube自动生成的字幕
  • all-subs 下载所有字幕(有点夸张,可能用于采集吧)
  • list-subs 列出所有可以下载的字幕,包括语言以及格式
  • sub-format FORMAT 选择下载的字幕格式,如果没有你选定的格式,youtube会选择另外一个格式下载
  • sub-lang LANGS 选择下载字幕的语言

所以我们可以看见,本身youtube-dl的字幕下载功能就很强大。我演示一下list-subs以及如何下载一个播放列表并且包括所有视频的英文、中文简体字幕。

$ youtube-dl --list-subs https://www.youtube.com/watch?v=hpb-mH-yjLc&list=PL2mpR0RYFQsBiCWVJSvVAO3OJ2t7DzoHA
#列出所有可供下载的字幕,效果见下图

$ youtube-dl --write-auto-sub --sub-lang en,zh-Hans --convert-subtitles srt https://www.youtube.com/playlist?list=PL2mpR0RYFQsBiCWVJSvVAO3OJ2t7DzoHA
# 下载播放列表

Reference##

伊恩结

2016年5月15日 05:01

受『比特新声』安利,平日里会时不时地看一下『利器』,这是『离线』杂志搞的一个网站,一开始是采访优秀的创造者,邀请他们来分享工作时所使用的工具,以及使用工具的方式和原则;然后慢慢丰富到有周报,群分享等内容,可以说是越来越丰富。

今天就给大家安利一发这个『伊恩结』!伊恩结是在『利器』的某一期周报看到的。众所周知,我们现在系鞋带用的最多的应该是蝴蝶结。蝴蝶结其实不算方便,而且容易松开;而这个伊恩结却有着蝴蝶结相似的系法(所以有着相似的外观),而且说不会松开不会比蝴蝶结不容易掉。所以还是有学习的价值的。

伊恩结

如何系一个“伊恩结”?简单来说,俩手拇指和食指各拿根鞋绳,一边正转,一边反转,然后一系就可以了。

豆豆 | 程序猿:推荐个系鞋带的方法,好看不松。就比蝴蝶结多绕一次,系出来还是比较美观的,剧烈运动也不会松。

上图还是看不懂,没关系,很正常,看看分解步骤:

伊恩结分解步骤

实测效果熟练后确实会比蝴蝶结要快,但是还是有松开的情况。

Reference:

annovar 注释软件

2016年4月28日 08:18

ANNOVAR简介

ANNOVAR是由王凯编写的一个注释软件,可以对SNP和indel进行注释,也可以进行变异的过滤筛选。

ANNOVAR能够利用最新的数据来分析各种基因组中的遗传变异。主要包含三种不同的注释方法,Gene-based Annotation(基于基因的注释)、Region-based Annotation(基于区域的注释)、Filter-based Annotation(基于筛选的注释)。

ANNOVAR由Perl编写。

优点:提供多个数据可直接下载、支持多种格式、注释直观;

缺点:没有数据库的物种无法注释。

ANNOVAR结构

ANNOVAR
│  annotate_variation.pl #主程序,功能包括下载数据库,三种不同的注释
│  coding_change.pl #可用来推断蛋白质序列
│  convert2annovar.pl #将多种格式转为.avinput的程序
│  retrieve_seq_from_fasta.pl #用于自行建立其他物种的转录本
│  table_annovar.pl #注释程序,可一次性完成三种类型的注释
│  variants_reduction.pl #可用来更灵活地定制过滤注释流程
│
├─example #存放示例文件
│
└─humandb #人类注释数据库

ANNOVAR下载数据库

命令示例

[kaiwang@biocluster ~/]$ Perl annotate_variation.pl -buildver hg19 -downdb -webfrom annovar refGene humandb/
# -buildver 表示version
# -downdb 下载数据库的指令
# -webfrom annovar 从annovar提供的镜像下载,不加此参数将寻找数据库本身的源
# humandb/ 存放于humandb/目录下

ANNOVAR的官方文档列出了可供下载的数据库及版本、更新日期等信息,可用-downdb avdblist参数查看。

数据库 数据库目录

ANNOVAR输入格式

[kaiwang@biocluster ~/]$ cat example/ex1.avinput
1 948921 948921 T C comments: rs15842, a SNP in 5' UTR of ISG15
1 1404001 1404001 G T comments: rs149123833, a SNP in 3' 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's disease
2 234183368 234183368 A G comments: rs2241880 (T300A), a SNP in the ATG16L1 associated with Crohn'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

ANNOVAR使用.avinput格式,如以上代码所示,该格式每列以tab分割,最重要的地方为前5列,分别是

  1. 染色体(Chromosome)
  2. 起始位置(Start)
  3. 结束位置(End)
  4. 参考等位基因(Reference Allele)
  5. 替代等位基因(Alternative Allele)
  6. 剩下为注释部分(可选)。

ANNOVAR主要也是依靠这5处信息对数据库进行比对,进而注释变异。

ANNOVAR格式转换

命令示例

$ convert2annovar.pl -format vcf4 example/ex2.vcf > ex2.avinput
# -format vcf4 指定格式为vcf

ANNOVAR主要使用convert2annovar.pl程序进行转换,转换后文件是精简过的,主要包含前面提到的5列内容,如果要将原格式的文件的所有内容都包含在转换后的.avinput文件中,可以使用-includeinfo参数;如果需要分开每个sample输出单一的.avinput文件,可以使用-allsample参数,等等。

ANNOVAR还主要支持以下格式转换:

  • SAMtools pileup format
  • Complete Genomics format
  • GFF3-SOLiD calling format
  • SOAPsnp calling format
  • MAQ calling format
  • CASAVA calling format

ANNOVAR注释功能

table_annovar.pl进行注释(可一次性完成三种类型的注释)

命令示例

[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文件

输出的csv文件将包含输入的5列主要信息以及各个数据库里的注释,此外,table_annoval.pl可以直接对vcf文件进行注释(不需要转换格式),注释的内容将会放在vcf文件的“INFO”那一栏。

Gene-based Annotation(基于基因的注释)

基于基因的注释(gene-based annotation)揭示variant与已知基因直接的关系以及对其产生的功能性影响,需要使用for gene-based的数据库。

命令示例

[kaiwang@biocluster ~/]$ annotate_variation.pl -geneanno -dbtype refGene -out ex1 -build hg19 example/ex1.avinput humandb/
# -geneanno  表示使用基于基因的注释
# -dbtype refGene  表示使用"refGene"数据库
# -out ex1  表示输出文件以ex1为前缀

因为annotate_variation.pl默认使用gene-based注释类型以及refGene数据库,所以上面的命令可以缺省-geneanno -dbtype refGene

运行命令后将会生成3个文件:

  1. ex1.variant_function 注释所有变异所在基因及位置
  2. ex1.exonic_variant_function 详细注释外显子区域的变异功能、类型、氨基酸改变等
  3. ex1.ann.log log文件,包含运行的命令行及运行提示,所用数据库文件

ex1.variant_function

第一个文件以.variant_function结尾,主要的内容如下

[kaiwang@biocluster ~/]$ cat ex1.variant_function 
UTR5 ISG15(NM_005101:c.-33T>C) 1 948921 948921 T C comments: rs15842, a SNP in 5' UTR of ISG15
UTR3 ATAD3C(NM_001039211:c.*91G>T) 1 1404001 1404001 G T comments: rs149123833, a SNP in 3' UTR of ATAD3C
splicing NPHP4(NM_001291593:exon19:c.1279-2T>A,NM_001291594:exon18:c.1282-2T>A,NM_015102:exon22:c.2818-2T>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's disease
exonic ATG16L1 2 234183368 234183368 A G comments: rs2241880 (T300A), a SNP in the ATG16L1 associated with Crohn'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

注释后输出的文件,同样每列以tab分割,第1列为变异所在的类型,如外显子(exonic)、UTR5、UTR3等(官方文档有详细的类型列表)。

如果第1列的为外显子、内含子或者非编码RNA,第二行将是对应的基因名(有多个基因名则会以逗号隔开);否则第二列将会给出相邻的两个基因以及对应的距离。

从第3列开始至第7列为输入的那5列主要信息,剩余为注释信息。

需要注意的是,如果该变异找到多种注释,ANNOVAR将会对它进行比较,以exonic = splicing > ncRNA > UTR5/UTR3 > intron > upstream/downstream > intergenic 的优先权重,取最优的表示,如果你想ANNOVAR列出该变异所有注释,可以使用--separate参数。

ex1.exonic_variant_function

第二个输出文件以.exonic_variant_function结尾,只列出外显子(氨基酸会改变)的变异,主要内容如下

[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'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'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

该文件的第1列为.variant_function文件中该变异所在的行号;第2列为该变异的功能性后果,如非同义SNV、同义SNV、移码插入等(官方文档同样有详细的类型列表);第3列包括基因名称、转录识别标志和相应的转录本的序列变化。第四列开始为输入文件的内容。

Region-based Annotation(基于区域的注释)

基于过滤的注释精确匹配查询变异与数据库中的记录:如果它们有相同的染色体,起始位置,结束位置,REF的等位基因和ALT的等位基因,才能认为匹配。基于区域的注释看起来更像一个区域的查询(这个区域也可以是一个单一的位点),在一个数据库中,它不在乎位置的精确匹配,它不在乎核苷酸的识别。

基于区域的注释(region-based annotation)揭示variant与不同基因组特定段的关系,例如:它是否落在已知的保守基因组区域。基于区域的注释的数据库一般由UCSC提供。

命令示例

[kaiwang@biocluster ~/]$ annotate_variation.pl -regionanno -build hg19 -out ex1 -dbtype phastConsElements46way example/ex1.avinput humandb/
# -regionanno 表示使用基于区域的注释
# -dbtype phastConsElements46way 表示使用"phastConsElements46way"数据库,注意需要使用Region-based的数据库

输出文件是ex1.hg19_phastConsElements46way,可以看到,Region-based 注释将会生成以注释数据库为后缀的注释文件。该文件主要内容有

[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'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

输出的注释文件第1列为“phastConsElements46way”,对应注释的类型,这里的phastCons 46-way alignments属于保守的基因组区域的注释;第二列包含评分和名称,评分来自UCSC,可以使用--score_threshold--normscore_threshold来过滤评分低的变异,“Name=lod=x”名称表示该区域的名称;剩余的部分为输入文件的内容。

Filter-based Annotation(基于过滤的注释)

filter-based和region-based主要的区别是,filter-based针对mutation(核苷酸的变化)而region-based针对染色体上的位置。例如region-based比对chr1:1000-1000而filter-based比对chr1:1000-1000上的A->G。

基于过滤的注释,使用不同的过滤数据库,可以给出这个variant的一系列信息。如在全基因组数据中的变异频率,可使用1000g2015aug、kaviar_20150923等数据库;在全外显组数据中的变异频率,可使用exac03、esp6500siv2等;在孤立的或者低代表人群中的变异频率,可使用ajews等数据库。(在ANNOVAR官方文档中也有详细的介绍

命令示例

[kaiwang@biocluster ~/]$ annotate_variation.pl -filter -dbtype 1000g2012apr_eur -buildver hg19 -out ex1 example/ex1.avinput humandb/
# -filter 使用基于过滤的注释
# -dbtype 1000g2012apr_eur 使用"1000g2012apr_eur"数据库

运行命令后,已知的变异会被写入一个*dropped结尾的文件,而没有在数据库中找到的变异将会被写入*filtered结尾的文件,*dropped文件是我们所需要的结果。这个文件内容如下

[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' 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'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' 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's disease

*dropped文件第1列如region-based注释的结果一样以数据库命名;第二列为等位基因频率,我们可以用-maf 0.05参数来过滤掉低于0.05的变异,;第三列开始同样是输入文件的内容。

需要注意的是,我们也可以使用-maf 0.05 -reverse过滤掉高于0.05的变异;但是过滤ALT等位基因的频率,我们更提倡使用-score_threshold参数。

ANNOVAR其他程序

ANNOVAR包里还有

  • Variants_Reduction: prioritizing causal variants
  • Coding_Change: Infer mutated protein sequence
  • Retrieve_Seq_from_FASTA: Retrieve nucleotide/protein sequences

三个程序没有介绍,可以参考官方文档的Accessory Programs自行了解。

Reference:

Pileup Format 学习笔记

2016年4月18日 06:25

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.

Pileup 格式是桑格中心(Tony Cox and Zemin Ning)提出,描述可用肉眼观察的某一个区域所有reads匹配的情况。

The pileup format has several variants. The default output by SAMtools looks like this:

seq1    272    T    24    ,.$.....,,.,.,...,,,.,..^+.    <<<+;<<<<<<<<<<<=<;<;7<&
seq1    273    T    23    ,.....,,.,.,...,,,.,..A    <<<;<<<<<<<<<3<=<<<;<<+
seq1    274    T    23    ,.$....,,.,.,...,,,.,...    7<7;<;<<<<<<<<<=<;<;<<6
seq1    275    A    23    ,$....,,.,.,...,,,.,...^l.    <+;9*<<<<<<<<<=<<:;<<<<
seq1    276    G    22    ...T,,.,.,...,,,.,....    33;+<<7=7<<7<&<<1;<<6<
seq1    277    T    22    ....,,.,.,.C.,,,.,..G.    +7<;<<<<<<<&<=<<:;<<&<
seq1    278    G    23    ....,,.,.,...,,,.,....^k.    %38*<<;<7<<7<=<<<;<<<<<
seq1    279    C    23    A..T,,.,.,...,,,.,.....    ;75&<<<<<<<<<=<<<9<<:<<

where each line consists of

  1. chromosome, 染色体
  2. 1-based coordinate, 染色体上的位置
  3. reference base, 该位点参考序列上的碱基
  4. the number of reads covering the site, 覆盖度(测得reads的数目)
  5. read bases and base qualities. 该位点的每条reads与该位点的匹配方式
  6. mapping quality 匹配质量 (Phred quality score from 0 to 93 using ASCII 33 to 126 (although in raw read data the Phred quality score rarely exceeds 60, higher scores are possible in assemblies or read maps))

read bases column

  • . stands for a match to the reference base on the forward strand 代表匹配到正链
  • , for a match on the reverse strand 代表匹配到负链
  • ACGTN for a mismatch on the forward strand 大写的ACGTN代表与reference的正向链上不同的实际碱基的5种情况
  • acgtn for a mismatch on the reverse strand 小写的acgtn代表与reference的反向链上不同的实际碱基的5种情况
  • A pattern \+[0-9]+[ACGTNacgtn]+ 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.
    • seq2 156 A 11 .$......+2AG.+2AG.+2AGGG <975;:<<<<<中的+2AG有3处,代表有3个read上有AG的2个bp的插入
  • Similarly, a pattern `-[0-9]+[ACGTNacgtn]+' represents a deletion from the reference.
    • seq3 200 A 20 ,,,,,..,.-4CACC.-4CACC....,.,,.^~. ==<<<<<<<<<<<::<;2<<同理,此处的-4CACC有2处,代表有2个read上有CACC的4个bp的缺失
  • a symbol ^ marks the start of a read segment which is a contiguous subsequence on the read separated by N/S/H CIGAR operations.
    ^代表刚好是read的开头
  • The ASCII of the character following ^ minus 33 gives the mapping quality. ^后面跟着的符号表示比对的质量(ASCII码减33)
  • A symbol $ marks the end of a read segment. $代表刚好是read的结尾

reference

❌
❌