Pyrocat

Git的工作原理(一):对象和引用

Git的用户界面简直糟透了。它既不友好也不一致,不少命令和选项的取名也违反直觉。新手常常会不小心把工作目录和版本树折腾到一种不知如何复原的状态。然而剥去尚需花大力气改进的界面,它那强大的版本控制功能,都是建立在一个简单的核心之上的。本文中,我们将一窥其底层的工作原理。

简单布料物理模拟

太长不看:Demo

不久前在Codepen上看到一个JavaScript实现的简单布料力学模拟,激起了我对柔体动力学模拟的兴趣。所谓柔体动力学,既是对可形变的物体的模拟。游戏和CG动画中的常见的衣服、布料和人体皆可认为是可形变的物体。对这类物体的物理模拟有多种方法,其中最为常见的便是基于韦尔莱积分法(Verlet integration)的物理模型。由于计算简单、资源消耗少,韦尔莱积分更是受游戏物理引擎开发者青睐。下面依样画葫芦,实现如何实现一个简单的布料物理模拟。

Unix: 世界上第一个计算机病毒

本文译自1994年出版的The Unix-Haters Handbook1,第1章。注意,文中许多事实已不能反映当今Unix系操作系统的发展状况。

伯克利最著名的两大特产分别是LSD和Unix,我可不认为这是一种巧合。

佚名

病毒越小、适应性越强就越好。它们不太复杂:没有呼吸作用、新陈代谢和运动等奥秘所需要的构造,它们只有足够实现自我复制的DNA和RNA。比方说,随便哪种流感病毒的体积都比它们感染的细胞要小许多倍,但却能在每个流感季节成功地变异出新菌株。偶尔毒性增强了,随之产生的流行病会杀死数百万人,因为人类的免疫系统没法在病毒入侵前消灭它们。但是,大多数时候,病毒只是些小烦恼——不可避免,却无处不在。

优秀病毒的特征是:

  • 体积小

    病毒能做的不多,所以它们也不需要很大。有人还争论病毒到底是活着的生物还是几片具有破坏性的核酸和蛋白质。

  • 移植性强

    一个病毒单体可以入侵多种细胞。经过少许变异后,能入侵更多。动物和病毒常常通过变异来攻击人类。证据表明,艾滋病病毒很可能是由猿猴病毒变异而来。

  • 霸占宿主资源

    如果宿主没有办法为病毒提供安全的环境和自我复制的能量,病毒就会死。

  • 快速变异

    病毒频繁地变异成不同种类。它们虽然有着相同的结构,但却有足够大的区别来混淆宿主的防御系统。

Unix具备一个非常成功的病毒的所有特征。它的最初形态很小,功能稀缺,其设计上的极简主义已登峰造极。正是因为它缺乏一个真正的操作系统所应该具有的功能(比如内存映射文件2(memory-mapped file)、高速I/O、健壮的文件系统、记录、文件、设备锁、合理的进程间通信,等等),它具有可移植性,而功能更强大的操作系统就没有这么高的可移植性了。Unix还从它的宿主处吸取能量,如果没有系统管理员维护,它就会时不时崩溃、吐核3(core dump),或者当机。Unix还经常变异:某个版本里正常工作的补丁在另一个版本里却不能用。如果安德罗美达菌株4是软件的话,那么它一定是Unix。

Unix是带用户界面的计算机病毒。

汉字中的「斜体」

在西文语境下,我们要在一句话中突出表示一个词,或者一句引语,按惯例往往采用斜体1。比如:I love you。随着计算机时代的到来,几乎所有文字处理软件,都内建了“斜体”这个功能。然而,崛起于西方世界的计算机科学,似乎从未考虑过东亚地区文字(CJK)的书写风格和历史习惯。在我们的的书写历史上,从未正式出现过使用意大利体来强调某个词语或者某句引语。由于汉字中并没有斜体,我们的文字处理软件中的“斜体”汉字,都是对正体字作倾斜变换后得到的伪斜体2

作为一个广为人知的误解,人们常常认为「斜体」就是「基准线向右倾斜的字体」,其实不然3。「斜体」特指为了加快书写速度而字母略微向右倾斜的一种手写书法风格,而「基准线向右倾斜的字体」,即上面提到的「伪斜体」,仅仅是对罗马体西文字母做向右倾斜变换。

Donald Knuth在他的著作《》中写道:

Slanted type is essentially the same as roman, but the letters are slightly skewed, while the letters in italic type are drawn in a different style.

那么根据这个定义,中文字体中是否有对应于西文斜体的风格?在我看来,答案是肯定的。我们定义一个西文字体是不是斜体,最主要看是不是有手写风格在里面。换句话说,我们要寻找的是一种用不同风格书写的书法字体。在中文语境中,一个最为广泛使用,且满足上述条件的候选字就是:楷体

CoffeeScript如何模拟类继承

CoffeeScript中可以使用class, extendssuper等关键字模拟OOP中的类与继承,比如下面的CoffeeScript代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Animal
  constructor: (@name) ->

  move: (meters) ->
    alert @name + " moved #{meters}m."

class Snake extends Animal
  move: ->
    alert "Slithering..."
    super 5

class Horse extends Animal
  move: ->
    alert "Galloping..."
    super 45

sam = new Snake "Sammy the Python"
tom = new Horse "Tommy the Palomino"

sam.move()
tom.move()

将被翻译成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
var Animal, Horse, Snake, sam, tom,
  __hasProp = {}.hasOwnProperty,
  __extends = function(child, parent) {
    for (var key in parent) {
        if (__hasProp.call(parent, key))
            child[key] = parent[key];
    }
    function ctor() {
        this.constructor = child;
    }
    ctor.prototype = parent.prototype;
    child.prototype = new ctor();
    child.__super__ = parent.prototype;
    return child;
  };

Animal = (function() {

  function Animal(name) {
    this.name = name;
  }
  Animal.prototype.move = function(meters) {
    return alert(this.name + (" moved " + meters + "m."));
  };

  return Animal;

})();

Snake = (function(_super) {

  __extends(Snake, _super);

  function Snake() {
    return Snake.__super__.constructor.apply(this, arguments);
  }

  Snake.prototype.move = function() {
    alert("Slithering...");
    return Snake.__super__.move.call(this, 5);
  };

  return Snake;

})(Animal);

Horse = (function(_super) {

  __extends(Horse, _super);

  function Horse() {
    return Horse.__super__.constructor.apply(this, arguments);
  }

  Horse.prototype.move = function() {
    alert("Galloping...");
    return Horse.__super__.move.call(this, 45);
  };

  return Horse;

})(Animal);

sam = new Snake("Sammy the Python");

tom = new Horse("Tommy the Palomino");

sam.move();

tom.move();

一开始看可能比较没头绪,所以下面将一步步渐进式地解释这种实现方式的含义。

LogoScript,一个Logo方言与实现

花了几天时间,完成了一个玩具脚本语言的解释器。我把这个语言命名为LogoScript。顾名思义,Logo是古老的绘图教学语言,Smalltalk的前身,现在大多数人知道它的就是“海龟作图“;取名中有Script,是因为它与JavaScript有着极其相似的语法。语言的实现只有两千余行代码,大部分由CoffeeScript编写。

Feature

下面是几个LogoScript脚本以及对应的输出图像。

Spiral

1
2
3
4
for (x = 1; x <= 150; x++) {
  fd(1.5 * x);
  rt(89);
}

spiral

Hypotrochoid

1
2
3
4
5
6
7
for (i = 0; i < 36; i++) {
  for (j = 0; j < 36; j++) {
    fd(16);
    rt(10);
  }
  rt(10);
}

hypotrochoid

Spinning Squares

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function hue(theta) {
  red = round(127.5 * (1 + sin(theta)));
  green = round(127.5 * (1 + sin(theta + 120)));
  blue = round(127.5 * (1 + sin(theta + 240)));
  return 'rgb(' + red + ',' + green + ',' + blue + ')';
}

function square(side) {
  bk(side / 2);
  rt(90);
  bk(side / 2);
  pd();
  for (i = 0; i < 4; i++) {
    fd(side);
    lt(90);
  }
  pu();
  fd(side / 2);
  lt(90);
  fd(side / 2);
}

function spinSquare(side) {
  if (side < 12) return;
  setpc(hue(1.4 * side));
  square(side);
  lt(4);
  spinSquare(side - 8);
}

clear('black');
pu();
rt(6);
spinSquare(340);

spinning-squares

Tree

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function treeColor(length) {
	return 2.5 * (100 - length);
}

angle = 50;

function tree(length) {
  if (length < 10) return;
  setpw(length / 9);
  setpc('rgb(255,' + round(treeColor(length)) + ',0)');
  fd(length);
  lt(angle / 2);
  tree(length * 0.65);
	rt(angle);
	tree(length * 0.85);
	lt(angle / 2);
	pu();
	bk(length);
	pd();
}

clear('black');
pu();
setxy(-94, -160);
rt(5);
pd();
tree(85);

tree

Twisted Roses

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function getColor(theta) {
  return round(abs(255 * cos(theta)));
}

function width(angle, radius) {
  seth2(radius * sin(angle), radius * cos(angle));
  return 2 * (1.5 + sin(45 + 2 * geth()));
}

function spiral(angle, twist) {
  // Twisted Rose Curves
  radius = 180 * sin(4 * angle);
  angle = angle + 20 * sin(twist * angle);
  setpw(width(angle, radius));
  setpc('rgb(' + getColor(30 + 3 * angle) + ',0,255)');
  setxy(radius * sin(angle), radius * cos(angle));
  pd();
}

clear('black');
pu();
//for (twist = 0; twist < 24; twist++) {
for (angle = 0; angle < 360; angle++) {
  spiral(angle, 7 /* twist */);
}
//}

twisted-7

修改twist的值可以得到不同的玫瑰曲线,比如为5和为6的时候分别如下:

twisted-5

twisted-6

一个时代的终结

本文是第二届《参考消息》读者译文大赛的参赛作品,与同学合作完成。原文刊载于《时代》杂志,作者Peter Bergen,在线浏览地址在这里

奥萨马·本·拉登一直认为自己有几分诗人的气质,但他的作品却呈现出一种病态。即使在“9·11”事件发生两年后,他的写的一首预测自己死亡情形的诗也不例外。本·拉登写道:“愿我葬身鹰腹,长眠于群鹰环绕的苍穹。”

事实是本·拉登在巴基斯坦被美军海豹突击队击毙,下葬于阿拉伯海深处。如果说有哪首诗能代表本·拉登的结局,这首诗便是“正义”之诗。这不由得让人想起“9·11”事件发生后的第9天,布什总统在国会演讲中所作的预言。布什在这次演讲中展现了他惊人的口才,他断言道,本·拉登和“基地”组织必将被送入“被遗弃的谎言筑成的历史无名冢”。

寻找莱娜:「互联网第一夫人」背后的故事

「莱娜图」恐怕是互联网历史上影响最深远的图片。早在70年代,南加州大学的工程师们就把这张图片用于图像处理研究中。这些研究工作为JPEG和MPEG标准的出现奠定了基础。这些技术被用于阿帕网(ARPANET)——万维网(WWW)的前身。

莱娜图其实是1972年11月号《花花公子》杂志上的一张插图的一部分。大约是在1973年的六月或七月,南加州大学信号与图像处理研究所的研究员们匆忙地寻找一副高质量的图片用于学术论文。他们希望找到一副动态范围很好的人脸图像。正好这时,一位没有被载入史册的研究员带着一本《花花公子》走了进来。大家使用一台Muirhead扫描仪将扫描范围定位在插图上部5.12英寸,扫描得到了这张512 × 512的图像。在扫描后,有人发现由于软件错误,这张图片缺少了一行像素,而且,由于数模转换器的计时错误,这张图片被轻微地纵向拉长。由于时间紧迫,他们没有重新扫描这张图片。于是,这张略有瑕疵的图片就这样流传下来了。从这时起。这张花花公子玩伴的图像被广泛地用在工业领域,成为了数字图像传输和处理的标准测试图。

Lenna Montage