« 好久都没更新过了,惭愧啊! | (回到Blog入口) | W3C认证果然严格啊! »

Perl6与唐宗汉

本文作者:夜猫子 
本来这是段录象的,被作者用笔记的方式写出来了,这样以来就弥补了当时环境的影响而造成的有些话没听清的情况,顺便值得一提的就是最近将在上海开次PERL的聚会,有意的朋友可以到www.perlchina.org
看看
唐个人简历: 
唐宗汉 男 1981年生人 籍贯台湾。 

本文作者:夜猫子
本来这是段录象的,被作者用笔记的方式写出来了,这样以来就弥补了当时环境的影响而造成的有些话没听清的情况,顺便值得一提的就是最近将在上海开次PERL的聚会,有意的朋友可以到www.perlchina.org
看看
唐个人简历:
唐宗汉 男 1981年生人 籍贯台湾。
唐的外表:长发,面白,十指修长。
唐的行为:说话有力,吐字清晰,语速很快(说明思维敏捷),随时携带自己的笔记本电脑,包括上厕所,目的是纪录下自己的随时会有的想法。
唐的称号:据称台湾十大电脑高手。
唐个人网址:http://www.autrijus.org/
唐的工作态度:每天一直努力干活直到累倒为止(累倒,是说感觉到十分的疲劳,沾床就睡的感觉)。
唐的教育经历: 14岁辍学,一直凭兴趣自学计算机知识(自称拥有自8086以来每个类型的计算机,现在在用一台华硕讯驰1。8G,计划很快去买台Mini-mac),是个绝对自学成材的自由软件者。曾去大学蹭课听,主听中文系与哲学系的课程。自我感受听中文系的老教授所讲的知识很有受益。
英语的学习:曾一段时间迷恋万智牌,为了打好牌而常上irc与老外交流,切磋牌技,经过一段时间,在irc里熟练了英语。而且还曾打到台湾万智牌的积分排名第一。
唐现在的生活:
  喜欢旅游,过去去过世界各地的很多地方(基本都是自费)。
  到处推广perl,参加开放源代码会议。刚在大陆给perlchina成员上课,推广perl。

  开办一家小计算机公司2-3年,没有什么正式的员工,大家都是网上认识的朋友。接到工作后,按照过去对大家能力的评价分配给大家干,然后大家分钱。自己干活的话是按照小时收费。每写一小时的软件收费100美金或欧元。写完的产品给客户说明需要开源,开源可以让客户免费享受很多的开源社区升级更新所带来的好处。当然如果客户不同意,他就说明要收两倍的价钱,如果客户要求软件的版权完全归自己所有,他会要求收6倍的价钱(竟然还是有一个客户愿意收6 倍的价钱)。

  从2005-02-01开始领导一个开发团队夜以继日的编写Pugs。这个团队大约有十五六人,其中有三分之一来自于台北perl推广组。

  平时当遇到某些困难问题的时候就需要大量的咖啡因(咖啡,后来换成可乐,可乐其实比较伤胃,所以注意不能多喝,好像现在想要换成茶?)。

唐对于perl的经历:
  学习perl只是由于正值互联网的兴起,有公司要他过去开发cgi,这才开始了perl的生涯。后来编写了大量的perl模块,有100多个,可以在cpan(请看附录)上找到。
  网址:http://search.cpan.org/~autrijus/

  原来最初觉得写perl很孤独,但是经过长时间的与各种朋友的交流才发现,原来很多的软件都是用perl写,原来有很多的大公司都在使用 perl,例如:微软的员工在用perl,微软赞助了windows下面的perl版本activeperl的开发;摩根士坦利整个公司都在使用 perl,他们在2003年赞助了perl基金会大约一半的费用;众多华尔街的金融机构都在使用perl   来做金融数据的处理;物工程科学也都在很大程度上使用perl,据称现在的基因工程还十分得益于perl的快速开发。

  由于在cpan上的贡献,曾在2003年2次获得perl基金会的奖励,每次2000美金。
  网址:http://www.perlfoundation.org/gc/grants/2003.html

  与台北的perl爱好者成立了台北perl推广组,每个月组织一次聚会,大约有30多人,大家见见面,并找个新的perl课题让某个人上台给大家讲演一下。最近半年这个活动已经成为了例行活动。(在台湾写perl的人大家互相都很熟悉,从唐口中了解到了董仲恺,openwebmail的开发者,一个上了8年的博士生,将自己的精力都放在了openwebmail的开发上,一个perl写的web mail,很不错)。

  在2001年唐第2次参加开放源代码大会的时候,需要在会上做一个5分钟的演讲,那时唐刚接管cpan的相关管理工作,所以他把自己在cpan 上最喜欢用的模块拿出来用中文创作了一段数来宝(cpan数来宝,有点中文rap的味道),最后还有一段一用英文唱的总结歌曲,这引起了与会者的满堂喝彩。所以以后唐到西雅图,德国,英国,都会应要求表演一段。
  网址:http://wagner.elixus.org/~autrijus/favcpan/start.html
  錄像:http://www.perl.org/tpc/2003/movies/perl-lt/

Perl6的开发: 最初开发perl6的原因与历史:
  在5年以前的2000年,由larry wall 在每年一次的开放源代码大会(oscon2000)上提出了perl6的开发计划。

  那时per*l5.6刚发布,但是当时的perl开发社群却感觉卡住了,很难再往前了。Perl这门语言已经有13年的历史,由于一直保持向后兼容,而且perl5的代核心码已经很成熟,可以说是浑然一体,所以很大程度的阻碍了我们添加新的功能,因为每次添加新的功能都有可能打破旧的代码的运行。

  Perl5是用c写的核心,它跑得很快,功能也很强,但是它的核心代码是那么的庞大,充满了各种很难以理解的宏调用。修改核心来添加新功能对任何一个人来说都是一件极为复杂和困难的工作。特别是在开发perl5.6的时候,添加了unicode与多线程的支持,但是在添加的过程中,开发者发现这种添加是件很痛苦的事情,因为每次添加新的功能都要抽取旧的功能来补。perl5的开发者就把这种现象比作一种积木游戏:叠叠乐(一堆小木头叠成一座高塔,每层有三块,每个游戏者轮流把底下的一块抽出来放到上面去,这样这个塔的底部就越来越脆弱,而这个塔就越来越高,谁抽出最后一块让塔倒下的人就是输家),大家认为perl5 的核心越来越像叠叠乐,已经越来越脆弱,无法再进一步的改进,perl5已经到了其生命的极限。

  所以larry wall就提出了开发perl6的计划。网址:http://www.perl.com/pub/a/2000/07/perl6.html

  当时的目的就是要从新设计一个perl,线程、unicode、可靠信号控制在一开始设计的时候就要被加进去,新的内核要更小,速度更快,外部扩展api要更加清晰,在过去的二进制兼容问题也要被彻底解决掉。

  然而,在larry计划新的perl6开发的同时,像python等其他语言也遇到了同样的问题:它们最初设计的时候想要解决的问题现在都已经基本解决了,可当现在要添加新功能上去的时候会发现,由于最初的设计并没有想象到现在的这种需求,所以再添加新功能也是件很困难的事情。

  既然大家都遇到相同的问题,所以这时两个开放源代码社区就提议合作共同设计一个新的底层平台,使用这个底层从根本上来解决这些大家都遇到的问题,这个底层平台就是perl6的parrot。


  在2001-04-01 larry wall(perl的设计者)与Guido van Rossum(python的设计者)一起宣布了parrot的开发计划。网址:http: //www.perl.com/pub/a/2001/04/01/parrot.htm

  这个消息令整个的开放源代码社区都十分的兴奋,大家十分期待着新项目的成功。

  这样perl6项目的整个计划就从原来的独立的perl6设计,变成了一个多层次的设计项目。

Perl6整个项目的设想:
  Perl6的整个项目是建立在底层parrot之上的。

  过去用perl5写的程序或模块与其他语言例如python、ruby都不能共容,如果想要共容的话必须用一些很糟糕的方法,所以他们就先设计了一个底层平台叫做parrot(鹦鹉,就像.net的运行期或java的虚拟机)。

  我们写perl6的代码,然后我们通过一个编译器将perl6的代码编译成字节码(byte code),这个字节码才可以直接在parrot上面运行,而parrot再负责把这些字节码具体的翻译成intel或sparc等平台上的机器码来执行。

  也就是说你可以用任意的语言来编写程序,然后通过一个编译器来翻译成统一规则的字节码,在统一的一个虚拟cpu平台parrot上运行。这样你就可以使用任意的语言来编写程序,最后大家都编译成统一规则的字节码,由于大家的字节码都遵循相同的规则,所以在字节码之间的相互调用就可以十分平滑的实现,这样不论你用何种语言编写的程序,就可以很容易的互相使用(这种技术就是JIT技术,Just In Time)。这样你用perl写的模块,就可以用python来调用,各种语言实现了共通。而且计划perl5写的程序也可以移植到parrot上面使用,这就意味着在cpan上的几千个perl模块就依然可以使用,而且其他语言也可以调用这些perl模块。而其他过去遇到的问题,如很难扩展,没有线程支持等,在parrot上面就解决掉了。在perl6架构下的整个程序的执行过程,如下图(执行自上而下):

Source Code
+------------+
| The Parser |
+------------+
Syntax Tree
+--------------+
| The Compiler |
+--------------+
Byte Code
+--------------------+
| Bytecode Optimizer |
+--------------------+
Better Byte Code
+---------+
| Runtime |
+---------+

  Source Code源代码,可以是各种语言的源代码。 The Parser是各种语言的解析器(例如python就有python的解析器,c就有c的解析器),负责将源代码转换成语法树。 Syntax Tree语法树。 The Compiler编译器,按照calling conviention规则,将各种语法树编译成字节码。 Byte Code字节码,就像虚拟cpu上面的汇编语言,而这个虚拟cpu就是parrot。 Bytecode Optimizer字节码优化器。 Better Byte Code优化后的字节码。 Runtime在这里就是parrot。

  因此最终成型的整个perl6项目实际上就是由两个部分组成:一个是底层的parrot,一个是上层的perl6语言。而Perl6的语言又可以分为:语言的设计(perl6的语法,规则,也就是Source Code),语言的实现(通过一个解析器与编译器将perl6的语言转换成字节码)。

  Perl6整个项目的想法与.net基本是同时想到的,整个概念其实与java和.net十分相似。

Parrot的特点:
  Paroot的设计就像一个软件cpu,并且它的设计与硬件cpu的设计很相近,例如:它也有一个寄存器结构,它也支持底层的操作。它的设计还参考了硬件cpu的设计。

  Parrot在设计上要满足各种动态语言的需求,而且特别注意可扩充性,像unicode,多线程等都是直接内建支持。

  Parrot的抽象层比.net与java更高,你可以写更少的代码来运行更复杂的运算。象各种面向对象相关的调用都在parrot内部有相应的机械码。

  Parrot的现在大小在250K至700K之间,它会有足够快的速度,并有足够的灵活性。

  Parrot支持多种平台,包括手持设备,如palm。
  网址:http://www.parrotcode.org

Perl6语言设计的特点:
  Perl6语言的设计思想:easy things should stay easy, hard things should get easier, and impossible things should get hard。

  例如:在perl6的语言设计上larry采用了霍夫曼编码的思想:常用的功能使用较短的单词来表示,不常用的功能用较长的单词来表示,这样就可以显著的提高你的输入程序的速度。比如说:过去perl5中的print”…”,现在在perl6中就可以用say”…”来直接代替,因为打印是程序中最常用的功能,所以就用较少的代码来表示,这样可以显著的帮助你减少代码的输入。

  Perl语言还有一个特性就是把当时最流行大家最推崇的其他语言好的功能集合起来,统一融合到自己的语言中来。在perl中这叫做多重典范。

  larry wall喜欢把这种情况比作英文,英文就是吸收了很多其他语言而组合而成的语言。Larry 的想法就是perl最好象英文那样:每个当地人在学习英文的时候都会带一些当地的方言,带一些当地的讲话习惯,但是大家也都能听懂,兼收并蓄其他语言的长处,来形成自己的特点。

  总之,把所有各种最流行的元素都集合起来,就组成了perl6语言。

  Perl6还有很强的灵活性(perl的一句格言就是:条条大路通罗马):  如果你特别喜欢oo,那么perl6感觉上就像java一样,就可以特别oo。
  如果你不喜欢强制类型声明,那perl6就可以不用声明。
  如果你特别喜欢逻辑语言例如:prolog,那么perl6就可以让你按照逻辑语言的方式来编写程序。
  Perl6吸收了很多其他语言的特点,因此你可以用自己喜欢的编程方式在perl6中编程,但是通过perl6中的语境相关的能力,不同的编程方式写出的perl6程序仍然可以很好的搭配在一起。
  这样设计的意图就是让程序员针对不同的问题,用不同的解决方式,从而对所有遇到的各种问题达到最优的解决方法。
  Perl6语言的两个特点就是:语境相关(context)与多重典范。
  Perl6与perl5的比较:语言本身的感觉其实还是跟perl5语言是一样的,只是在运行时的过程与perl5截然不同。对于过去perl5语言的很多语法perl6也继续使用,对于perl5语法的不合理部分perl6做了改进。
  网址:http://dev.perl.org/perl6
正在开发的Perl6及其相关软件:

  Parrot,perl6的执行引擎。已经开发到了0.1.2版,现在实际可以运行python、basic。
  网址:http://www.parrotcode.org

  在Parrot方面现在已经有了很多的半成品:
  比如ponie是一个能将perl5编译到parrot上面来的软件。
  网址:http://www.poniecode.org/

  有人正在将Php、Ruby移植到parrot上面来。

  有人声称要将gcc(gnu的开源c/c++编译器)移植到parrot上面,这样以后所有的可以用gcc编译的程序可以直接编译到parrot上面的字节码来运行。

  甚至还有人决定要移植.net到parrot上来。

  这当然是一个疯狂的决定,然而成事是都要靠疯子,疯子与天才是靠最后的成败来决定的,他未必会成功,但是如果成功是很了不起的(唐的原话)。

  Pugs,不管其他perl6的开发,只是先对perl6做一个真实的实现,以此检验perl6语言的特性,帮助perl6语言的进一步设计,最后计划转变为perl6的编译器到parrot。
  网址:httP://www.pugscode.org

Perl6整个项目过去4年的开发过程: Perl6语言的设计:
  在perl6 语言的初始设计的时候,首先成立了一个rfc(Request For Comments)项目,就是向所有关心perl6语言的人邀稿,大家将自己想在perl6语言中想实现的功能写成rfc,然后发给larry wall,larry wall就会想办法在perl6中帮你实现。最后larry花了一整年的时间把各种rfc中描述的特性整合到新的perl6语言中(在开发perl5的时候,他们也是用了快一整年的时间将很多其他语言的优点都整合到perl5中来,Perl过去的版本也都是这样,到处偷学,采纳各种语言好的想法)。

  Larry wall收集整理完成rfc后,从2001年起就不断的开始写启示录(Apocalypses,希腊文),描述perl6的新功能。启示录的格式与 larry wall过去写的Programming Perl(相当于perl5的圣经)这本书的格式是一样的,例如:在Programming Perl中的第6章描述的是子程序那么在启世录的第六章也是写的子程序。

  由于启示录对于perl6的描述并不是十分详细,而且写作的时间已经过去了3年,所以在2004年起larry开始根据自己的启示录编写纲要(Synopsis),来对相应的启示录章节做总结,并且更加专业的。到了2004年12月,perl6语言的大部分设计就都已经写在一系列的纲要中,而且已经稳定到了可以实际运用的程度。

Perl6的编译器的开发:
  在2000年的10月YAS在两个星期中筹集了75000美金来雇用Damian Conway(perl核心开发人员)2001年一年的时间,可以让他专门去开发perl6。

  在2002年Damian仍然继续专门负责用perl5来开发一个perl6的rules。

  在2003年Damian完成了Perl6::Rules模块,这是一个在perl5上做perl6 rules的一个雏形,是整个perl6编译器的关键部分。但是开发出的产品由于perl5自身的原因,很不成熟,无法稳定运行。

  所以3年过去了,没有成熟的perl6到parrot的编译器出现。过去开发perl6编译器的路线是错误的。

  在2005年初,根据一份perl6的建议书,perl6的开发计划再从新采用 C 语言实作 Rules 引擎(即为 PGE),来开发perl6的编译器。

  2005年2月,唐开始了pugs,另一个独立的perl6编译器的开发。

Parrot的开发:
  在2001起由Dan Sugalski负责开始开发parrot。

  从2001年8月开始放出代码,第一个版本是0.0.2版,到2005年1月已经放出过14个版本,最新的版本是0.1.2版。

  现在已经有些语言可以编译成parrot的字节码。你现在也可以用parrot的汇编语言写一些简单的程序在测试解析器上运行,parrot已经支持绝大多数的数学运算,一些基本的字符操作和一些条件运算。

  整个parrot开发速度已经超过了预期,而且还在快速进行当中。当然一些parrot子系统的开发还要进一步加快。

Perl6编译器开发过程中出现的问题:
  当最初宣布这个perl6的开发计划时,整个perl6的社区非常的高兴,大家都在等待perl6的成功运行。但是2002-2004三年的时间过去了,没有一支perl6的程序跑得起来。现在parrot的程序其实已经很稳定了,但是perl6语言到parrot的编译器一直没有实现(Parrot现在都可以跑python了)。所以到了2004年的年底大家已经绝望了,感觉perl6的实际运行遥遥无期。在这3年期间larry仍然一篇一篇的写启示录, damian一篇篇的给启示录写注疏(对于启示录中的内容实际在日常使用时的语法),可是却完全没有一个真正的perl6语言实现。

  就有一个小笑话:有人问写的perl6的程序从哪里跑?damian会说:“在我脑子里跑”。可是把他从澳洲请过来专门跑perl6程序也太贵了,而且他也不可能夜以继日的专门跑perl6程序。:)Parrot本来设计起来是要跑perl6的,但是现在似乎parrot什么都可以跑就是没法跑 perl6。

关键是问题到底出在什么地方呢?
  问题就是当初perl6的设计是要实现自足执行(self-hosting)。对于所谓的自足执行举例来说明:c的编译器是由c写的, c++的编译器是由c++写的,java的编译器有一些是由java写的,c#的编译器是由c#写的。以此类推,非常多的编译程序都是用自己来写自己的编译器,用自己来写自己的执行环境,这就是所谓的自足执行。可是我们现在所熟悉的脚本语言python php perl大都是用c来实现的,就不是自足执行,这带来的问题是你要实现任何新功能都要进入另一个语言去改,而且改了以后会影响全部的语言。你不能用自己的语言来写一个新的功能。所以在设计perl6的时候,larry就说perl6要实现自足执行,perl6要自己执行自己。这就产生了激活问题 Bootstrapping(就像一个人想提着自己的鞋带把自己提到空中,通俗说就是鸡生蛋蛋生鸡的问题)。如果一开始什么也没有的话,就无法激活。
  Perl5的时候的语法是用的yacc语法,yacc
  网址:http://www.lysator.liu.se/c/ANSI-C-grammar-y.html

  是一个用c写的语法解析器。他能帮你把你写的程序解析成程序能够理解的语法树。

  但是这种语法的灵活度比较差。所以在开发perl6的时候,就决定使用perl6 rules来解析perl6的语法,也就是所谓的自足执行。

  perl6的rules是对perl5中正则表达式的从新改进,而由于决定用perl6 rules来解析perl6的语法,所以rules在perl6中就占有了核心的地位,而问题就是出在了rules的编写上:

  最初的计划是利用 Perl 5 来解决自足执行的问题:先扩充 Perl 5,使其执行于 Parrot 虚拟机器上(透过 B::Parrot 或 Ponie),再以 Perl 5 来实际编写 Perl 6 编译器,最后透过 p5-to-p6 转换器将编译器转译成 Perl 6。不过,虽然Damian编写的Perl6::Rules模块确实在 Perl 5上实现了Rules 的雏型,但对于建构编译器而言仍显得不够成熟。

  所以过去3年perl6编译器的开发,走了一条错误的道路,整个开发perl6编译器的计划必须从新修正。

Perl6的转机—pugs的开发:
  在2005-2-1唐也开始了一件很疯狂的事情:对于过去的perl6开发通通都不管,从新编写一个解释器pugs直接运行perl6。 pugs这个项目根过去的 perl5、parrot都没有关系,在它开始的时候,唐也没有通知原perl6的开发人员,完全是自己另起炉灶,一开始大家都很迷惑,以为唐要取而代之吗?唐不管larry了吗?唐要篡位吗?

  所以唐就写了一篇外典(Apocrypha,希腊文,这里是针对larry写的Apocalypses)来解释自己开发pugs的原因。

  网址:http://svn.perl.org/perl6/pugs/trunk/docs/zh-cn/01Overview.html

  外典的意思就是用来表明不是larry写的,而是唐自己在larry的基础上对现在pugs开发的描述。

  唐开发pugs这个项目并没有得到perl基金会的资金支持。主要是最近perl基金会的资金比较紧张,唐认为自己还有财力来独立完成这个项目,所以就没有要perl基金会的赞助。

  Pugs的目的就是用来帮助perl6激活。

  Perl6 (larry启示录中描述的perl6)是一个很复杂很庞大的语言,在pugs实际开发的时候,会发现perl6语言(larry启示录中描述的 perl6)有很多自相矛盾的地方,唐的开发团队就把这些问题汇报给larry,然后larry就不断地指导来在pugs的实际开发中就解决这些冲突。这样pugs就可以实际的帮助perl6语言来进一步的完善语言设计。

  而且在解决自足执行的过程中,常存在许多瓶颈,使得许多依赖这些瓶颈的工作无法推展。好比说,没有可用的 Perl 6 实际程序,就难以为 Perl 6 撰写单元测试与标准程序库;在缺少 AST 介面的情况下,也没办法撰写 AST 求值器。Pugs 为解决自足执行过程中的各个方面提供可用的替代元件,因此解决了上述的困境。

  pugs这个项目开发的进度很快,在第7天的时候就可以跑大部分的运算程序,到了第20天就有了模块,到了第22天就有上千个测试,到了3月5号,除了对象与rules方面的某些新功能以外,其他的perl6程序全都可以执行。

  所以整个项目在以一种很恐怖的速度在开发,团队现在有16个人。

  现在已经有人写perl6的小例子,还有人在把blosxom(一个轻量级的博客系统)往perl6上面做移植,这个东西已经基本可以在 pugs上面运行了,还有其他的很多常见的计算机的运算比如河内塔、快速排序、曼德布罗特集等等都可以在pugs上面运行了,而且执行的速度还很快。

Pugs的开发计划:
  希望每个月可以放出一个版本,半年以后可以将pugs移植到parrot上面运行。

6.0: 首次释出
6.2: 基本输入输出与流程控制元件、可覆写变数(mutable variables)与赋值(assignment)。
6.28: 类(classes)与特质(traits)(perl6的对象系统)。
6.283: 规则(rules)与文法(grammars)。
6.2831: 角色组合(role composition)及其它执行时期功能。
6.28318: 宏(macros)。
6.283185: 如有必要,将 Pugs 移植至 Perl 6。
在最后一个版本也就是6.283185的时候就要完成pugs的基本使命,perl6的激活。
  Pugs这个项目是用haskell,一种纯正的函数式程序设计语言来写的。
  网址:http://www.haskell.org/

  大部分的人都不太懂haskell,唐也只是才学haskell两个月。

  唐正在鼓动perl社区的所有人来学haskell,包括larry。
  网址:http://www.pugscode.org

perl附录:
CPAN介绍:
  CPAN是一个有很多perl模块的web站点,perl现在只所以还为大家所使用,大部分是因为 cpan的强大能力,在cpan中现在有大约7000多个模块。大约有1000多个是大家常用的。这些模可以直接拿来使用,实现各种各样的功能。所以及大的方便了人们开发perl的软件。因为很多的实现只需要你去cpan下载一个相应的模块,然后安装在你的机器上,再写很少量的代码就可以完成。因此使用 perl的开发速度是非常快的。这也就是为什么perl是hacker的首选工具。他可以很快帮助你造出你想要的实现。
  网址:http://www.cpan.org

Perl核心开发人员的介绍与照片:
  Larry Wall、Dan Sugalski、Damian Conway。
  网址:http://www.perlfoundation.org/gc/grants/2002.html

关于larry wall的中文介绍:
  网址:http://fund.perlchina.org/archive/archive.php?action=archive&page=18

关于作者:
  alexe,一个无业的自由计算机者,热爱自由软件,正在努力编写im与web相关的协议。msn:alexe_com@msn.com

关于

此页面包含了发表于2005年5月20日 15:39的 Blog 上的单篇日记。

此 Blog 的前一篇日记是 好久都没更新过了,惭愧啊!

此 Blog 的后一篇日记是 W3C认证果然严格啊!

更多信息可在 主索引 页和 归档 页看到。

Creative Commons License
此 Blog 中的日记遵循以下授权 Creative Commons(创作共用)授权.
Powered by
Movable Type 6.3.2