Ohm：用两百行 JavaScript 创造你自己的编程语言

都那么厉害了以后可以不用上班了

感觉程序员可以下岗了

# Ohm：用两百行 JavaScript 创造你自己的编程语言

解析器是一种超级有用的软件库。从概念上简单的说，它们的实现很有挑战性，并且在计算机科学中经常被认为是黑魔法。在这个系列的博文中，我会向你们展示为什么你不需要成为哈利波特就能够精通解析器这种魔法。但是为了以防万一带上你的魔杖吧！

我们将探索一种叫做 Ohm 的新的开源库，它使得搭建解析器很简单并且易于重用。在这个系列里，我们使用 Ohm 去识别数字，构建一个计算器等等。在这个系列的最后你将已经用不到 200 行的代码发明了一种完整的编程语言。这个强大的工具将让你能够做到一些你可能过去认为不可能的事情。

### 为什么解析器很困难？

解析器非常有用。在很多时候你可能需要一个解析器。或许有一种你需要处理的新的文件格式，但还没有人为它写了一个库；又或许你发现了一种古老格式的文件，但是已有的解析器不能在你的平台上构建。我已经看到这样的事发生无数次。 Code 在或者不在， Data 就在那里，不增不减。

从根本上来说，解析器很简单：只是把一个数据结构转化成另一个。所以你会不会觉得你要是邓布利多校长就好了？

解析器历来是出奇地难写，所面临的挑战是绝大多数现有的工具都很老，并且需要一定的晦涩难懂的计算机科学知识。如果你在大学里上过编译器课程，那么课本里也许还有从上世纪七十年传下来的技术。幸运的是，解析器技术从那时候起已经提高了很多。

典型的，解析器是通过使用一种叫作<ruby>   形式语法  <rp>  （ </rp> <rt>  formal grammar </rt> <rp>  ） </rp></ruby>的特殊语法来定义你想要解析的东西来创造的，然后你需要把它放入像 [Bison](https://en.wikipedia.org/wiki/GNU_bison) 和 [Yacc](https://en.wikipedia.org/wiki/Yacc) 的工具中，这些工具能够产生一堆 C 代码，这些代码你需要修改或者链接到你实际写入的编程语言中。另外的选择是用你更喜欢的语言亲自动手写一个解析器，这很慢且很容易出错，在你能够真正使用它之前还有许多额外的工作。

想像一下，是否你关于你想要解析的东西的语法描述也是解析器？如果你能够只是直接运行这些语法，然后仅在你需要的地方增加一些<ruby> 挂钩 <rp>  （ </rp> <rt>  hook </rt> <rp>  ） </rp></ruby>呢？那就是 Ohm 所可以做到的事。

### Ohm 简介

[Ohm](https://github.com/cdglabs/ohm) 是一种新的解析系统。它类似于你可能已经在课本里面看到过的语法，但是它更强大，使用起来更简单。通过 Ohm, 你能够使用一种灵活的语法在一个 .ohm 文件中来写你自己的格式定义，然后使用你的宿主语言把语义加入到里面。在这篇博文里，我们将用 JavaScript 作为宿主语言。

Ohm 建立于一个为创造更简单、更灵活的解析器的多年研究基础之上。VPRI 的 [STEPS program (pdf)](http://www.vpri.org/pdf/tr2012001_steps.pdf) 使用 Ohm 的前身 [Ometa](http://tinlizzie.org/ometa/) 为许多特殊的任务创造了专门的语言（比如一个有 400 行代码的平行制图描绘器）。

Ohm 有许多有趣的特点和符号，但是相比于全部解释它们，我认为我们只需要深入其中并构建一些东西就行了。

### 解析整数

让我们来解析一些数字。这看起来会很简单，只需在一个文本串中寻找毗邻的数字，但是让我们尝试去处理所有形式的数字：整数和浮点数、十六进制数和八进制数、科学计数、负数。解析数字很简单，正确解析却很难。

亲自构建这个代码将会很困难，会有很多问题，会伴随有许多特殊的情况，比如有时会相互矛盾。正则表达式或许可以做的这一点，但是它会非常丑陋而难以维护。让我们用 Ohm 来试试。

用 Ohm 构建的解析器涉及三个部分：<ruby> 语法 <rp>  （ </rp> <rt>  grammar </rt> <rp>  ） </rp></ruby>、<ruby> 语义 <rp>  （ </rp> <rt>  semantics </rt> <rp>  ） </rp></ruby>和<ruby> 测试 <rp>  （ </rp> <rt>  tests </rt> <rp>  ） </rp></ruby>。我通常挑选问题的一部分为它写测试，然后构建足够的语法和语义来使测试通过。然后我再挑选问题的另一部分，增加更多的测试、更新语法和语义，从而确保所有的测试能够继续通过。即使我们有了新的强大的工具，写解析器从概念上来说依旧很复杂。测试是用一种合理的方式来构建解析器的唯一方法。现在，让我们开始工作。

我们将从整数开始。一个整数由一系列相互毗邻的数字组成。让我们把下面的内容放入一个叫做 grammar.ohm 的文件中：

```
CoolNums {
   // just a basic integer
   Number = digit+
}

```

这创造了一条匹配一个或多个数字（`digit`）叫作 `Number` 的单一规则。`＋` 意味着一个或更多，就在正则表达式中一样。当有一个或更多的数字时，这个规则将会匹配它们，如果没有数字或者有一些不是数字的东西将不会匹配。“数字（`digit`）”的定义是从 0 到 9 其中的一个字符。`digit` 也是像 `Number` 一样的规则，但是它是 Ohm 的其中一条构建规则因此我们不需要去定义它。如果我们想的话可以推翻它，但在这时候这没有任何意义，毕竟我们不打算去发明一种新的数。

现在，我们可以读入这个语法并用 Ohm 库来运行它。

把它放入 test1.js：

```
var ohm = require('ohm-js');
var fs = require('fs');
var assert = require('assert');
var grammar = ohm.grammar(fs.readFileSync('src/blog_numbers/syntax1.ohm').toString());

```

`Ohm.grammar` 调用将读入该文件并解析成一个语法对象。现在我们可以增加一些语义。把下面内容增加到你的 JavaScript 文件中：

```
var sem = grammar.createSemantics().addOperation('toJS', {
    Number: function(a) {
        return parseInt(this.sourceString,10);
    }
});

```

这通过 `toJS` 操作创造了一个叫作 `sem` 的语法集。这些语义本质上是一些对应到语法中每个规则的函数。每个函数当与之相匹配的语法规则被解析时将会被调用。上面的 `Number` 函数将会在语法中的 `Number` 规则被解析时被调用。<ruby> 语法 <rp>  （ </rp> <rt>  grammar </rt> <rp>  ） </rp></ruby>定义了在语言中这些代码是什么，<ruby> 语义 <rp>  （ </rp> <rt>  semantics </rt> <rp>  ） </rp></ruby>定义了当这些代码被解析时应该做什么。

语义函数能够做我们想做的任何事，比如打印出故障信息、创建对象，或者在任何子节点上递归调用 `toJS`。此时我们仅仅想把匹配的文本转换成真正的 JavaScript 整数。

所有的语义函数有一个内含的 `this` 对象，带有一些有用的属性。其 `source` 属性代表了输入文本中和这个节点相匹配的部分。`this.sourceString` 是一个匹配输入的串，调用内置在 JavaScript 中的 `parseInt` 函数会把这个串转换成一个数。传给 `parseInt` 的 `10` 这个参数告诉 JavaScript 我们输入的是一个以 `10` 为基底（10 进制）的数。如果少了这个参数， JavaScript 也会假定以 10 为基底，但是我们把它包含在里面因为后面我们将支持以 16 为基底的数，所以使之明确比较好。

既然我们有一些语法，让我们来实际解析一些东西看一看我们的解析器是否能够工作。如何知道我们的解析器可以工作？通过测试，许多许多的测试，每一个可能的边缘情况都需要一个测试。

使用标准的断言 `assert` API，以下这个测试函数能够匹配一些输入并运用我们的语义把它转换成一个数，然后把这个数和我们期望的输入进行比较。

```
   function test(input, answer) {
     var match = grammar.match(input);
     if(match.failed()) return console.log("input failed to match " + input + match.message);
     var result = sem(match).toJS();
     assert.deepEqual(result,answer);
     console.log('success = ', result, answer);
    }

```

就是如此。现在我们能够为各种不同的数写一堆测试。如果匹配失败我们的脚本将会抛出一个例外。否则就打印成功信息。让我们尝试一下，把下面这些内容加入到脚本中：

```
    test("123",123);
    test("999",999);
    test("abc",999);

```

然后用 `node test1.js` 运行脚本。

你的输出应该是这样：

```
success =  123 123
success =  999 999
input failed to match abcLine 1, col 1:
> 1 | abc
      ^
Expected a digit

```

真酷。正如预期的那样，前两个成功了，第三个失败了。更好的是，Ohm 自动给了我们一个很棒的错误信息指出匹配失败。

### 浮点数

我们的解析器工作了，但是它做的工作不是很有趣。让我们把它扩展成既能解析整数又能解析浮点数。改变 grammar.ohm 文件使它看起来像下面这样：

```
CoolNums {
  // just a basic integer
  Number = float | int
  int    = digit+
  float  = digit+ "." digit+
}

```

这把 `Number` 规则改变成指向一个浮点数（`float`）或者一个整数（`int`）。这个 `|` 代表着“或”。我们把这个读成“一个 `Number` 由一个浮点数或者一个整数构成。”然后整数（`int`）定义成 `digit+`，浮点数（`float`）定义成 `digit+` 后面跟着一个句号然后再跟着另一个 `digit+`。这意味着在句号前和句号后都至少要有一个数字。如果一个数中没有一个句号那么它就不是一个浮点数，因此就是一个整数。

现在，让我们再次看一下我们的语义功能。由于我们现在有了新的规则所以我们需要新的功能函数：一个作为整数的，一个作为浮点数的。

```
var sem = grammar.createSemantics().addOperation('toJS', {
    Number: function(a) {
        return a.toJS();
    },
    int: function(a) {
        console.log("doing int", this.sourceString);
        return parseInt(this.sourceString,10);
    },
    float: function(a,b,c) {
        console.log("doing float", this.sourceString);
        return parseFloat(this.sourceString);
    }
});

```

这里有两件事情需要注意。首先，整数（`int`）、浮点数（`float`）和数（`Number`）都有相匹配的语法规则和函数。然而，针对 `Number` 的功能不再有任何意义。它接收子节点 `a` 然后返回该子节点的 `toJS` 结果。换句话说，`Number` 规则简单的返回相匹配的子规则。由于这是在 Ohm 中任何规则的默认行为，因此实际上我们不用去考虑 `Number` 的作用，Ohm 会替我们做好这件事。

其次，整数（`int`）有一个参数 `a`，然而浮点数有三个：`a`、`b` 和 `c`。这是由于规则的<ruby> 实参数量 <rp>  （ </rp> <rt>  arity </rt> <rp>  ） </rp></ruby>决定的。<ruby>   实参数量  <rp>  （ </rp> <rt>  arity </rt> <rp>  ） </rp></ruby>意味着一个规则里面有多少参数。如果我们回过头去看语法，浮点数（`float`）的规则是：

```
  float  = digit+ "." digit+

```

浮点数规则通过三个部分来定义：第一个 `digit+`、`.`、以及第二个 `digit+`。这三个部分都会作为参数传递给浮点数的功能函数。因此浮点数必须有三个参数，否则 Ohm 库会给出一个错误。在这种情况下我们不用在意参数，因为我们仅仅直接攫取了输入串，但是我们仍然需要参数列在那里来避免编译器错误。后面我们将实际使用其中一些参数。

现在我们可以为新的浮点数支持添加更多的测试。

```
test("123",123);
test("999",999);
//test("abc",999);
test('123.456',123.456);
test('0.123',0.123);
test('.123',0.123);

```

注意最后一个测试将会失败。一个浮点数必须以一个数开始，即使它就是个 0，`.123` 不是有效的，实际上真正的 JavaScript 语言也有相同的规则。

### 十六进制数

现在我们已经有了整数和浮点数，但是还有一些其它的数的语法最好可以支持：十六进制数和科学计数。十六进制数是以 16 为基底的整数。十六进制数的数字能从 0 到 9 和从 A 到 F。十六进制数经常用在计算机科学中，当用二进制数据工作时，你可以仅仅使用两个数字表示 0 到 255 的数。

在绝大多数源自 C 的编程语言（包括 JavaScript），十六进制数通过在前面加上 `0x` 来向编译器表明后面跟的是一个十六进制数。为了让我们的解析器支持十六进制数，我们只需要添加另一条规则。

```
  Number = hex | float | int
  int    = digit+
  float  = digit+ "." digit+
  hex    = "0x" hexDigit+
  hexDigit := "0".."9" | "a".."f" | "A".."F"

```

我实际上已经增加了两条规则。十六进制数（`hex`）表明它是一个 `0x` 后面一个或多个十六进制数字（`hexDigits`）的串。一个十六进制数字（`hexDigit`）是从 0 到 9，或从 a 到 f，或 A 到 F（包括大写和小写的情况）的一个字符。我也修改了 `Number` 规则来识别十六进制数作为另外一种可能的情况。现在我们只需要另一条针对十六进制数的功能规则。

```
    hex: function(a,b) {
        return parseInt(this.sourceString,16);
    }

```

注意到，在这种情况下，我们把 `16` 作为基底传递给 `parseInt`，因为我们希望 JavaScript 知道这是一个十六进制数。

我略过了一些很重要需要注意的事。`hexDigit` 的规则像下面这样：

```
  hexDigit := "0".."9" | "a".."f" | "A".."F"

```

注意我使用的是 `:=` 而不是 `=`。在 Ohm 中，`:=` 是当你需要推翻一条规则的时候使用。这表明 Ohm 已经有了一条针对 `hexDigit` 的默认规则，就像 `digit`、`space` 等一堆其他的东西。如果我使用了 `=`, Ohm 将会报告一个错误。这是一个检查，从而避免我无意识的推翻一个规则。由于新的 `hexDigit` 规则和 Ohm 的构建规则一样，所以我们可以把它注释掉，然后让 Ohm 自己来实现它。我留下这个规则只是因为这样我们可以看到它实际上是如何进行的。

现在，我们可以添加更多的测试然后看到十六进制数真的能工作：

```
test('0x456',0x456);
test('0xFF',255);

```

### 科学计数

最后，让我们来支持科学计数。科学计数是针对非常大或非常小的数的，比如 `1.8×10^3`。在大多数编程语言中，科学计数法表示的数会写成这样：1.8e3 表示 18000，或者 1.8e-3 表示 .018。让我们增加另外一对规则来支持这个指数表示：

```
    float  = digit+ "." digit+ exp?
    exp    = "e" "-"? digit+

```

上面在浮点数规则末尾增加了一个指数（`exp`）规则和一个 `?`。`?` 表示没有或有一个，所以指数（`exp`）是可选的，但是不能超过一个。增加指数（`exp`）规则也改变了浮点数规则的实参数量，所以我们需要为浮点数功能增加另一个参数，即使我们不使用它。

```
    float: function(a,b,c,d) {
        console.log("doing float", this.sourceString);
        return parseFloat(this.sourceString);
    },

```

现在我们的测试可以通过了：

```
test('4.8e10',4.8e10);
test('4.8e-10',4.8e-10);

```

### 结论

Ohm 是构建解析器的一个很棒的工具，因为它易于上手，并且你可以递增的增加规则。Ohm 也还有其他我今天没有写到的很棒的特点，比如调试观察仪和子类化。

到目前为止，我们已经使用 Ohm 来把字符串翻译成 JavaScript 数，并且 Ohm 经常用于把一种表示方式转化成另外一种。然而，Ohm 还有更多的用途。通过放入不同的语义功能集，你可以使用 Ohm 来真正处理和计算东西。一个单独的语法可以被许多不同的语义使用，这是 Ohm 的魔法之一。

在这个系列的下一篇文章中，我将向你们展示如何像真正的计算机一样计算像 `(4.85 + 5 * (238 - 68)/2)` 这样的数学表达式，不仅仅是解析数。

额外的挑战：你能够扩展语法来支持八进制数吗？这些以 8 为基底的数能够只用 0 到 7 这几个数字来表示，前面加上一个数字 0 或者字母 `o`。看看针对下面这些测试情况是够正确。下次我将给出答案。

```
test('0o77',7*8+7);
test('0o23',0o23);

```

---

via: <https://www.pubnub.com/blog/2016-08-30-javascript-parser-ohm-makes-creating-a-programming-language-easy/>

作者：[Josh Marinacci](https://www.pubnub.com/blog/author/josh/) 译者：[ucasFL](https://github.com/ucasFL) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Summary: TypeScript 是一种基于 JavaScript 衍生的语言，是由微软为了使大型 Web 应用开发更容易而创造的一种语言，现在已经发布了 2.0 里程碑版本。

azure的管理门户就是使用这种语言开发的。

是前台，还只是部分，不能把 HTML/CSS 遗忘了。

typescript助力nodejs开发

# 微软为大型 JavaScript 应用而开发的 TypeScript 发布了 2.0 版本

TypeScript 是一种基于 JavaScript 衍生的语言，是由微软为了[使大型 Web 应用开发更容易](http://arstechnica.com/information-technology/2012/10/microsoft-typescript-the-javascript-we-need-or-a-solution-looking-for-a-problem/)而创造的一种语言，现在已经发布了 [2.0 里程碑版本](https://blogs.msdn.microsoft.com/typescript/2016/09/22/announcing-typescript-2-0/)。

在用于大型开发时， JavaScript 由于其固有的特性而面临一些挑战。其它的静态编译语言，如 C#、Java 和 C++ 在每次开发人员敲下“编译”时会进行全面的错误检查，而 JavaScript 直到运行时才会做错误检查。这意味着，从输入错误到像对非数字进行数学运算这样的错误用法都根本不会遇到检查，所以，用户不走运的话就会遇到这些问题。而在 TypeScript 中，微软的目标是引入一些其它语言也提供的检查和校验，而依然保持和 JavaScript 的兼容性，并可以编译成 JavaScript。

根据介绍，TypeScript 2.0 引入了一些新功能，改进了性能、增强了 JavaScript 兼容性，并在 TypeScript 进行编译时扩大了错误检查的范围。TypeScript 2.0 中的一大进步就是给予开发人员对 `null` 值的更大控制。

`null` 用于表示变量根本没有值，它被其发明人戏称为“[价值十亿美元的错误](https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare)”。一次又一次，程序总是由于没有正确检查一个值是否是 `null` 值而掉到坑里。但是不管好与不好，所有主流的编程语言都支持这个 `null` 的概念。

TypeScript 2.0 引入了[许多新的特性](https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript)，但是其中最大的特性就是对 `null` 值的控制。在 TypeScript 2.0 中，开发人员可以可以启用一种新的行为，以默认防止变量赋值为 null。当启用该选项时，默认情况下变量必须有一个值，且这个值不能是 `null`。这可以让编译器发现变量没有初始化的错误。

TypeScript 似乎赢得了许多 JavaScript 开发者的拥护，谷歌采用它来[开发 Angular 2 框架](https://blogs.msdn.microsoft.com/typescript/2015/03/05/angular-2-built-on-typescript/)，而 Visual Studio、Visual Studio Code、Eclipse、Emacs、Vim 等等开发环境也都支持 TypeScript。微软已经把它作为社区驱动的项目进行了开源，目前已经有超过 150 个独立贡献者参与了该项目，这已经是雷蒙德拥抱开源的成功典范之一。


理解 Linux 下 Shell 命令的不同分类及它们的用法

不同的 shell，其具体实现是有差异的。

# 理解 Linux 下 Shell 命令的不同分类及它们的用法

当你打算真正操纵好你的 Linux 系统，没有什么能比命令行界面更让你做到这一点。为了成为一个 Linux 高手，你必须能够理解 [Shell 命令的不同类型](http://www.tecmint.com/different-types-of-linux-shells/)，并且会在终端下正确的使用它们。

在 Linux 下，命令有几种类型，对于一个 Linux 新手来说，知道不同命令的意思才能够高效和准确的使用它们。因此，在这篇文章里，我们将会遍及各种不同分类的 Linux Shell 命令。

需要注意一件非常重要的事：命令行界面和 Shell 是不同的，命令行界面只是为你提供一个访问 Shell 的方式。而 Shell ，它是可编程的，这使得它可以通过命令与内核进行交流。

下面列出了 Linux 下命令的不同种类：

### 1. 程序可执行文件（文件系统 中的命令）

当你执行一条命令的时候，Linux 通过从左到右搜索存储在 `$PATH` 环境变量中的目录来找到这条命令的可执行文件。

你可以像下面这样查看存储在 `$PATH` 中的目录：

```
$ echo $PATH
/home/aaronkilik/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

```

在上面的命令中，目录 `/home/aaronkilik/bin` 将会被首先搜索，紧跟着是 `/usr/local/sbin`，然后一直接着下去。在搜索过程中，搜索顺序是至关重要的。

比如在 `/usr/bin` 目录里的文件系统中的命令：

```
$ ll /bin/

```

示例输出：

```
total 16284
drwxr-xr-x  2 root root    4096 Jul 31 16:30 ./
drwxr-xr-x 23 root root    4096 Jul 31 16:29 ../
-rwxr-xr-x  1 root root    6456 Apr 14 18:53 archdetect*
-rwxr-xr-x  1 root root 1037440 May 17 16:15 bash*
-rwxr-xr-x  1 root root  520992 Jan 20  2016 btrfs*
-rwxr-xr-x  1 root root  249464 Jan 20  2016 btrfs-calc-size*
lrwxrwxrwx  1 root root       5 Jul 31 16:19 btrfsck -> btrfs*
-rwxr-xr-x  1 root root  278376 Jan 20  2016 btrfs-convert*
-rwxr-xr-x  1 root root  249464 Jan 20  2016 btrfs-debug-tree*
-rwxr-xr-x  1 root root  245368 Jan 20  2016 btrfs-find-root*
-rwxr-xr-x  1 root root  270136 Jan 20  2016 btrfs-image*
-rwxr-xr-x  1 root root  249464 Jan 20  2016 btrfs-map-logical*
-rwxr-xr-x  1 root root  245368 Jan 20  2016 btrfs-select-super*
-rwxr-xr-x  1 root root  253816 Jan 20  2016 btrfs-show-super*
-rwxr-xr-x  1 root root  249464 Jan 20  2016 btrfstune*
-rwxr-xr-x  1 root root  245368 Jan 20  2016 btrfs-zero-log*
-rwxr-xr-x  1 root root   31288 May 20  2015 bunzip2*
-rwxr-xr-x  1 root root 1964536 Aug 19  2015 busybox*
-rwxr-xr-x  1 root root   31288 May 20  2015 bzcat*
lrwxrwxrwx  1 root root       6 Jul 31 16:19 bzcmp -> bzdiff*
-rwxr-xr-x  1 root root    2140 May 20  2015 bzdiff*
lrwxrwxrwx  1 root root       6 Jul 31 16:19 bzegrep -> bzgrep*
-rwxr-xr-x  1 root root    4877 May 20  2015 bzexe*
lrwxrwxrwx  1 root root       6 Jul 31 16:19 bzfgrep -> bzgrep*
-rwxr-xr-x  1 root root    3642 May 20  2015 bzgrep*

```

### 2. Linux 别名

这些是用户定义的命令，它们是通过 shell 内置命令 `alias` 创建的，其中包含其它一些带有选项和参数的 shell 命令。这个意图主要是使用新颖、简短的名字来替代冗长的命令。

创建一个别名的语法像下面这样：

```
$ alias newcommand='command -options'

```

通过下面的命令，可以列举系统中的所有别名：

```
$ alias -p
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -alF'
alias ls='ls --color=auto'

```

要在 Linux 中创建一个新的别名，仔细阅读下面的例子。

```
$ alias update='sudo apt update'
$ alias upgrade='sudo apt dist-upgrade'
$ alias -p | grep 'up'

```

然而，上面这些我们创建的别名只能暂时的工作，当经过下一次系统启动后它们不再工作。你可以像下面展示的这样在 '.bashrc' 文件中设置永久别名。

添加以后，运行下面的命令来激活：

```
$ source ~/.bashrc

```

### 3. Linux Shell 保留字

在 shell 程序设计中，`if`、`then`、`fi`、`for`、`while`、`case`、`esac`、`else`、`until` 以及其他更多的字都是 shell 保留字。正如描述所暗示的，它们在 shell 中有特殊的含义。

你可以通过使用下面展示的 `type` 命令来列出所有的 shell 关键字：

```
$ type if then fi for while case esac else until
if is a shell keyword
then is a shell keyword
fi is a shell keyword
for is a shell keyword
while is a shell keyword
case is a shell keyword
esac is a shell keyword
else is a shell keyword
until is a shell keyword

```

### 4. Linux shell 函数

一个 shell 函数是一组在当前 shell 内一起执行的命令。函数有利于在 shell 脚本中实现特殊任务。在 shell 脚本中写 shell 函数的传统形式是下面这样：

```
function_name() {
command1
command2
......
}

```

或者像这样：

```
function function_name {
command1
command2
......
}

```

让我们看一看如何在一个名为 shell\_functions.sh 的脚本中写 shell 函数。

```
#!/bin/bash
#write a shell function to update and upgrade installed packages
upgrade_system(){
sudo apt update;
sudo apt dist-upgrade;
}
#execute function
upgrade_system

```

取代通过命令行执行两条命令：`sudo apt update` 和 `sudo apt dist-upgrade`，我们在脚本内写了一个像执行一条单一命令一样来执行两条命令的 shell 函数 upgrade\_system。

保存文件，然后使脚本可执行。最后像下面这样运行 shell 函数：

```
$ chmod +x shell_functions.sh
$ ./shell_functions.sh

```

### 5. Linux Shell 内置命令

这些是在 shell 中内置的 Linux 命令，所以你无法在文件系统中找到它们。这些命令包括 `pwd`、`cd`、`bg`、`alias`、`history`、`type`、`source`、`read`、`exit` 等。

你可以通过下面展示的 `type` 命令来列出或检查 Linux 内置命令：

```
$ type pwd
pwd is a shell builtin
$ type cd
cd is a shell builtin
$ type bg
bg is a shell builtin
$ type alias
alias is a shell builtin
$ type history
history is a shell builtin

```

学习一些 Linux 内置命令用法：

* [Linux 下 15 个 pwd 命令例子](http://www.tecmint.com/pwd-command-examples/)
* [Linux 下 15 个 cd 命令例子](http://www.tecmint.com/cd-command-in-linux/)
* [了解 Linux 下 history 命令的威力](http://www.tecmint.com/history-command-examples/)

### 结论

作为一个 Linux 用户，知道你所运行的命令类型是很重要的。我相信，通过上面明确、简单并且易于理解的解释，包括一些相关的说明，你可能对 “[Linux 命令的不同种类](http://www.tecmint.com/different-types-of-linux-shells/)”有了很好的理解。

你也可以在下面的评论区提任何问题或补充意见，从而和我们取得联系。

---

via: <http://www.tecmint.com/understanding-different-linux-shell-commands-usage/>

作者：[Aaron Kili](http://www.tecmint.com/author/aaronkili/)  译者：[ucasFL](https://github.com/ucasFL) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


漫游 HTTP/2

Summary: 到现在 HTTP/2 已经完全超越了 SPDY，并且还在不断成长，HTTP/2 有很多关系性能的提升，我们应该开始布署它了。

# 漫游 HTTP/2

自从我写了上一篇博文之后，就再也找不到空闲时间写文章了。今天我终于可以抽出时间写一些关于 HTTP 的东西。

我认为每一个 web 开发者都应该对这个支撑了整个 Web 世界的 HTTP 协议有所了解，这样才能帮助你更好的完成开发任务。

在这篇文章中，我将讨论什么是 HTTP，它是怎么产生的，它的地位，以及我们应该怎么使用它。

### HTTP 是什么

首先我们要明白 HTTP 是什么。HTTP 是一个基于 `TCP/IP` 的应用层通信协议，它是客户端和服务端在互联网互相通讯的标准。它定义了内容是如何通过互联网进行请求和传输的。HTTP 是在应用层中抽象出的一个标准，使得主机（客户端和服务端）之间的通信得以通过 `TCP/IP` 来进行请求和响应。TCP 默认使用的端口是 `80`，当然也可以使用其它端口，比如 HTTPS 使用的就是 `443` 端口。

### `HTTP/0.9` - 单行协议 (1991)

HTTP 最早的规范可以追溯到 1991 年，那时候的版本是 `HTTP/0.9`，该版本极其简单，只有一个叫做 `GET`的请求方式。如果客户端要访问服务端上的一个页面，只需要如下非常简单的请求：

```
GET /index.html

```

服务端对应的返回类似如下：

```
(response body)
(connection closed)

```

就这么简单，服务端捕获到请求后立马返回 HTML 并且关闭连接，在这之中

* 没有<ruby> 头信息 <rp>  （ </rp> <rt>  headers </rt> <rp>  ） </rp></ruby>
* 仅支持 `GET` 这一种请求方法
* 必须返回 HTML

如同你所看到的，当时的 HTTP 协议只是一块基础的垫脚石。

### HTTP/1.0 - 1996

在 1996 年，新版本的 HTTP 对比之前的版本有了极大的改进，同时也被命名为 `HTTP/1.0`。

与 `HTTP/0.9` 只能返回 HTML 不同的是，`HTTP/1.0` 支持处理多种返回的格式，比如图片、视频、文本或者其他格式的文件。它还增加了更多的请求方法（如 `POST` 和 `HEAD`），请求和响应的格式也相应做了改变，两者都增加了头信息；引入了状态码来定义返回的特征；引入了字符集支持；支持<ruby> 多段类型 <rp>  （ </rp> <rt>  multi-part </rt> <rp>  ） </rp></ruby>、用户验证信息、缓存、内容编码格式等等。

一个简单的 HTTP/1.0 请求大概是这样的：

```
GET / HTTP/1.0
Host: kamranahmed.info
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
Accept: */*

```

正如你所看到的，在请求中附带了客户端中的一些个人信息、响应类型要求等内容。这些是在 `HTTP/0.9` 无法实现的，因为那时候没有头信息。

一个对上述请求的响应例子如下所示：

```
HTTP/1.0 200 OK
Content-Type: text/plain
Content-Length: 137582
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84

(response body)
(connection closed)

```

从 `HTTP/1.0` （HTTP 后面跟的是版本号）早期开始，在状态码 `200` 之后就附带一个原因短语（你可以用来描述状态码）。

在这个较新一点的版本中，请求和响应的头信息仍然必须是 `ASCII` 编码，但是响应的内容可以是任意类型，如图片、视频、HTML、文本或其他类型，服务器可以返回任意内容给客户端。所以这之后，`HTTP` 中的“<ruby> 超文本 <rp>  （ </rp> <rt>  Hyper Text </rt> <rp>  ） </rp></ruby>”成了名不副实。 `HMTP` （<ruby> 超媒体传输协议 <rp>  （ </rp> <rt>  Hypermedia transfer protocol </rt> <rp>  ） </rp></ruby>）可能会更有意义，但是我猜我们还是会一直沿用这个名字。

`HTTP/1.0` 的一个主要缺点就是它不能在一个连接内拥有多个请求。这意味着，当客户端需要从服务器获取东西时，必须建立一个新的 TCP 连接，并且处理完单个请求后连接即被关闭。需要下一个东西时，你必须重新建立一个新的连接。这样的坏处在哪呢？假设你要访问一个有 `10` 张图片，`5` 个<ruby> 样式表 <rp>  （ </rp> <rt>  stylesheet </rt> <rp>  ） </rp></ruby>和 `5` 个 JavaScript 的总计 `20` 个文件才能完整展示的一个页面。由于一个连接在处理完成一次请求后即被关闭，所以将有 `20` 个单独的连接，每一个文件都将通过各自对应的连接单独处理。当连接数量变得庞大的时候就会面临严重的性能问题，因为 `TCP` 启动需要经过三次握手，才能缓慢开始。

#### 三次握手

三次握手是一个简单的模型，所有的 `TCP` 连接在传输应用数据之前都需要在三次握手中传输一系列数据包。

* `SYN` - 客户端选取一个随机数，我们称为 `x`，然后发送给服务器。
* `SYN ACK` - 服务器响应对应请求的 `ACK` 包中，包含了一个由服务器随机产生的数字，我们称为 `y`，并且把客户端发送的 `x+1`，一并返回给客户端。
* `ACK` - 客户端在从服务器接受到 `y` 之后把 `y` 加上 `1` 作为一个 `ACK` 包返回给服务器。

一旦三次握手完成后，客户端和服务器之间就可以开始交换数据。值得注意的是，当客户端发出最后一个 `ACK` 数据包后，就可以立刻向服务器发送应用数据包，而服务器则需要等到收到这个 `ACK` 数据包后才能接受应用数据包。

>
> 请注意，上图有点小问题，客户端发回的最后一个 ACK 包仅包含 `y+1`，上图应该是 `ACK:y+1` 而不是 `ACK:x+1,y+1`
>
>
>

然而，某些 HTTP/1.0 的实现试图通过新引入一个称为 `Connection: keep-alive` 的头信息来克服这一问题，这个头信息意味着告诉服务器“嘿，服务器，请不要关闭此连接，我还要用它”。但是，这并没有得到广泛的支持，问题依然存在。

除了无连接之外，HTTP 还是一个无状态的协议，即服务器不维护有关客户端的信息。因此每个请求必须给服务器必要的信息才能完成请求，每个请求都与之前的旧的请求无关。所以，这增加了推波助澜的作用，客户端除了需要新建大量连接之外，在每次连接中还需要发送许多重复的数据，这导致了带宽的大量浪费。

### `HTTP/1.1` - 1999

`HTTP/1.0` 经过仅仅 3 年，下一个版本，即 `HTTP/1.1` 就在 1999 年发布了，改进了它的前身很多问题，主要的改进包括：

* **增加了许多 HTTP 请求方法**，包括 `PUT`、`PATCH`、`HEAD`、`OPTIONS`、`DELETE`。
* **主机标识符** `Host` 在 `HTTP/1.0` 并不是必须的，而在 `HTTP/1.1` 是必须的。
* 如上所述的**持久连接**。在 `HTTP/1.0` 中每个连接只有一个请求并在该请求结束后被立即关闭，这导致了性能问题和增加了延迟。 `HTTP/1.1` 引入了持久连接，即连接在默认情况下是不关闭并保持开放的，这允许多个连续的请求使用这个连接。要关闭该连接只需要在头信息加入 `Connection: close`，客户通常在最后一个请求里发送这个头信息就能安全地关闭连接。
* 新版本还引入了“<ruby> 管线化 <rp>  （ </rp> <rt>  pipelining </rt> <rp>  ） </rp></ruby>”的支持，客户端可以不用等待服务器返回响应，就能在同一个连接内发送多个请求给服务器，而服务器必须以接收到的请求相同的序列发送响应。但是你可能会问了，客户端如何知道哪里是第一个响应下载完成而下一个响应内容开始的地方呢？要解决这个问题，头信息必须有 `Content-Length`，客户可以使用它来确定哪些响应结束之后可以开始等待下一个响应。
	+ 值得注意的是，为了从持久连接或管线化中受益， 头部信息必须包含 `Content-Length`，因为这会使客户端知道什么时候完成了传输，然后它可以发送下一个请求（持久连接中，以正常的依次顺序发送请求）或开始等待下一个响应（启用管线化时）。
	+ 但是，使用这种方法仍然有一个问题。那就是，如果数据是动态的，服务器无法提前知道内容长度呢？那么在这种情况下，你就不能使用这种方法中获益了吗？为了解决这个问题，`HTTP/1.1` 引进了分块编码。在这种情况下，服务器可能会忽略 `Content-Length` 来支持分块编码（更常见一些）。但是，如果它们都不可用，那么连接必须在请求结束时关闭。
* 在动态内容的情况下**分块传输**，当服务器在传输开始但无法得到 `Content-Length` 时，它可能会开始按块发送内容（一块接一块），并在传输时为每一个小块添加 `Content-Length`。当发送完所有的数据块后，即整个传输已经完成后，它发送一个空的小块，比如设置 `Content-Length` 为 0 ，以便客户端知道传输已完成。为了通知客户端块传输的信息，服务器在头信息中包含了 `Transfer-Encoding: chunked`。
* 不像 HTTP/1.0 中只有 Basic 身份验证方式，`HTTP/1.1` 包括<ruby> 摘要验证方式 <rp>  （ </rp> <rt>  digest authentication </rt> <rp>  ） </rp></ruby>和<ruby> 代理验证方式 <rp>  （ </rp> <rt>  proxy authentication </rt> <rp>  ） </rp></ruby>。
* 缓存。
* <ruby> 范围请求 <rp>  （ </rp> <rt>  Byte Ranges </rt> <rp>  ） </rp></ruby>。
* 字符集。
* <ruby> 内容协商 <rp>  （ </rp> <rt>  Content Negotiation </rt> <rp>  ） </rp></ruby>。
* 客户端 cookies。
* 支持压缩。
* 新的状态码。
* 等等。

我不打算在这里讨论所有 `HTTP/1.1` 的特性，因为你可以围绕这个话题找到很多关于这些的讨论。我建议你阅读 [`HTTP/1.0` 和 `HTTP/1.1` 版本之间的主要差异](http://www.ra.ethz.ch/cdstore/www8/data/2136/pdf/pd1.pdf)，希望了解更多可以读[原始的 RFC](https://tools.ietf.org/html/rfc2616)。

`HTTP/1.1` 在 1999 年推出，到现在已经是多年前的标准。虽然，它比前一代改善了很多，但是网络日新月异，它已经垂垂老矣。相比之前，加载网页更是一个资源密集型任务，打开一个简单的网页已经需要建立超过 30 个连接。你或许会说，`HTTP/1.1` 具有持久连接，为什么还有这么多连接呢？其原因是，在任何时刻 `HTTP/1.1` 只能有一个未完成的连接。 `HTTP/1.1` 试图通过引入管线来解决这个问题，但它并没有完全地解决。因为一旦管线遇到了缓慢的请求或庞大的请求，后面的请求便被阻塞住，它们必须等待上一个请求完成。为了克服 `HTTP/1.1` 的这些缺点，开发人员开始实现一些解决方法，例如使用 spritesheets、在 CSS 中编码图像、单个巨型 CSS / JavaScript 文件、[域名切分](https://www.maxcdn.com/one/visual-glossary/domain-sharding-2/)等。

### SPDY - 2009

谷歌走在业界前列，为了使网络速度更快，提高网络安全，同时减少网页的等待时间，他们开始实验替代的协议。在 2009 年，他们宣布了 `SPDY`。

>
> `SPDY` 是谷歌的商标，而不是一个缩写。
>
>
>

显而易见的是，如果我们继续增加带宽，网络性能开始的时候能够得到提升，但是到了某个阶段后带来的性能提升就很有限了。但是如果把这些优化放在等待时间上，比如减少等待时间，将会有持续的性能提升。这就是 `SPDY` 优化之前的协议的核心思想，减少等待时间来提升网络性能。

>
> 对于那些不知道其中区别的人，等待时间就是延迟，即数据从源到达目的地需要多长时间（单位为毫秒），而带宽是每秒钟数据的传输量（比特每秒）。
>
>
>

`SPDY` 的特点包括：复用、压缩、优先级、安全性等。我不打算展开 `SPDY` 的细节。在下一章节，当我们将介绍 `HTTP/2`，这些都会被提到，因为 `HTTP/2` 大多特性是从 `SPDY` 受启发的。

`SPDY` 没有试图取代 HTTP，它是处于应用层的 HTTP 之上的一个传输层，它只是在请求被发送之前做了一些修改。它开始成为事实标准，大多数浏览器都开始支持了。

2015年，谷歌不想有两个相互竞争的标准，所以他们决定将其合并到 HTTP 协议，这样就导致了 `HTTP/2` 的出现和 `SPDY` 的废弃。

### `HTTP/2` - 2015

现在想必你明白了为什么我们需要另一个版本的 HTTP 协议了。 `HTTP/2` 是专为了低延迟地内容传输而设计。主要特点和与 `HTTP/1.1` 的差异包括：

* 使用二进制替代明文
* 多路传输 - 多个异步 HTTP 请求可以使用单一连接
* 报头使用 HPACK 压缩
* 服务器推送 - 单个请求多个响应
* 请求优先级
* 安全性

#### 1. 二进制协议

`HTTP/2` 通过使其成为一个二进制协议以解决 HTTP/1.x 中存在的延迟问题。作为一个二进制协议，它更容易解析，但可读性却不如 `HTTP/1.x`。<ruby> 帧 <rp>  （ </rp> <rt>  frames </rt> <rp>  ） </rp></ruby>和<ruby> 流 <rp>  （ </rp> <rt>  stream </rt> <rp>  ） </rp></ruby>的概念组成了 `HTTP/2` 的主要部分。

**帧和流**

现在 HTTP 消息是由一个或多个帧组成的。`HEADERS` 帧承载了<ruby> 元数据 <rp>  （ </rp> <rt>  meta data </rt> <rp>  ） </rp></ruby>，`DATA` 帧则承载了内容。还有其他类型的帧（`HEADERS`、`DATA`、`RST_STREAM`、`SETTINGS`、`PRIORITY` 等等），这些你可以通过 [HTTP/2 规范](https://http2.github.io/http2-spec/#FrameTypes)来了解。

每个 `HTTP/2` 请求和响应都被赋予一个唯一的流 ID，并切分成帧。帧就是一小片二进制数据。帧的集合称为流，每个帧都有个标识了其所属流的流 ID，所以在同一个流下的每个帧具有共同的报头。值得注意的是，除了流 ID 是唯一的之外，由客户端发起的请求使用了奇数作为流 ID，从来自服务器的响应使用了偶数作为流 ID。

除了 `HEADERS` 帧和 `DATA` 帧，另一个值得一提的帧是 `RST_STREAM`。这是一个特殊的帧类型，用来中止流，即客户可以发送此帧让服务器知道，我不再需要这个流了。在 `HTTP/1.1` 中让服务器停止给客户端发送响应的唯一方法是关闭连接，这样造成了延迟增加，因为之后要发送请求时，就要必须打开一个新的请求。而在 `HTTP/2`，客户端可以使用 `RST_STREAM` 来停止接收特定的数据流，而连接仍然打开着，可以被其他请求使用。

#### 2. 多路传输

因为 `HTTP/2` 是一个二进制协议，而且如上所述它使用帧和流来传输请求与响应，一旦建立了 TCP 连接，相同连接内的所有流都可以同过这个 TCP 连接异步发送，而不用另外打开连接。反过来说，服务器也可以使用同样的异步方式返回响应，也就是说这些响应可以是无序的，客户端使用分配的流 ID 来识别数据包所属的流。这也解决了 HTTP/1.x 中请求管道被阻塞的问题，即客户端不必等待占用时间的请求而其他请求仍然可以被处理。

#### 3. HPACK 请求头部压缩

RFC 花了一篇文档的篇幅来介绍针对发送的头信息的优化，它的本质是当我们在同一客户端上不断地访问服务器时，许多冗余数据在头部中被反复发送，有时候仅仅是 cookies 就能增加头信息的大小，这会占用许多宽带和增加传输延迟。为了解决这个问题，`HTTP/2` 引入了头信息压缩。

不像请求和响应那样，头信息中的信息不会以 `gzip` 或者 `compress` 等格式压缩。而是采用一种不同的机制来压缩头信息，客户端和服务器同时维护一张头信息表，储存了使用了哈夫曼编码进行编码后的头信息的值，并且后续请求中若出现同样的字段则忽略重复值（例如<ruby> 用户代理 <rp>  （ </rp> <rt>  user agent </rt> <rp>  ） </rp></ruby>等），只发送存在两边信息表中它的引用即可。

我们说的头信息，它们同 `HTTP/1.1` 中一样，并在此基础上增加了一些伪头信息，如 `:scheme`，`:host` 和 `:path`。

#### 4. 服务器推送

服务器推送是 `HTTP/2` 的另一个巨大的特点。对于服务器来说，当它知道客户端需要一定的资源后，它可以把数据推送到客户端，即使客户端没有请求它。例如，假设一个浏览器在加载一个网页时，它解析了整个页面，发现有一些内容必须要从服务端获取，然后发送相应的请求到服务器以获取这些内容。

服务器推送减少了传输这些数据需要来回请求的次数。它是如何做到的呢？服务器通过发送一个名字为 `PUSH_PROMISE` 特殊的帧通知到客户端“嘿，我准备要发送这个资源给你了，不要再问我要了。”这个 `PUSH_PROMISE` 帧与要产生推送的流联系在一起，并包含了要推送的流 ID，也就是说这个流将会被服务器推送到客户端上。

#### 5. 请求优先级

当流被打开的时候，客户端可以在 `HEADERS` 帧中包含优先级信息来为流指定优先级。在任何时候，客户端都可以发送 `PRIORITY` 帧来改变流的优先级。

如果没有任何优先级信息，服务器将异步地无序地处理这些请求。如果流分配了优先级，服务器将基于这个优先级来决定需要分配多少资源来处理这个请求。

#### 6. 安全性

在是否强制使用 `TLS` 来增加安全性的问题上产生了大范围的讨论，讨论的结果是不强制使用。然而大多数厂商只有在使用 `TLS` 时才能使用 `HTTP/2`。所以 `HTTP/2` 虽然规范上不要求加密，但是加密已经约定俗成了。这样，在 `TLS` 之上实现 `HTTP/2` 就有了一些强制要求，比如，`TLS` 的最低版本为 `1.2`，必须达到某种级别的最低限度的密钥大小，需要布署 ephemeral 密钥等等。

到现在 `HTTP/2` 已经[完全超越了 SPDY](http://caniuse.com/#search=http2)，并且还在不断成长，HTTP/2 有很多关系性能的提升，我们应该开始布署它了。

如果你想更深入的了解细节，请访问[该规范的链接](https://http2.github.io/http2-spec)和 [HTTP/2 性能提升演示的链接](http://www.http2demo.io/)。请在留言板写下你的疑问或者评论，最后如果你发现有错误，请同样留言指出。

这就是全部了，我们之后再见~

---

via: <http://kamranahmed.info/blog/2016/08/13/http-in-depth/>

作者：[Kamran Ahmed](http://github.com/kamranahmedse) 译者：[NearTan](https://github.com/NearTan) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


是时候合并 LibreOffice 和 OpenOffice 了

wps linux版也不错啊，没见有人提过

wps 不是開源軟件。

界面丑+1， 所以我一般都用wps for linux，做得很用心

LibreOffice我只用来打开奇怪的文件，然后转pdf，开源软件强迫症我已痊愈了。

另外一个不是开源的linux软件被频频提及，虽然它已经没有用了——QQ for linux

calligra也一起来合并吧

不错的提议@！~

libreoffice其实挺好用的。经常用。不过在windows一般般经常卡顿。在linux上就是神器了。就差字体了

然而那是 adware。

然而你是win用户，哈哈

话说 WPS 老弹窗，还建议我安装其他软件，说需要我的支持 WPS 才能更好的走下去。我很有罪恶感啊，为了不妨碍 WPS 走下去，我 win 下用了永中 office，linux 下用了 libreoffice。

同意，虽然我还在用。。。

来自112.51.26.78的 Chrome Mobile 51.0|Android 6.0 用户

赞一个，开发者都不容易。

界面真的太过时了。而且跟各个主流桌面环境都不搭。

问个问题：这俩开源软件，怎么赚钱？毕竟那么多开发人员，工资谁发？

都在说界面，我觉得LibreOffice现在的界面挺好的，win上、linux上都用的它，难道我的思想太落伍了？

Caligra 是 KDE 自家的项目，人家才不稀罕呢

LibreOffice汇出所有设定

LibreOffice的所有设定，都放在LibreOffice资料夹里。

C:\Users←使用者。 \a←安装作业系统的时候，输入的名称。 \AppData←档案总管〜『隐藏的项目』要开启，才会显示AppData资料夹。 \Roaming\LibreOffice

备份LibreOffice资料夹，重新安装的时候，再把LibreOffice资料夹，放到原来的地方。

注：

1、如果安装的是预览版，因为预览版的名称是LibreOfficeDev，所以会显示LibreOfficeDev资料夹。

2、正式版跟预览版可以一起安装，如果正式版跟预览版都安装的话，就会显示LibreOffice资料夹跟LibreOfficeDev资

# 是时候合并 LibreOffice 和 OpenOffice 了

先说下 OpenOffice。可能你已经无数次地看到说 Apache OpenOffice [即将结束](/article-7741-1.html)。上一个稳定版本是 4.1.2 （发布于 2015 年 10 月），而最近的一个严重安全漏洞用了一个月才打上补丁。编码人员的缺乏使得开发如爬行前进一般。然后，可能是最糟糕的消息了：这个项目建议用户切换到 [MS Office](https://products.office.com/)（或 [LibreOffice](https://www.libreoffice.org/download/))。

丧钟为谁而鸣？丧钟为你而鸣，OpenOffice。

我想说些可能会惹恼一些人的话。你准备好了吗？

OpenOffice 的终止对开源和用户来说都将是件好事。

让我解释一下。

### 一个分支统治所有

当 LibreOffice 从 OpenOffice 分支出来后，我们看到了另一个情况：分支不只在原始基础上进行改进，而且大幅超越了它。LibreOffice 一举成功。所有之前预装 OpenOffice 的 Linux 发行版都迁移到了这个新项目。LibreOffice 从起跑线突然冲出，并迅速迈出了一大步。更新以极快的速度发布，改善内容丰富而重要。

不久后，OpenOffice 就被开源社区丢在了脑后。当 2011 年 Oracle 决定终止这个项目并把代码捐赠给 Apache 项目时，这种情况自然更加恶化了。从此 OpenOffice 艰难前进，然后把我们就看到了现在这种局面：一个生机勃勃的 LibreOffice 和一个艰难的、缓慢的 OpenOffice。

但我认为在这个相当昏暗的隧道末尾有一丝曙光。

### 合并他们

这听起来可能很疯狂，但我认为是时候把 LibreOffice 和 OpenOffice 合二为一了。是的，我知道很可能有政治考虑和自尊意识，但我认为合并成一个会更好。合并的好处很多。我首先能想到的是：

* 把 MS Office 过滤器整合起来：OpenOffice 在更好地导入某些 MS Office 文件上功能很强（而众所周知 LibreOffice 正在改进，但时好时坏）
* LibreOffice 有更多开发者：尽管 OpenOffice 的开发者数量不多，但也无疑会增加到合并后的项目。
* 结束混乱：很多用户以为 OpenOffice 和 LibreOffice 是同一个东西。有些甚至不知道 LibreOffice 存在。这将终结那些混乱。
* 合并他们的用户量：OpenOffice 和 LibreOffice 各自拥有大量用户。联合后，他们将是个巨大的力量。

### 宝贵机遇

OpenOffice 的终止实际上会成为整个开源办公套件行业的一个宝贵机遇。为什么？我想表明有些东西我认为已经需要很久了。如果 OpenOffice 和 LibreOffice 集中他们的力量，比较他们的代码并合并，他们之后就可以做一些更必要的改进工作，不仅是整体的内部工作，也包括界面。

我们得面对现实，LibreOffice 和（相关的） OpenOffice 的用户界面都是过时的。当我安装 LibreOffice 5.2.1.2 时，工具栏绝对是个灾难（见下图）。

*LibreOffice 默认工具栏显示*

尽管我支持和关心（并且日常使用）LibreOffice，但事实已经再清楚不过了，界面需要完全重写。我们正在使用的是 90 年代末/ 2000 年初的复古界面，它必须得改变了。当新用户第一次打开 LibreOffice 时，他们会被淹没在大量按钮、图标和工具栏中。Ubuntu Unity 的平视显示（Head up Display，简称 HUD）帮助解决了这个问题，但那并不适用于其它桌面和发行版。当然，有经验的用户知道在哪里找什么（甚至定制工具栏以满足特殊的需要），但对新用户或普通用户，那种界面是个噩梦。现在是做出改变的一个好时机。引入 OpenOffice 最后残留的开发者并让他们加入到改善界面的战斗中。借助于整合 OpenOffice 额外的导入过滤器和现代化的界面，LibreOffice 终能在家庭和办公桌面上都引起一些轰动。

### 这会真的发生吗？

这需要发生。但是会发生吗？我不知道。但即使掌权者决定用户界面并不需要重组（这会是个失误），合并 OpenOffice 仍是前进的一大步。合并两者将带来开发的更专注，更好的推广，公众更少的困惑。

我知道这可能看起来有悖于开源的核心精神，但合并 LibreOffice 和 OpenOffice 将能联合两者的力量，而且可能会摆脱弱点。

在我看来，这是双赢的。

---

via: <http://www.techrepublic.com/article/its-time-to-make-libreoffice-and-openoffice-one-again/>

作者：[Jack Wallen](http://www.techrepublic.com/search/?a=jack%2Bwallen)  译者：[bianjp](https://github.com/bianjp) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


5 个值得了解的 Linux 服务器发行版

没有debian吗？

Ubuntu 都有  居然没有Debian  何解

CentOS 7支撑着我家的路由

来自山东青岛的 Chrome Mobile iOS 53.0|iOS 10.0 用户

Debian在服务器上的表现真不怎么样。1、支持周期太短只有2-3年

2、易维护性同比较差

3、软件包更新有时候并不严格维护ABI/API兼容

下面是解释。Debian在版本支持周期外额外提供两年的"LTS"支持，这个LTS跟一般理解的LTS有些差异，大概就是只提供非常要命的安全补丁，一些小问题都不会修复。易维护性主要体现在自带套件上，RHEL、SUSE提供了非常多运维友好的套件，这里面甚至有一些是非自由的。第三点是社区的锅，毕竟纯社区运作无责任为你的数据安全负责。

感觉Ubuntu是从桌面版学习转向专业级服务器版的一个重要跳板

# 5 个值得了解的 Linux 服务器发行版

>
> 你在 Distrowatch.com 上看到列出的将近 300 个 Linux 发行版本中，几乎任何一个发行版都可以被用来作为服务器系统。下面是一些相对于其他发行版而言比较突出的一些发行版。
>
>
>

<img src="content_image/album_201609_27_195515uun7unfdbacfdecf.jpg" alt="" title="">

你在 Distrowatch.com 上看到列出的将近 300 个 Linux 发行版本中，几乎任何一个发行版都可以被用来作为服务器系统，在 Linux 发展的早期，给用户提供的一直是“全能”发行版，例如 Slackware、Debian 和 Gentoo 可以为家庭和企业作为服务器完成繁重的工作。那或许对业余爱好者是不错的，但是它对于专业人员来说也有好多不必要的地方。

首先，这里有一些发行版可以作为文件和应用服务器，给工作站提供常见外围设备的共享，提供网页服务和其它我们希望服务器做的任何工作，不管是在云端、在数据中心或者在服务器机架上，除此之外没有别的用途。

下面是 5 个最常用的 Linux 发行版的简单总结，而且每一个发行版都可以满足小型企业的需求。

### Red Hat Enterprise Linux（RHEL）

这或许是最有名的 Linux 服务器发行版了。RHEL 以它在高要求的至关重要的任务上坚如磐石的稳定性而出名，例如运行着纽约证券交易系统。红帽也提供了业内最佳的服务支持。

那么红帽 Linux 的缺点都有什么呢？ 尽管红帽以提供首屈一指的客户服务和支持而出名，但是它的支持订阅费用并不便宜。有人可能会指出，这的确物有所值。确实有便宜的 RHEL 第三方服务，但是你或许应该在这么做之前做一些研究。

### CentOS

任何喜欢 RHEL，但是又不想给红帽付费来获得支持的人都应该了解一下 CentOS，它基本上是红帽企业版 Linux 的一个分支。尽管这个项目 2004 年左右才开始，但它在 2014 年得到了红帽的官方支持，而它现在雇佣可这个项目的大多数开发者，这意味着安全补丁和漏洞修复提交到红帽不久后就会在 CentOS 上可用。

如果你想要部署 CentOS，你将需要有 Linux 技能的员工，因为没有了技术支持，你基本上只能靠自己。有一个好消息是 CentOS 社区提供了十分丰富的资源，例如邮件列表、Web 论坛和聊天室，所以对那些寻找帮助的人来说，社区帮助还是有的。

### Ubuntu Server

当许多年前 Canonical 宣布它将要推出一个服务器版本的 Ubuntu 的时候，你可能会听到过嘲笑者的声音。然而嘲笑很快变成了惊奇，Ubuntu Server 迅速地站稳了脚跟。部分原因是因为其来自 Debian 派生的基因，Debian 长久以来就是一个备受喜爱的 Linux 服务器发行版，Ubuntu 通过提供一般人可以支付的起的技术支持费用、优秀的硬件支持、开发工具和很多亮点填补了这个市场空隙。

那么 Ubuntu Server 有多么受欢迎呢？最近的数据表明它正在成为在 OpenStack 和 Amazon Elastic Compute Cloud 上[部署最多的操作系统](http://www.zdnet.com/article/ubuntu-linux-continues-to-dominate-openstack-and-other-clouds/)。在那里 Ubuntu Server 超过了位居第二的 Amazon Linux 的 Amazon Machine Image 一大截，而且让第三位 Windows 处于尘封的地位。另外一个调查显示 Ubuntu Server 是[使用最多的 Linux web 服务器](https://w3techs.com/technologies/details/os-linux/all/all)。

### SUSE Linux Enterprise Server（SLES）

这个源自德国的发行版在欧洲有很大的用户群，而且在本世纪初由 Novell 公司引起的 PR 问题出现之前，它一直都是大西洋这边的排名第一服务器发行版。在那段漫长的时期之后，SUSE 在美国获得了发展，而且它的使用或许加速了惠普企业公司将它作为 [Linux 首选合作伙伴](http://windowsitpro.com/industry/suse-now-hpes-preferred-partner-micro-focus-pact)。

SLES 稳定而且易于维护，这正是很久以来对于一个好的 Linux 发行版所期待的东西。付费的 7\*24 小时快速响应技术支持可以供你选择，使得这发行版很适合关键任务的部署。

### ClearOS

基于 RHEL，之所以这里要包括 [ClearOS](https://www.clearos.com/) 是因为它对于每个人来说都足够简单，甚至是没有专业知识的人都可以去配置它。它定位于服务中小型企业，它也可以被家庭用户用来作为娱乐服务器，为了简单易用我们可以基于 Web 界面进行管理，它是以“构建你的 IT 基础设施应该像在智能手机上下载 app 一样简单”为前提来定制的。

最新的 7.2 发行版本，包括了一些可能并不“轻量级”的功能，例如对微软 Hyper-V 技术的 VM 支持，支持 XFS 和 BTRFS 文件系统，也支持 LVM 和 IPv6。这些新特性在免费版本或者在并不算贵的带着各种支持选项的专业版中都是可用的。

---

via: <http://windowsitpro.com/industry/five-linux-server-distros-worth-checking-out>

作者：[Christine Hall](http://windowsitpro.com/industry/five-linux-server-distros-worth-checking-out) 译者：[LinuxBars](https://github.com/LinuxBars) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Mozilla 将封杀沃通和 StartSSL 一年内新签发的所有证书

邻站 OSC 就使用的 WoSign 签署的证书，而且还是 http 和 https 混用。

关于这个严肃的问题，大家可以看看 Ubuntu中文论坛 的这个帖子，就知道始末了

http://forum.ubuntu.org.cn/viewtopic.php?f=126&t=475291

草 我们公司以前就是用的wosign，后来换赛门铁克了好像

中枪！我去，这事儿什么时候会定，我需要换证书了orz...

这是个严重问题呀

要是chrome也这么积极就好了<br />
不过chrome毕竟安全上可以将就一下的

本来已经准备采购的，合同都谈好了，还好看到这个新闻！

还好还好！

# Mozilla 将封杀沃通和 StartSSL 一年内新签发的所有证书

Firefox 浏览器背后的 Mozilla 基金会正在考虑对沃通（WoSign）及被其秘密收购的 StartCom（著名的 StartSSL 即其旗下产品）这两个 CA 一年内新签发的所有 SSL 证书进行封杀。

Mozilla 的工程师是在对这两个 CA 签发了一系列可疑的 SSL SHA-1 证书进行调查之后，宣布了这个禁令。

<img src="content_image/album_201609_27_235231v37ur7524fndn4n6.jpg" alt="" title="">

### 这两家 CA 试图规避 SHA-1 停用政策

该问题主要是因为各大主要浏览器厂商共同决定从 2016 年 1 月 1 日开始就停止接受采用陈旧的 SHA-1 签名算法的证书。而 Mozilla 指责沃通今年还在签发 SHA-1 签名的证书，并将签发日期倒填成去年 12 月份。

虽然 Mozilla 也允许一些其它的 CA 在 2016 年 1 月 1 日之后继续签发 SHA-1 证书，比如说[赛门铁克](http://news.softpedia.com/news/mozilla-gives-a-security-pass-to-the-people-it-shouldn-t-500986.shtml)，但是他们仅允许那些通过了复杂的审批流程的 CA 这样做，而显然沃通没有得到同意。

### 沃通秘密收购了 StartCom

此外，沃通似乎在否认其收购了以色列 CA 公司 StartCom。Mozilla 说，沃通已经于 2015 年 11 月 1 日百分百地收购了 StartCom。而另一方面，[据奇虎 360 称](http://www.solidot.org/story?sid=49774)，它共计持有 84% 的沃通股份。但是这些信息沃通此前都予以否认或拒绝发表意见。

此外，在 Mozilla 披露的技术细节中显示，StartCom 已经开始使用沃通的基础架构来签发新的证书了。而且，StartCom 也和沃通一样在 2016 年采用了倒填日期的手段来签发 SHA-1 证书。Mozilla 的安全工程师也展示了这种违例的案例细节。

Mozilla 的调查发现，一个和 GeoTrust CA 合作了多年的付费处理机构 Tyro 突然在 6 月中旬使用 StartCom 部署了一个 SHA-1 签名的证书，而此前该机构从未和 StartCom 有过合作。该证书看起来是在 2015 年 12 月 20 日签发的，而在同一个日期 StartCom 签发大量的 SHA-1 证书。Mozlla 发现这些证书部署于 2016 年中，这很不正常，这显然是采用倒填日期来规避 SHA-1 停用的策略。

这些问题以及其它的[更多问题](https://wiki.mozilla.org/CA:WoSign_Issues)让 Mozilla 决定在至少一年内不再信任沃通和 StartCom 的 SSL 证书。

### 或许会永久封杀

Mozilla 说这个临时封杀仅针对这两个公司最新签发的证书，不影响已经分发给他们的客户的证书。如果这两个公司在一年的封杀后没有通过一系列的检查，Mozilla 将准备封杀这两个公司的所有证书。

“许多人都在盯着 Web PKI 安全体系，如果发现了这样的倒填（不管是什么原因），Mozilla 会立即永久地取消对沃通和 StartCom 根证书的信任。”该[报告](https://docs.google.com/document/d/1C6BlmbeQfn4a9zydVi2UvjBGv6szuSB4sMYUcVrR8vQ/preview#)中说。

此外，Chrome 和其它产品的对它们的封杀也在计划中。“其它的浏览器厂商和根证书存储运营者也会做出他们自己的决定，我们在这个文档中摆出了这些信息，以便他们了解我们做出这个决定的原因，并可以据此做出他们的决定。”Mozilla 说。


关于“Linux中国” RSS 的一个调查问卷，如果你在用，请来看看

2, 2.1

我不知道有这个东西，但是告诉我地址我会去弄懂怎么订阅！加油

2.2 我要全文，打开浏览器有点麻烦

来自广东广州的 Chrome Mobile 37.0|Android 6.0 用户

2.2 我要全文，打开浏览器有点麻烦： 我之前是用脚本来看，不过自从更新有延迟后就少用了。

RSS 订阅还是要全文的，毕竟我不喜欢再打开浏览器

基本都是每天打开浏览器看的

2.1、RSS 订阅中有标题和摘要就行了，感兴趣我会点击链接的

2、我已经订阅了“Linux 中国”的 RSS<br />
有没有全文无所谓

2. 我已经订阅了“Linux中国”的RSS<br />
订阅中还是有全文吧，比较方便。

2.2、RSS 订阅还是要全文的，毕竟我不喜欢再打开浏览器

不会订阅

订阅过，但苦于没有一个好使的rss客户端

1我不知道有这个东西

2.2、RSS 订阅还是要全文的。

但是，看到感兴趣的，我会点开链接看，

点开链接的页面排版看全文内容会比订阅显示来的舒服

1、我不知道有这个东西

1还是1

2.2、RSS 订阅还是要全文的，毕竟我不喜欢再打开浏览器

2.2<br />
看标题感兴趣的点进去看全文，省的来回切换浏览器和ttrss，而且rss基本也没广告

2.2

摘要内容太少，不方便了解全文的内容和深度

2.1、RSS 订阅中有标题和摘要就行了，感兴趣我会点击链接的

2.2、RSS 订阅还是要全文的，毕竟我不喜欢再打开浏览器

Linux.cn不是新闻网站，2.1不可取。

RSS 订阅还是要全文的，毕竟我不喜欢再打开浏览器

2.1  我一直用浏览器打开。

2.1  我一直用浏览器的RSS打开。

2.2、RSS 订阅还是要全文的<br />
RSS重度用户

果断2.2   8D8D<br />
不过说实话，这个问卷调查的结果须评估参与人群的bias，即由于“RSS用户更容易看到这份调查问卷”，故而调查结果会比真实结果更向选项2偏离。所以需要对结果进行一个合理的smear或去偏化。

2.2

一直在用，非常方便。

沒有好用的客戶端，用的不舒服。

来自广东广州的 Chrome Mobile 53.0|Android 5.1 用户

让我选一定是2.2，能少步骤就尽量少步骤

2.2 天天在用

牛！下次我们要做人群调查，就请您来做模型~ :D

来自117.136.66.16的 Chrome Mobile 37.0|Android 4.2 用户

现在 Linux 中国在浏览器上的 RSS 只能提供3条推送么？感觉有点少啊。

2.2、RSS 订阅还是要全文的，毕竟我不喜欢再打开浏览器

2.2我在用

在用，很好，微信太邪恶，不喜欢

１

one

1、我不知道有这个东西

必须 2.2，不过要是为了避免爬虫改成 2.1 还是勉强可以接受。

2.1<br />
现在这样，我根本舍不得在用流量的情况下刷新。

2.2<br />
用的feedly

1.1、我不会去订阅 RSS

来自江苏苏州的 Internet Explorer 11.0|Windows 8.1 用户

主要是从来没用过

2.1

海外用戶全文怕卡在網速慢，何不提供 2.1 跟 2.2 兩種 rss 讓用戶自己選擇？

1.2、告诉我 RSS 地址在哪里，我去订阅!  一直想订阅呢

不知道rss是什么玩意？不知道怎么使用。囧

1、我不知道有这个东西

页面左上角~

唉？这是个有道理的建议啊！

不知道，rss是什么，→_→

来自湖北武汉的 Chrome Mobile 51.0|Android 4.4 用户

RSS用全文更好

2 1

来自117.136.61.97的 Sina Weibo 6.10|Android 6.0 用户

1.1<br />
闲麻烦。。。不要鄙视我好吧。。。

2、我已经订阅了“Linux 中国”的 RSS<br />
2.2、RSS 订阅还是要全文的，毕竟我不喜欢再打开浏览器

1、我不知道有这个东西

2.2、RSS 订阅还是要全文的，毕竟我不喜欢再打开浏览器

rss在chrome内核的浏览器上 不支持

2.1、RSS 订阅中有标题和摘要就行了，感兴趣我会点击链接的

:D:D

WangYueScream [Baidu Spark 8.6|Windows 7]

非常感谢保留RSS全文

rss是啥，，我去百度一下。。。   顺便问一下，这网站怎么检测的用户浏览器和操作系统版本的。。。『貌似可以利用这个搞事情。。』

# 关于“Linux中国” RSS 的一个调查问卷，如果你在用，请来看看

<img src="content_image/album_201609_28_111005q2964a06b4axzhbv.jpg" alt="" title="">

各位 “Linux 中国”的朋友们，无论你是在用电脑还是手机，无论你是用浏览器访问“Linux 中国”的网站还是用微信接收推送，抑或者你就是用 RSS 阅读软件一直订阅我们的频道的。那么这里有一个小小的调查，希望得到您的反馈。不长，一分钟就行。

1、我不知道有这个东西

1.1、我不会去订阅 RSS

1.2、告诉我 [RSS 地址](https://linux.cn/rss.xml)在哪里，我去订阅

2、我已经订阅了“Linux 中国”的 RSS

2.1、RSS 订阅中有标题和摘要就行了，感兴趣我会点击链接的

2.2、RSS 订阅还是要全文的，毕竟我不喜欢再打开浏览器

请在下面发表您的评论即可。

**更新：**

*本来发此文是考虑将现有的 RSS 从全文方式改为摘要方式——倒不是为了引流，而是为了规避部分恶意爬虫。不过没有想到得到了大家这么多的回复，而且使用 RSS 的人要比我预想中的多得多。*

*虽然大家有不少人提到了有标题和摘要就可以了，不过也还有更多的人提到要全文，那就保持不变吧，还是全文好了~*

*最后，谢谢大家的关注和回复，如有任何建议，请随时反馈给我们。*

*更新2：*

*增加了一个专门提供摘要方式的 RSS ：https://linux.cn/rss-digest.xml 大家可以试试（页面左上角也有链接）。如发现有不足之处，敬请提出。*


你该选择 openSUSE 的五大理由

Summary: 相比其他的 Linux 发行版，我总能在 openSUSE 上看到一些令人耳目一新的东西。我说不太好，但它总是如此的闪亮和个性鲜明。这绿色的大蜥蜴是看起来如此的令人惊叹！但这并不是 openSUSE 即便不是最好也是要比其它发行版更好的原因！

二奶机上安装的TUMBLEWEED，感觉现在KDE下的软件很少，以前很多好用的软件已经停止开发了

不熟啊，一般都是选CentOS或Ubuntu，一个专门做服务器，一个开发的时候用

大蜥蜴是我见过安装界面最漂亮、人性化的系统，但是我没有深入的用SUSE，所以我连他的包管理是什么都不知道。。。

之前一直用arch，前段时间因为觉得gnome的工作区域太小了，就换回ubuntu，但是ubuntu的bcloud用不了，在arch和ubuntu里面辗转好多次，现在电脑里面是arch+win10 ，这几天在玩LOL，所以一般都是用的win10.

等ubuntu16.10出来之后去装ubuntu，实在不满意的话，就用大蜥蜴

那你还是继续用arch了，ubuntu不用LTS无意义<br />
bcloud的问题在github上有解决方案

新手最应该从 opensuse 入门而不是 ubuntu。

1、opensuse -> arch linux -> fedora -> fedora(desktop)+centos(server)

2、opensuse -> arch linux -> opensuse -> opensesu(desktop)+suse(server)

第二种比较少见。

openusese赞一个，但其国内论坛氛围还是差一些，好多问题没有解决呀

我是在ubuntu上装都装不上bcloud，arch的仓库里面有bcloud，安装之后修改那几个文件就行了，，，

表示不懂AppArmor，還是默默的管理窩RH系的SELinux

openSUSE 曾经是我的主系统，但是已经换成 Debian 好多年了。

不用openSuse的理由则不需要有5个那么多，优秀的发行版多的很。我不用opensuse的理由是，不愿与某二三人为代表的某群人为伍。

用过很长一段时间opensuse，包括tumbleweed，并没有比Ubuntu更好用，相反因为很多问题都可以很好的找到Ubuntu下的解决方案，很多软件作者也更熟悉ubuntu的问题解决，所以opensuse反而显得更难用了～特别是还有一个非常不友好的社区！！！

来自浙江杭州的 Yandex Browser 16.9|GNU/Linux 用户

你说的对，某些人总是太高傲

说实在的，虽然翻译译了这一篇文章，但还是真的没有用过 openSUSE。我记得第一个地使用的 Linux 发行版就是 Ubuntu，但是什么都不懂，就随便装来玩玩。再到后来，熟悉一点之后，就尝试过 deepin，CentOS。再到 接触 LFS，这个完全自主从零开始的东东，因为自己有很多地方不懂，没能构建起来。可能是自己对分区的排布、引导的自定义安装等原因，最后还是选择长久使用 Archlinux，滚动式更新也很适合我这种强迫症的人。同时也保留 windows 10，作为游戏。哈哈。

我也是用的arch，但是我不想用gnome了，又用不惯kde，，，，，其实挺想用unity的，，，但是源码git下来make不了。

刚开始用 Archlinux 的时候是用的 xfce，后来换了默认主题数据额效果更好的 Plasma。

我找不到好的plsma美化资源，而且也用不过kde。<br />
xfce也是不知道该怎么美化。。。

opensuse怎么安装？

opensuse源里的软件不全，上次装caffe，很多软件都要自己编译

opensuse还发布了树莓派64bit系列版本。这是目前唯一主流发行版官方支持的64位树莓派linux系统。但是有一些问题。15.0版wiringpi用不了，有bug。42.3版wiringpi需要修改一些东西，能用。但是我在更新内核后，反复重启进不了系统了。

怎样把 Leap-15.3 的系统内核升级到 5.15 新版内核？

# 你该选择 openSUSE 的五大理由

多数的的桌面 Linux 用户都会选择三种发行版本：Debian/Ubuntu、Fedora 或者 Arch Linux。但是今天，我将给出你需要使用 openSUSE 的五大理由。

相比其他的 Linux 发行版，我总能在 [openSUSE](https://www.opensuse.org/) 上看到一些令人耳目一新的东西。我说不太好，但它总是如此的闪亮和个性鲜明。这绿色的大蜥蜴是看起来如此的令人惊叹！但这并不是 openSUSE **即便不是最好也是要比其它发行版更好**的原因！

请别误解我。我在各种场合用过许多不同的 Linux 发行版，同时也很敬佩在这些发行版背后默默工作的开发者，是他们让计算变成一件快乐的事情。但是 openSUSE 一直让人感觉，嗯，令人崇敬——你是不是也这样觉得？

### openSUSE 比其他 Linux 发行版要好的五大理由

你是不是认为我在说 openSUSE 是最好的 Linux 发行版？不，我并不是要表达这个意思。其实没有任何一个 Linux 发行版是最好的。它真的可以满足你寻找 “灵魂伴侣” 的需求。

但在这里，我准备给大家说说，openSUSE 比其他发行版做得要好的五件事。如下：

#### #1 社区规则

openSUSE 是一个典型的社区驱动型项目。我经常看到很多用户在升级后抱怨开发人员改变了他们喜欢的发行版。但在 openSUSE 不是这样，openSUSE 是纯社区驱动的项目，并且任何时候都朝着用户所希望的方向发展。

#### #2 系统的健壮性

另外一个是操作系统的集成程度。我可以在同一个 openSUSE 系统上安装所有的[最好的 Linux 桌面环境](https://itsfoss.com/best-linux-desktop-environments/)，而在 Ubuntu 上则因为系统的稳定性，坚决不允许用户这样做。而这恰好体现了一个系统的健壮程度。因此，对于那些喜欢自己动手完成每一件事的用户，openSUSE 还是很诱人的。

#### #3 易于安装软件

在 Linux 的世界里有很多非常好用的包管理工具。从 Debian 的 apt-get 到 [Fedora](https://itsfoss.com/fedora-24-review/) 的 DNF，它们无不吸引着用户，而且在这些发行版成为流行版本的过程中扮演着重要角色。

openSUSE 同样有一个将软件传递到桌面的好方法。[software.opensuse.org](https://software.opensuse.org/421/en) 是一个 Web 界面，你可以用它从仓库中获取安装软件。你所需要做的就是打开这个链接 (当然，是在 openSUSE 系统上)，在搜索框中输入你想要的软件，点击“直接安装”即可。就是这么简单，不是吗？

听起来就像是在使用 Google 商店一样，是吗？

#### #4 YAST

毫不夸张的说，[YaST](https://en.opensuse.org/Portal:YaST) (LCTT 译注: YaST 是 openSUSE 和 SUSE Linux 企业版的安装和配置工具) 绝对是世界上有史以来**操作系统**上最好的控制中心。并且毫无疑问地，你可以使用它来操控系统上的一切：网络、软件升级以及所有的基础设置等。无论是 openSUSE 的个人版或是 SUSE Linux 企业版，你都能在 YaST 的强力支撑下，轻松的完成安装。总之，一个工具，方便而无所不能。

#### #5 开箱即用的极致体验

SUSE 的团队是 Linux 内核中最大的贡献者团体之一。他们辛勤的努力也意味着，他们有足够的经验来应付不同的硬件条件。

有着良好的硬件支持，一定会有很棒的开箱即用的体验。

#### #6 他们做了一些搞笑视频

等等，不是说好了是五个理由吗？怎么多了一个！

但因为 [Abhishek](https://itsfoss.com/author/abhishek/) 逼着我加进来，因为他们做的 Linux 的搞笑视频才使 openSUSE 成为了最好的发行版。

开了个玩笑，不过还是看看 [Uptime Funk](https://www.youtube.com/watch?v=zbABy9ul11I)，你将会知道[为什么 SUSE 是最酷的 Linux](https://itsfoss.com/suse-coolest-linux-enterprise/) 。

### LEAP 还是 TUMBLEWEED？该用哪一个！

如果你现在想要使用 openSUSE 了，让我来告诉你，这两个 openSUSE 版本：LEAP 和 TUMBLEWEED。哪一个更合适你一点。

尽管两者都提供了相似的体验和相似的环境，但还是需要你自行决定安装那个版本到你硬盘上。

#### OPENSUSE : LEAP

[openSUSE Leap](https://en.opensuse.org/Portal:Leap) 是一个普通的大众版本，基本上每八个月更新一次。目前最新的版本是 openSUSE 42.1。它所有的软件都是稳定版，给用户提供最顺畅的体验。

对于家庭用户、办公和商业用户，是再合适不过的了。它合适那些想要一个稳定系统，而不必事事亲为，可以让他们安心工作的用户。只要进行正确的设置之后，你就不必担心其他事情，然后专心投入工作就好。同时，我也强烈建议图书馆和学校使用 Leap。

#### OPENSUSE: TUMBLEWEED

[Tumbleweed version of openSUSE](https://en.opensuse.org/Portal:Tumbleweed) 是滚动式更新的版本。它定期更新系统中所使用的软件集的最新版本。对于想要使用最新软件以及想向 openSUSE 做出贡献的开发者和高级用户来说，这个版本绝对值得一试。

需要指出的是，Tumbleweed 并不是 Leap 的 beta 和 测试版本 。它是最新锐的 Linux 稳定发行版。

Tumbleweed 给了你最快的更新，但是仅在开发者确定某个包的稳定性之后才行。

### 说说你的想法?

请在下方评论说出你对 openSUSE 的想法。如果你已经在考虑使用 openSUSE，你更想用 Leap 和 Tumbleweed 哪一个版本呢？

来，让我们开干！

---

via: <https://itsfoss.com/why-use-opensuse/>

作者：[Aquil Roshan](https://itsfoss.com/author/aquil/) 译者：[GHLandy](https://github.com/GHLandy) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


在 Ubuntu 16.04 上安装和使用服务器监控报警系统 Shinken

现在还有这么复杂的SNMP监控软件？？？

确实够绕的。

模块好多！！

# 在 Ubuntu 16.04 上安装和使用服务器监控报警系统 Shinken

Shinken 是一个用 Python 实现的开源的主机和网络监控框架，并与 Nagios like 兼容，它可以运行在所有支持 Python 程序的操作系统上，比如说 Linux、Unix 和 Windows。Shinken 是 Jean Gabes 为了验证一个新的 Nagios 架构思路而编写，但是这个想法被 Nagios 的作者拒绝后成为了一个独立的网络系统监视软件，并保持了与 Nagios 的兼容。

在这篇教程中，我将会描述如何从源代码编译安装 Shinken 和向监视系统中添加一台 Linux 主机。我将会以 Ubuntu 16.04 Xenial Xerus 操作系统来作为 Shinken 服务器和所监控的主机。

### 第一步 安装 Shinken 服务器

Shinken 是一个 Python 框架，我们可以通过 `pip` 安装或者从源码来安装它，在这一步中，我们将用源代码编译安装 Shinken。

在我们开始安装 Shinken 之前还需要完成几个步骤。

安装一些新的 Python 软件包并创建一个名为 `shinken` 的系统用户：

```
sudo apt-get install python-setuptools python-pip python-pycurl
useradd -m -s /bin/bash shinken

```

从 GitHub 仓库下载 Shinken 源代码：

```
git clone https://github.com/naparuba/shinken.git
cd shinken/

```

然后用以下命令安装 Shinken：

```
git checkout 2.4.3
python setup.py install

```

然后，为了得到更好的效果，我们还需要从 Ubuntu 软件库中安装 `python-cherrypy3` 软件包：

```
sudo apt-get install python-cherrypy3

```

到这里，Shinken 已经成功安装，接下来我们将 Shinken 添加到系统启动项并且启动它：

```
update-rc.d shinken defaults
systemctl start shinken

```

### 第二步 安装 Shinken Webui2

Webui2 是 Shinken 的 Web 界面（在 shinken.io 可以找到）。最简单的安装 Shinken webui2 的方法是使用shinken CLI 命令（必须作为 `shinken` 用户执行）。

切换到 shinken 用户：

```
su - shinken

```

初始化 shiken 配置文件，下面的命令将会创建一个新的配置文件 `.shinken.ini` ：

```
shinken --init

```

接下来用 shinken CLI 命令来安装 `webui2`：

```
shinken install webui2

```

至此 webui2 已经安装好，但是我们还需要安装 MongoDB 和用 `pip` 来安装另一个 Python 软件包。在 root 下运行如下命令：

```
sudo apt-get install mongodb
pip install pymongo>=3.0.3 requests arrow bottle==0.12.8

```

接下来，切换到 shinken 目录下并且通过编辑 `broker-master.cfg` 文件来添加这个新的 webui2 模块：

```
cd /etc/shinken/brokers/
vim broker-master.cfg

```

在第 40 行添加一个模块选项：

```
modules     webui2

```

保存文件并且退出编辑器。

现在进入 `contacts` 目录下编辑 `admin.cfg` 来进行管理配置。

```
cd /etc/shinken/contacts/
vim admin.cfg

```

按照如下修改：

```
contact_name    admin       # Username 'admin'
password        yourpass    # Pass 'mypass'

```

保存和退出。

### 第三步 安装 Nagios 插件和 Shinken 软件包

在这一步中，我们将安装 Nagios 插件和一些 Perl 模块。然后从 shinken.io 安装其他的软件包来实现监视。

安装 Nagios 插件和安装 Perl 模块所需要的 `cpanminus`：

```
sudo apt-get install nagios-plugins* cpanminus

```

用 `cpanm` 命令来安装 Perl 模块。

```
cpanm Net::SNMP
cpanm Time::HiRes
cpanm DBI

```

现在我们创建一个 `utils.pm` 文件的链接到 shinken 的目录，并且为 `Log_File_Health` 创建了一个新的日志目录 。

```
chmod u+s /usr/lib/nagios/plugins/check_icmp
ln -s /usr/lib/nagios/plugins/utils.pm /var/lib/shinken/libexec/
mkdir -p /var/log/rhosts/
touch /var/log/rhosts/remote-hosts.log

```

然后，从 shinken.io 安装 shinken 软件包 `ssh` 和 `linux-snmp` 来监视 SSH 和 SNMP ：

```
su - shinken
shinken install ssh
shinken install linux-snmp

```

### 第四步 添加一个 Linux 主机 host-one

我们将添加一个新的将被监控的 Linux 主机，IP 地址为 192.168.1.121，主机名为 host-one 的 Ubuntu 16.04。

连接到 host-one 主机：

```
ssh host1@192.168.1.121

```

从 Ubuntu 软件库中安装 snmp 和snmpd 软件包：

```
sudo apt-get install snmp snmpd

```

然后，用 `vim` 编辑 `snmpd.conf` 配置文件：

```
vim /etc/snmp/snmpd.conf

```

注释掉第 15 行并取消注释第 17 行：

```
#agentAddress  udp:127.0.0.1:161
agentAddress udp:161,udp6:[::1]:161

```

注释掉第 51 和 53 行，然后加一行新的配置，如下：

```
#rocommunity mypass  default    -V systemonly
#rocommunity6 mypass  default   -V systemonly

rocommunity mypass

```

保存并退出。

现在用 `systemctl` 命令来启动 `snmpd` 服务：

```
systemctl start snmpd

```

在 shinken 服务器上通过在 `hosts` 文件夹下创建新的文件来定义一个新的主机：

```
cd /etc/shinken/hosts/
vim host-one.cfg

```

粘贴如下配置信息：

```
define host{
        use                 generic-host,linux-snmp,ssh
        contact_groups      admins
        host_name           host-one
        address             192.168.1.121
        _SNMPCOMMUNITY      mypass        # SNMP Pass Config on snmpd.conf
    }

```

保存并退出。

在 shinken 服务器上编辑 SNMP 配置文件。

```
vim /etc/shinken/resource.d/snmp.cfg

```

将 `public` 改为 `mypass` -必须和你在客户端 `snmpd` 配置文件中使用的密码相同：

```
$SNMPCOMMUNITYREAD$=mypass

```

保存并退出。

现在将服务端和客户端都重启：

```
reboot

```

现在 Linux 主机已经被成功地添加到 shinken 服务器中了。

### 第五步 访问 Shinken Webui2

在端口 7677 访问 Shinken webui2 （将 URL 中的 IP 替换成你自己的 IP 地址）：

```
http://192.168.1.120:7767

```

用管理员用户和密码登录（你在 admin.cfg 文件中设置的）

Webui2 中的 Shinken 面板：

我们的两个服务器正在被 Shinken 监控：

列出所有被 linux-snmp 监控的服务：

所有主机和服务的状态信息：

### 第6步 Shinken 的常见问题

#### NTP 服务器相关的问题

当你得到如下的 NTP 错误提示

```
TimeSync - CRITICAL ( NTP CRITICAL: No response from the NTP server)
TimeSync - CRITICAL ( NTP CRITICAL: Offset unknown )

```

为了解决这个问题，在所有 Linux 主机上安装 ntp。

```
sudo apt-get install ntp ntpdate

```

编辑 ntp 配置文件：

```
vim /etc/ntp.conf

```

注释掉所有 pools 并替换为：

```
#pool 0.ubuntu.pool.ntp.org iburst
#pool 1.ubuntu.pool.ntp.org iburst
#pool 2.ubuntu.pool.ntp.org iburst
#pool 3.ubuntu.pool.ntp.org iburst

pool 0.id.pool.ntp.org
pool 1.asia.pool.ntp.org
pool 0.asia.pool.ntp.org

```

然后，在新的一行添加如下限制规则：

```
# Local users may interrogate the ntp server more closely.
restrict 127.0.0.1
restrict 192.168.1.120 #shinken server IP address
restrict ::1
NOTE: 192.168.1.120 is the Shinken server IP address.

```

保存并退出。

启动 ntp 并且检查 Shinken 面板。

```
ntpd

```

#### check\_netint.pl Not Found 问题

从 github 仓库下载源代码到 shinken 的库目录下：

```
cd /var/lib/shinken/libexec/
wget https://raw.githubusercontent.com/Sysnove/shinken-plugins/master/check_netint.pl
chmod +x check_netint.pl
chown shinken:shinken check_netint.pl

```

#### 网络占用的问题

这是错误信息：

```
ERROR : Unknown interface eth\d+

```

检查你的网络接口并且编辑 `linux-snmp` 模版。

在我的 Ununtu 服务器，网卡是 “enp0s8”，而不是 eth0，所以我遇到了这个错误。

`vim` 编辑 `linux-snmp` 模版：

```
vim /etc/shinken/packs/linux-snmp/templates.cfg

```

在第 24 行添加网络接口信息：

```
_NET_IFACES         eth\d+|em\d+|enp0s8

```

保存并退出。

---

via: <https://www.howtoforge.com/tutorial/server-monitoring-with-shinken-on-ubuntu-16-04/>

作者：[Muhammad Arul](https://www.howtoforge.com/tutorial/server-monitoring-with-shinken-on-ubuntu-16-04/) 译者：[LinuxBars](https://github.com/LinuxBars) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出

Save and exit.


AWS 和 GCP 的 Spark 技术哪家强？

Summary: 毋庸置疑，云计算将会在未来数据科学领域扮演至关重要的角色。弹性，可扩展性和按需分配的计算能力作为云计算的重要资源，直接导致云服务提供商集体火拼。其中最大的两股势力正是亚马逊网络服务（AWS) 和谷歌云平台（GCP)。

# AWS 和 GCP 的 Spark 技术哪家强？

>
> Tianhui Michael Li 和 Ariel M’ndange-Pfupfu 将在今年 10 月 10、12 和 14 号组织一个在线经验分享课程：[Spark 分布式计算入门](http://www.oreilly.com/live-training/distributed-computing-with-spark.html?intcmp=il-data-olreg-lp-oltrain_20160828_new_site_spark_comparison_aws_gcp_post_top_note_training_link)。该课程的内容包括创建端到端的运行应用程序和精通 Spark 关键工具。
>
>
>

毋庸置疑，云计算将会在未来数据科学领域扮演至关重要的角色。弹性，可扩展性和按需分配的计算能力作为云计算的重要资源，直接导致云服务提供商集体火拼。其中最大的两股势力正是[亚马逊网络服务（AWS)](https://aws.amazon.com/) 和[谷歌云平台（GCP)](https://cloud.google.com/)。

本文依据构建时间和运营成本对 AWS 和 GCP 的 Spark 工作负载作一个简短比较。实验由我们的学生在<ruby> 数据孵化器 <rp>  （ </rp> <rt>  The Data Incubator </rt> <rp>  ） </rp></ruby>进行，<ruby>   数据孵化器  <rp>  （ </rp> <rt>  The Data Incubator </rt> <rp>  ） </rp></ruby>是一个大数据培训组织，专门为公司招聘顶尖数据科学家并为公司职员培训最新的大数据科学技能。尽管 Spark 效率惊人，分布式工作负载的时间和成本亦然可以大到不能忽略不计。因此我们一直努力寻求更高效的技术，以便我们的学生能够学习到最好和最快的工具。

### 提交 Spark 任务到云

[Spark](http://spark.apache.org/) 是一个类 MapReduce 但是比 MapReduce 更灵活、更抽象的并行计算框架。Spark 提供 Python 和 Java 编程接口，但它更愿意用户使用原生的 Scala 语言进行应用程序开发。Scala 可以把应用程序和依赖文件打包在一个 JAR 文件从而使 Spark 任务提交变得简单。

通常情况下，Sprark 结合 HDFS 应用于分布式数据存储，而与 YARN 协同工作则应用于集群管理；这种堪称完美的配合使得 Spark 非常适用于 AWS 的弹性 MapReduce （EMR）集群和 GCP 的 Dataproc 集群。这两种集群都已有 HDFS 和 YARN 预配置，不需要额外进行配置。

### 配置云服务

通过命令行比通过网页界面管理数据、集群和任务具有更高的可扩展性。对 AWS 而言，这意味着客户需要安装 [CLI](http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-set-up.html)。客户必须获得证书并为每个 EC2 实例创建[独立的密钥对](http://docs.aws.amazon.com/ElasticMapReduce/latest/DeveloperGuide/EMR_SetUp_KeyPair.html)。除此之外，客户还需要为 EMR 用户和 EMR 本身创建角色（基本权限），主要是准入许可规则，从而使 EMR 用户获得足够多的权限（通常在 CLI 运行 `aws emr create-default-roles` 就可以）。

相比而言，GCP 的处理流程更加直接。如果客户选择安装 [Google Cloud SDK](https://cloud.google.com/sdk/#Quick_Start) 并且使用其 Google 账号登录，那么客户即刻可以使用 GCP 的几乎所有功能而无需其他任何配置。唯一需要提醒的是不要忘记通过 API 管理器启用计算引擎、Dataproc 和云存储 JSON 的 API。

当你安装你的喜好设置好之后，有趣的事情就发生了！比如可以通过`aws s3 cp`或者`gsutil cp`命令拷贝客户的数据到云端。再比如客户可以创建自己的输入、输出或者任何其他需要的 bucket，如此，运行一个应用就像创建一个集群或者提交 JAR 文件一样简单。请确定日志存放的地方，毕竟在云环境下跟踪问题或者调试 bug 有点诡异。

### 一分钱一分货

谈及成本，Google 的服务在以下几个方面更有优势。首先，购买计算能力的原始成本更低。4 个 vCPU 和 15G RAM 的 Google 计算引擎服务（GCE）每小时只需 0.20 美元，如果运行 Dataproc，每小时也只需区区 0.24 美元。相比之下，同等的云配置，AWS EMR 则需要每小时 0.336 美元。

其次，计费方式。AWS 按小时计费，即使客户只使用 15 分钟也要付足 1 小时的费用。GCP 按分钟计费，最低计费 10 分钟。在诸多用户案例中，资费方式的不同直接导致成本的巨大差异。

两种云服务都有其他多种定价机制。客户可以使用 AWS 的 Sport Instance 或 GCP 的 Preemptible Instance 来竞价它们的空闲云计算能力。这些服务比专有的、按需服务便宜，缺点是不能保证随时有可用的云资源提供服务。在 GCP 上，如果客户长时间（每月的 25% 至 100%）使用服务，可以获取更多折扣。在 AWS 上预付费或者一次购买大批量服务可以节省不少费用。底线是，如果你是一个超级用户，并且使用云计算已经成为一种常态，那么最好深入研究云计算，自己算计好成本。

最后，新手在 GCP 上体验云服务的费用较低。新手只需 300 美元信用担保，就可以免费试用 60 天 GCP 提供的全部云服务。AWS 只免费提供特定服务的特定试用层级，如果运行 Spark 任务，需要付费。这意味着初次体验 Spark，GCP 具有更多选择，也少了精打细算和讨价还价的烦恼。

### 性能比拼

我们通过实验检测一个典型 Spark 工作负载的性能与开销。实验分别选择 AWS 的 m3.xlarg 和 GCP 的 n1-standard-4，它们都是由一个 Master 和 5 个核心实例组成的集群。除了规格略有差别，虚拟核心和费用都相同。实际上它们在 Spark 任务的执行时间上也表现的惊人相似。

测试 Spark 任务包括对数据的解析、过滤、合并和聚合，这些数据来自公开的<ruby>   堆栈交换数据转储  <rp>  （ </rp> <rt>  Stack Exchange Data Dump </rt> <rp>  ） </rp></ruby>。通过运行相同的 JAR，我们首先对大约 50M 的数据子集进行[交叉验证](http://stats.stackexchange.com/)，然后将验证扩大到大约 9.5G 的数据集。

>
> Figure 1. Credit: Michael Li and Ariel M'ndange-Pfupfu.
>
>
>

>
> Figure 2. Credit: Michael Li and Ariel M'ndange-Pfupfu.
>
>
>

结果表明，短任务在 GCP 上具有明显的成本优势，这是因为 GCP 以分钟计费，并最终扣除了 10 分钟的费用，而 AWS 则收取了 1 小时的费用。但是即使长任务，因为计费方式占优，GPS 仍然具有相当优势。同样值得注意的是存储成本并不包括在此次比较当中。

### 结论

AWS 是云计算的先驱，这甚至体现在 API 中。AWS 拥有巨大的生态系统，但其许可模型已略显陈旧，配置管理也有些晦涩难解。相比之下，Google 是云计算领域的新星并且将云计算服务打造得更加圆润自如。但是 GCP 缺少一些便捷的功能，比如通过简单方法自动结束集群和详细的任务计费信息分解。另外，其 Python 编程接口也不像 [AWS 的 Boto](https://github.com/boto/boto3) 那么全面。

如果你初次使用云计算，GCP 因其简单易用，别具魅力。即使你已在使用 AWS，你也许会发现迁移到 GCP 可能更划算，尽管真正从 AWS 迁移到 GCP 的代价可能得不偿失。

当然，现在对两种云服务作一个全面的总结还非常困难，因为它们都不是单一的实体，而是由多个实体整合而成的完整生态系统，并且各有利弊。真正的赢家是用户。一个例证就是在<ruby> 数据孵化器 <rp>  （ </rp> <rt>  The Data Incubator </rt> <rp>  ） </rp></ruby>，我们的博士数据科学研究员在学习分布式负载的过程中真正体会到成本的下降。虽然我们的[大数据企业培训客户](https://www.thedataincubator.com/training.html)可能对价格不那么敏感,他们更在意能够更快速地处理企业数据，同时保持价格不增加。数据科学家现在可以享受大量的可选服务，这些都是从竞争激烈的云计算市场得到的实惠。

---

via: <https://www.oreilly.com/ideas/spark-comparison-aws-vs-gcp>

作者：[Michael Li](https://www.oreilly.com/people/76a5b-michael-li) [Ariel M'Ndange-Pfupfu](https://www.oreilly.com/people/Ariel-Mndange-Pfupfu) 译者：[firstadream](https://github.com/firstadream) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Linux 发行版们应该禁用 IPv4 映射的 IPv6 地址吗？

Summary: 正如近期 OpenBSD 邮件列表的讨论所关注的，一个使得向 IPv6 转换更加轻松的机制设计同时也可能导致网络更不安全——并且 Linux 发行版们的默认配置可能并不安全。

我有强迫症  ss -nl 看着一堆 :xx  和 ::xx 就头疼，所以直接关系ipv6 清净了不少。

关闭 关闭 ……

有意见提RFC上去，讨论通过了大家一起用，不然这种比较底层的实现特立独行跟社区过不去不会有好下场。OpenBSD很好么？Linux本质是工程派的，为什么要向学院派的看齐，嗯？

关掉吧....

# Linux 发行版们应该禁用 IPv4 映射的 IPv6 地址吗？

从各方面来看，互联网向 IPv6 的过渡是件很缓慢的事情。不过在最近几年，可能是由于 IPv4 地址资源的枯竭，IPv6 的使用处于[上升态势](https://www.google.com/intl/en/ipv6/statistics.html)。相应的，开发者也有兴趣确保软件能在 IPv4 和 IPv6 下工作。但是，正如近期 OpenBSD 邮件列表中的讨论所关注的，一个使得向 IPv6 转换更加轻松的机制设计同时也可能导致网络更不安全——并且 Linux 发行版们的默认配置可能并不安全。

<img src="content_image/album_201609_30_135551ptzgfjoo2fxlfe9t.jpg" alt="" title="">

### 地址映射

IPv6 在很多方面看起来可能很像 IPv4，但它是一个不同地址空间的不同的协议。服务器程序想要接受使用二者之中任意一个协议的连接，必须给两个不同的地址族分别打开一个套接字——IPv4 的 `AF_INET` 和 IPv6 的 `AF_INET6`。特别是一个程序希望在主机上的使用两种地址协议的任意接口都接受连接的话，需要创建一个绑定到全零通配符地址（`0.0.0.0`）的 `AF_INET` 套接字和一个绑定到 IPv6 等效地址（写作 `::`）的 `AF_INET6` 套接字。它必须在两个套接字上都监听连接——或者有人会这么认为。

多年前，在 [RFC 3493](https://tools.ietf.org/html/rfc3493#section-3.7)，IETF 指定了一个机制，程序可以使用一个单独的 IPv6 套接字工作在两个协议之上。有了一个启用这个行为的套接字，程序只需要绑定到 `::` 地址从而在所有接口上接受使用这两个协议的连接。当创建了一个 IPv4 连接到该绑定端口，源地址会像 [RFC 2373](https://tools.ietf.org/html/rfc2373#page-10) 中描述的那样映射到 IPv6。所以，举个例子，一个使用了这个模式的程序会将一个 `192.168.1.1` 的传入连接看作来自 `::ffff:192.168.1.1`（这个混合的写法就是这种地址的通常写法）。程序也能通过相同的映射方法打开一个到 IPv4 地址的连接。

RFC 要求默认实现这个行为，所以大多数系统这么做了。不过也有些例外，OpenBSD 就是其中之一；在那里，希望在两种协议下工作的程序能做的只能是创建两个独立的套接字。但一个在 Linux 中打开两个套接字的程序会遇到麻烦：IPv4 和 IPv6 套接字都会尝试绑定到 IPv4 地址，所以不论是哪个，后者都会失败。换句话说，一个绑定到 `::` 指定端口的套接字的程序会同时绑定到那个端口上的 IPv6 的 `::` 和 IPv4 的 `0.0.0.0` 地址。如果程序之后尝试绑定一个 IPv4 套接字到 `0.0.0.0` 的相同端口上时，这个操作会失败，因为这个端口已经被绑定了。

当然有个办法可以解决这个问题；程序可以调用 `setsockopt()` 来打开 `IPV6_V6ONLY` 选项。一个打开两个套接字并且设置了 `IPV6_V6ONLY` 的程序应该可以在所有的系统间移植。

读者们可能对不是每个程序都能正确处理这一问题没那么震惊。事实证明，这些程序的其中之一是<ruby> 网络时间协议 <rp>  （ </rp> <rt>  Network Time Protocol </rt> <rp>  ） </rp></ruby>的 [OpenNTPD](https://github.com/openntpd-portable/) 实现。Brent Cook 最近给上游 OpenNTPD 源码[提交了一个小补丁](https://lwn.net/Articles/688464/)，添加了必要的 `setsockopt()` 调用，它也被提交到了 OpenBSD 中了。不过那个补丁看起来不大可能被接受，最可能的原因是因为 OpenBSD 式的理由（LCTT 译注：如前文提到的，OpenBSD 并不受这个问题的影响）。

### 安全担忧

正如上文所提到，OpenBSD 根本不支持 IPv4 映射的 IPv6 套接字。即使一个程序试着通过将 `IPV6_V6ONLY` 选项设置为 0 来显式地启用地址映射，它的作者也会感到沮丧，因为这个设置在 OpenBSD 系统中无效。这个决定背后的原因是这个映射带来了一些安全隐忧。攻击打开的接口的攻击类型有很多种，但它们最后都会回到规定的两个途径到达相同的端口，每个端口都有它自己的控制规则。

任何给定的服务器系统可能都设置了防火墙规则，描述端口的允许访问权限。也许还会有适当的机制，比如 TCP wrappers 或一个基于 BPF 的过滤器，或一个网络上的路由器可以做连接状态协议过滤。结果可能是导致防火墙保护和潜在的所有类型的混乱连接之间的缺口造成同一 IPv4 地址可以通过两个不同的协议到达。如果地址映射是在网络边界完成的，情况甚至会变得更加复杂；参看[这个 2003 年的 RFC 草案](https://tools.ietf.org/html/draft-itojun-v6ops-v4mapped-harmful-02)，它描述了如果映射地址在主机之间传播，一些随之而来的其它攻击场景。

改变系统和软件正确地处理 IPv4 映射的 IPv6 地址当然可以实现。但那增加了系统的整体复杂度，并且可以确定这个改动没有实际地完整实现到它应该实现的范围内。如同 Theo de Raadt [说的](https://lwn.net/Articles/688465/)：

>
> **有时候人们将一个糟糕的想法放进了 RFC。之后他们发现这个想法是不可能的就将它丢回垃圾箱了。结果就是概念变得如此复杂，每个人都得在管理和编码方面是个全职专家。**
>
>
>

我们也根本不清楚这些全职专家有多少在实际配置使用 IPv4 映射的 IPv6 地址的系统和网络。

有人可能会说，尽管 IPv4 映射的 IPv6 地址造成了安全危险，更改一下程序让它在实现了地址映射的系统上关闭地址映射应该没什么危害。但 Theo [认为](https://lwn.net/Articles/688466/)不应该这么做，有两个理由。第一个是有许多破旧的程序，它们永远不会被修复。而实际的原因是给发行版们施加了压力去默认关闭地址映射。正如他说的：“**最终有人会理解这个危害是系统性的，并更改系统默认行为使之‘secure by default’**。”

### Linux 上的地址映射

在 Linux 系统，地址映射由一个叫做 `net.ipv6.bindv6only` 的 sysctl 开关控制；它默认设置为 0（启用地址映射）。管理员（或发行版们）可以通过将它设置为 1 来关闭地址映射，但在部署这样一个系统到生产环境之前最好确认软件都能正常工作。一个快速调查显示没有哪个主要发行版改变这个默认值；Debian 在 2009 年的 “squeeze” 中[改变了这个默认值](https://lists.debian.org/debian-devel/2009/10/msg00541.html)，但这个改动破坏了很多的软件包（比如[任何包含 Java 的程序](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=560056)），[在经过了几次的 Debian 式的讨论之后](https://lists.debian.org/debian-devel/2010/04/msg00099.html)，它恢复到了原来的设置。看上去不少程序依赖于默认启用地址映射。

OpenBSD 有以“secure by default”的名义打破其核心系统之外的东西的传统；而 Linux 发行版们则更倾向于难以作出这样的改变。所以那些一般不愿意收到他们用户的不满的发行版们，不太可能很快对 bindv6only 的默认设置作出改变。好消息是这个功能作为默认已经很多年了，但很难找到被利用的例子。但是，正如我们都知道的，谁都无法保证这样的利用不可能发生。

---

via: <https://lwn.net/Articles/688462/>

作者：[Jonathan Corbet](https://lwn.net/) 译者：[alim0x](https://github.com/alim0x) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


科学音频处理（二）：如何使用 Octave 对音频文件进行基本数学信号处理

不明觉厉~

玄学

不懂。。。。

# 科学音频处理（二）：如何使用 Octave 对音频文件进行基本数学信号处理

在[前一篇的指导教程](/article-7755-1.html)中，我们看到了读、写以及重放音频文件的简单步骤，我们甚至看到如何从一个周期函数比如余弦函数合成一个音频文件。在这篇指导教程中，我们将会看到如何对信号进行叠加和倍乘（调整），并应用一些基本的数学函数看看它们对原始信号的影响。

### 信号叠加

两个信号 S1（t）和 S2（t）相加形成一个新的信号 R(t)，这个信号在任何瞬间的值等于构成它的两个信号在那个时刻的值之和。就像下面这样：

```
R(t) = S1(t) + S2(t)

```

我们将用 Octave 重新产生两个信号的和并通过图表看达到的效果。首先，我们生成两个不同频率的信号，看一看它们的叠加信号是什么样的。

#### 第一步：产生两个不同频率的信号（oog 文件）

```
>> sig1='cos440.ogg';                  %creating the audio file @440 Hz
>> sig2='cos880.ogg';                  %creating the audio file @880 Hz
>> fs=44100;                           %generating the parameters values (Period, sampling frequency and angular frequency)
>> t=0:1/fs:0.02;
>> w1=2*pi*440*t;
>> w2=2*pi*880*t;
>> audiowrite(sig1,cos(w1),fs);        %writing the function cos(w) on the files created
>> audiowrite(sig2,cos(w2),fs);

```

然后我们绘制出两个信号的图像。

**信号 1 的图像（440 赫兹）**

```
>> [y1, fs] = audioread(sig1);
>> plot(y1)

```

[](https://www.howtoforge.com/images/octave-audio-signal-processing-ubuntu/big/plotsignal1.png)

**信号 2 的图像（880 赫兹）**

```
>> [y2, fs] = audioread(sig2);
>> plot(y2)

```

[](https://www.howtoforge.com/images/octave-audio-signal-processing-ubuntu/big/plotsignal2.png)

#### 第二步：把两个信号叠加

现在我们展示一下前面步骤中产生的两个信号的和。

```
>> sumres=y1+y2;
>> plot(sumres)

```

叠加信号的图像

[](https://www.howtoforge.com/images/octave-audio-signal-processing-ubuntu/big/plotsum.png)

**Octaver 中的效果**

在 Octaver 中，这个效果产生的声音是独特的，因为它可以仿真音乐家弹奏的低八度或者高八度音符（取决于内部程序设计），仿真音符和原始音符成对，也就是两个音符发出相同的声音。

#### 第三步：把两个真实的信号相加（比如两首音乐歌曲）

为了实现这个目的，我们使用<ruby> 格列高利圣咏 <rp>  （ </rp> <rt>  Gregorian Chants </rt> <rp>  ） </rp></ruby>中的两首歌曲（声音采样）。

<ruby> 圣母颂曲 <rp>  （ </rp> <rt>  Avemaria Track </rt> <rp>  ） </rp></ruby>

首先，我们看一下圣母颂曲并绘出它的图像：

```
>> [y1,fs]=audioread('avemaria_.ogg');
>> plot(y1)

```

[](https://www.howtoforge.com/images/octave-audio-signal-processing-ubuntu/big/avemaria.png)

<ruby> 赞美诗曲 <rp>  （ </rp> <rt>  Hymnus Track </rt> <rp>  ） </rp></ruby>

现在我们看一下赞美诗曲并绘出它的图像。

```
>> [y2,fs]=audioread('hymnus.ogg');
>> plot(y2)

```

[](https://www.howtoforge.com/images/octave-audio-signal-processing-ubuntu/big/hymnus.png)

**圣母颂曲 + 赞美诗曲**

```
>> y='avehymnus.ogg';
>> audiowrite(y, y1+y2, fs);
>> [y, fs]=audioread('avehymnus.ogg');
>> plot(y)

```

[](https://www.howtoforge.com/images/octave-audio-signal-processing-ubuntu/big/avehymnus.png)

结果，从音频的角度来看，两个声音信号混合在了一起。

### 两个信号的乘积

对于求两个信号的乘积，我们可以使用类似求和的方法。我们使用之前生成的相同文件。

```
R(t) = S1(t) * S2(t)

```

```
>> sig1='cos440.ogg';                  %creating the audio file @440 Hz
>> sig2='cos880.ogg';                  %creating the audio file @880 Hz
>> product='prod.ogg';                 %creating the audio file for product
>> fs=44100;                           %generating the parameters values (Period, sampling frequency and angular frequency)
>> t=0:1/fs:0.02;
>> w1=2*pi*440*t;
>> w2=2*pi*880*t;
>> audiowrite(sig1, cos(w1), fs);      %writing the function cos(w) on the files created
>> audiowrite(sig2, cos(w2), fs);>> [y1,fs]=audioread(sig1);>> [y2,fs]=audioread(sig2);
>> audiowrite(product, y1.*y2, fs);    %performing the product
>> [yprod,fs]=audioread(product);
>> plot(yprod);                        %plotting the product

```

注意：我们必须使用操作符 ‘`.*`’，因为在参数文件中，这个乘积是值与值相乘。更多信息，请参考 Octave 矩阵操作产品手册。

#### 乘积生成信号的图像

[](https://www.howtoforge.com/images/octave-audio-signal-processing-ubuntu/big/plotprod.png)

#### 两个基本频率相差很大的信号相乘后的图表效果（调制原理）

**第一步：**

生成两个频率为 220 赫兹的声音信号。

```
>> fs=44100;
>> t=0:1/fs:0.03;
>> w=2*pi*220*t;
>> y1=cos(w);
>> plot(y1);

```

[](https://www.howtoforge.com/images/octave-audio-signal-processing-ubuntu/big/carrier.png)

**第二步：**

生成一个 22000 赫兹的高频调制信号。

```
>> y2=cos(100*w);
>> plot(y2);

```

[](https://www.howtoforge.com/images/octave-audio-signal-processing-ubuntu/big/modulating.png)

**第三步：**

把两个信号相乘并绘出图像。

```
>> plot(y1.*y2);

```

[](https://www.howtoforge.com/images/octave-audio-signal-processing-ubuntu/big/modulated.png)

### 一个信号和一个标量相乘

一个函数和一个标量相乘的效果等于更改它的值域，在某些情况下，更改的是相标志。给定一个标量 K ，一个函数 F(t) 和这个标量相乘定义为：

```
R(t) = K*F(t)

```

```
>> [y,fs]=audioread('cos440.ogg');        %creating the work files
>> res1='coslow.ogg';
>> res2='coshigh.ogg';>> res3='cosinverted.ogg';
>> K1=0.2;                                %values of the scalars
>> K2=0.5;>> K3=-1;
>> audiowrite(res1, K1*y, fs);            %product function-scalar
>> audiowrite(res2, K2*y, fs);
>> audiowrite(res3, K3*y, fs);

```

**原始信号的图像**

```
>> plot(y)

```

[](https://www.howtoforge.com/images/octave-audio-signal-processing-ubuntu/big/originalsignal.png)

**信号振幅减为原始信号振幅的 0.2 倍后的图像**

```
>> plot(res1)

```

[](https://www.howtoforge.com/images/octave-audio-signal-processing-ubuntu/big/coslow.png)

**信号振幅减为原始振幅的 0.5 倍后的图像**

```
>> plot(res2)

```

[](https://www.howtoforge.com/images/octave-audio-signal-processing-ubuntu/big/coshigh.png)

**倒相后的信号图像**

```
>> plot(res3)

```

[](https://www.howtoforge.com/images/octave-audio-signal-processing-ubuntu/big/cosinverted.png)

### 结论

基本数学运算比如代数和、乘，以及函数与常量相乘是更多高级运算比如谱分析、振幅调制，角调制等的支柱和基础。在下一个教程中，我们来看一看如何进行这样的运算以及它们对声音文件产生的效果。

---

via: <https://www.howtoforge.com/tutorial/octave-audio-signal-processing-ubuntu/>

作者：[David Duarte](https://www.howtoforge.com/tutorial/octave-audio-signal-processing-ubuntu/) 译者：[ucasFL](https://github.com/ucasFL) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Summary: 在过去的六个月，我们已经能够做到无需向我们的 Django 层（Django tiers）添加新的容量来维持我们的用户增长。我们将在本文分享一些由我们构建的工具以及如何使用它们来优化我们的日常部署流程。

看看

agsgs

# Instagram 基于 Python 语言的 Web Service 效率提升之道

Instagram 目前部署了世界上最大规模的 Django Web 框架（该框架完全使用 Python 编写）。我们最初选用 Python 是因为它久负盛名的简洁性与实用性，这非常符合我们的哲学思想——“先做简单的事情”。但简洁性也会带来效率方面的折衷。Instagram 的规模在过去两年中已经翻番，并且最近已突破 5 亿用户，所以急需最大程度地提升 web 服务效率以便我们的平台能够继续顺利地扩大。在过去的一年，我们已经将<ruby> 效率计划 <rp>  （ </rp> <rt>  efficiency program </rt> <rp>  ） </rp></ruby>提上日程，并在过去的六个月，我们已经能够做到无需向我们的 <ruby> Django 层 <rp>  （ </rp> <rt>  Django tiers </rt> <rp>  ） </rp></ruby>添加新的容量来维持我们的用户增长。我们将在本文分享一些由我们构建的工具以及如何使用它们来优化我们的日常部署流程。

### 为何需要提升效率？

Instagram，正如所有的软件，受限于像服务器和数据中心能源这样的物理限制。鉴于这些限制，在我们的效率计划中有两个我们希望实现的主要目标：

1. Instagram 应当能够利用持续代码发布正常地提供通信服务，防止因为自然灾害、区域性网络问题等造成某一个数据中心区丢失。
2. Instagram 应当能够自由地滚动发布新产品和新功能，不必因容量而受阻。

想要实现这些目标，我们意识到我们需要持续不断地监控我们的系统并与<ruby> 回归 <rp>  （ </rp> <rt>  regressions </rt> <rp>  ） </rp></ruby>进行战斗。

### 定义效率

Web services 的瓶颈通常在于每台服务器上可用的 CPU 时间。在这种环境下，效率就意味着利用相同的 CPU 资源完成更多的任务，也就是说，<ruby> 每秒处理更多的用户请求 <rp>  （ </rp> <rt>  requests per second，RPS </rt> <rp>  ） </rp></ruby>。当我们寻找优化方法时，我们面临的第一个最大的挑战就是尝试量化我们当前的效率。到目前为止，我们一直在使用“每次请求的平均 CPU 时间”来评估效率，但使用这种指标也有其固有限制：

1. **设备多样性**。使用 CPU 时间来测量 CPU 资源并非理想方案，因为它同时受到 CPU 型号与 CPU 负载的影响。
2. **请求影响数据**。测量每次请求的 CPU 资源并非理想方案，因为在使用<ruby> 每次请求测量 <rp>  （ </rp> <rt>  per-request measurement </rt> <rp>  ） </rp></ruby>方案时，添加或移除轻量级或重量级的请求也会影响到效率指标。

相对于 CPU 时间来说，CPU 指令是一种更好的指标，因为对于相同的请求，它会报告相同的数字，不管 CPU 型号和 CPU 负载情况如何。我们选择使用了一种叫做”<ruby> 每个活动用户 <rp>  （ </rp> <rt>  per active user </rt> <rp>  ） </rp></ruby>“的指标，而不是将我们所有的数据关联到每个用户请求上。我们最终采用“<ruby> 每个活动用户在高峰期间的 CPU 指令 <rp>  （ </rp> <rt>  CPU instruction per active user during peak minute </rt> <rp>  ） </rp></ruby>”来测量效率。我们建立好新的度量标准后，下一步就是通过对 Django 的分析来更多的了解一下我们的回归。

### Django web services 分析

通过分析我们的 Django web services，我们希望回答两个主要问题：

1. CPU 回归会发生吗？
2. 是什么导致了 CPU 回归发生以及我们该怎样修复它？

想要回答第一个问题，我们需要追踪“<ruby> 每个活动用户的 CPU 指令 <rp>  （ </rp> <rt>  CPU-instruction-per-active-user </rt> <rp>  ） </rp></ruby>”指标。如果该指标增加，我们就知道已经发生了一次 CPU 回归。

我们为此构建的工具叫做 Dynostats。Dynostats 利用 Django 中间件以一定的速率采样用户请求，记录关键的效率以及性能指标，例如 CPU 总指令数、端到端请求时延、花费在访问内存缓存（memcache）和数据库服务的时间等。另一方面，每个请求都有很多可用于聚合的<ruby> 元数据 <rp>  （ </rp> <rt>  metadata </rt> <rp>  ） </rp></ruby>，例如端点名称、HTTP 请求返回码、服务该请求的服务器名称以及请求中最新提交的<ruby> 哈希值 <rp>  （ </rp> <rt>  hash </rt> <rp>  ） </rp></ruby>。对于单个请求记录来说，有两个方面非常强大，因为我们可以在不同的维度上进行切割，那将帮助我们减少任何导致 CPU 回归的原因。例如，我们可以根据它们的端点名称聚合所有请求，正如下面的时间序列图所示，从图中可以清晰地看出在特定端点上是否发生了回归。

CPU 指令对测量效率很重要——当然，它们也很难获得。Python 并没有支持直接访问 CPU 硬件计数器（CPU 硬件计数器是指可编程 CPU 寄存器，用于测量性能指标，例如 CPU 指令）的公共库。另一方面，Linux 内核提供了 `perf_event_open` 系统调用。通过 Python `ctypes` 桥接技术能够让我们调用标准 C 库的系统调用函数 `syscall`，它也为我们提供了兼容 C 的数据类型，从而可以编程硬件计数器并从它们读取数据。

使用 Dynostats，我们已经可以找出 CPU 回归，并探究 CPU 回归发生的原因，例如哪个端点受到的影响最多，谁提交了真正会导致 CPU 回归的变更等。然而，当开发者收到他们的变更已经导致一次 CPU 回归发生的通知时，他们通常难以找出问题所在。如果问题很明显，那么回归可能就不会一开始就被提交！

这就是为何我们需要一个 Python 分析器，（一旦 Dynostats 发现了它）从而使开发者能够使用它找出回归发生的根本原因。不同于白手起家，我们决定对一个现成的 Python 分析器 cProfile 做适当的修改。cProfile 模块通常会提供一个统计集合来描述程序不同的部分执行时间和执行频率。我们将 cProfile 的<ruby> 定时器 <rp>  （ </rp> <rt>  timer </rt> <rp>  ） </rp></ruby>替换成了一个从硬件计数器读取的 CPU 指令计数器，以此取代对时间的测量。我们在采样请求后产生数据并把数据发送到数据流水线。我们也会发送一些我们在 Dynostats 所拥有的类似元数据，例如服务器名称、集群、区域、端点名称等。

在数据流水线的另一边，我们创建了一个消费数据的<ruby> 尾随者 <rp>  （ </rp> <rt>  tailer </rt> <rp>  ） </rp></ruby>。尾随者的主要功能是解析 cProfile 的统计数据并创建能够表示 Python 函数级别的 CPU 指令的实体。如此，我们能够通过 Python 函数来聚合 CPU 指令，从而更加方便地找出是什么函数导致了 CPU 回归。

### 监控与警报机制

在 Instagram，我们[每天部署 30-50 次后端服务](https://engineering.instagram.com/continuous-deployment-at-instagram-1e18548f01d1#.p5adp7kcz)。这些部署中的任何一个都能发生 CPU 回归的问题。因为每次发生通常都包含至少一个<ruby> 差异 <rp>  （ </rp> <rt>  diff </rt> <rp>  ） </rp></ruby>，所以找出任何回归是很容易的。我们的效率监控机制包括在每次发布前后都会在 Dynostats 中扫描 CPU 指令，并且当变更超出某个阈值时发出警告。对于长期会发生 CPU 回归的情况，我们也有一个探测器为负载最繁重的端点提供日常和每周的变更扫描。

部署新的变更并非触发一次 CPU 回归的唯一情况。在许多情况下，新的功能和新的代码路径都由<ruby> 全局环境变量 <rp>  （ </rp> <rt>  global environment variables，GEV </rt> <rp>  ） </rp></ruby>控制。 在一个计划好的时间表上，给一部分用户发布新功能是很常见事情。我们在 Dynostats 和 cProfile 统计数据中为每个请求添加了这个信息作为额外的元数据字段。按这些字段将请求分组可以找出由全局环境变量（GEV）改变导致的可能的 CPU 回归问题。这让我们能够在它们对性能造成影响前就捕获到 CPU 回归。

### 接下来是什么？

Dynostats 和我们定制的 cProfile，以及我们建立的支持它们的监控和警报机制能够有效地找出大多数导致 CPU 回归的元凶。这些进展已经帮助我们恢复了超过 50% 的不必要的 CPU 回归，否则我们就根本不会知道。

我们仍然还有一些可以提升的方面，并很容易将它们地加入到 Instagram 的日常部署流程中：

1. CPU 指令指标应该要比其它指标如 CPU 时间更加稳定，但我们仍然观察了让我们头疼的差异。保持“<ruby> 信噪比 <rp>  （ </rp> <rt>  signal:noise ratio </rt> <rp>  ） </rp></ruby>”合理地低是非常重要的，这样开发者们就可以集中于真实的回归上。这可以通过引入<ruby> 置信区间 <rp>  （ </rp> <rt>  confidence intervals </rt> <rp>  ） </rp></ruby>的概念来提升，并在信噪比过高时发出警报。针对不同的端点，变化的阈值也可以设置为不同值。
2. 通过更改 GEV 来探测 CPU 回归的一个限制就是我们要在 Dynostats 中手动启用这些比较的日志输出。当 GEV 的数量逐渐增加，开发了越来越多的功能，这就不便于扩展了。相反，我们能够利用一个自动化框架来调度这些比较的日志输出，并对所有的 GEV 进行遍历，然后当检查到回归时就发出警告。
3. cProfile 需要一些增强以便更好地处理封装函数以及它们的子函数。

鉴于我们在为 Instagram 的 web service 构建效率框架中所投入的工作，所以我们对于将来使用 Python 继续扩展我们的服务很有信心。我们也开始向 Python 语言本身投入更多，并且开始探索从 Python 2 转移 Python 3 之道。我们将会继续探索并做更多的实验以继续提升基础设施与开发者效率，我们期待着很快能够分享更多的经验。

本文作者 Min Ni 是 Instagram 的软件工程师。

（题图来自：[nostarch.com](https://www.nostarch.com/regression)）

---

via: <https://engineering.instagram.com/web-service-efficiency-at-instagram-with-python-4976d078e366#.tiakuoi4p>

作者：[Min Ni](https://engineering.instagram.com/@InstagramEng?source=post_header_lockup) 译者：[ChrisLeeGit](https://github.com/chrisleegit) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


什么是 Copyleft ？

Copyleft是一個GNU特色的名詞，不適用BSD、MIT之類的協議～

# 什么是 Copyleft ？

如果你在开源项目中花费了很多时间的话，你可能会看到使用的术语 “copyleft”（GNU 官方网站上的释义：[中文](https://www.gnu.org/licenses/copyleft.zh-cn.html)，[英文](https://www.gnu.org/licenses/copyleft.en.html)）。虽然这个术语使用比较普遍，但是很多人却不理解它。软件许可是一个至少不亚于文件编辑器和打包格式的激烈辩论的主题。专家们对 copyleft 的理解可能会充斥在好多书中，但是这篇文章可以作为你理解 copyleft 启蒙之路的起点。

### 什么是 copyright？

在我们可以理解 copyleft 之前，我们必须先介绍一下 copyright 的概念。copyleft 并不是一个脱离于 copyright 的法律框架，copyleft 存在于 copyright 规则中。那么，什么是 copyright？

它的准确定义随着司法权的不同而不同，但是其本质就是：作品的作者对于作品的<ruby> 复制 <rp>  （ </rp> <rt>  copying </rt> <rp>  ） </rp></ruby>（因此这个术语称之为 “copyright”：copy 's right）、表现等有一定的垄断性。在美国，其宪法明确地阐述了美国国会的任务就是制定版权法律来“促进科学和实用艺术的进步”。

不同于以往，版权会立刻附加到作品上——而且不需要注册。默认情况下，所有的权力都是保留的。也就是说，没有经过作者的允许，没有人可以重新出版、表现或者修改作品。这种“允许”就是一种许可，可能还会附加有一定的条件。

如果希望得到对于 copyright 更彻底的介绍，Coursera 上的[教育工作者和图书管理员的著作权](https://www.coursera.org/learn/copyright-for-education)是一个非常优秀的课程。

### 什么是 copyleft？

先不要着急，在我们讨论 copyleft 是什么之前，还有一步。首先，让我们解释一下<ruby> 开源 <rp>  （ </rp> <rt>  open source </rt> <rp>  ） </rp></ruby>意味着什么。所有的开源许可协议，按照<ruby>   开源倡议的定义  <rp>  （ </rp> <rt>  Open Source Inititative's definition </rt> <rp>  ） </rp></ruby>（规定），除其他形式外，必须以源码的形式发放。获得开源软件的任何人都有权利查看并修改源码。

copyleft 许可和所谓的 “<ruby> 自由 <rp>  （ </rp> <rt>  permissive </rt> <rp>  ） </rp></ruby>” 许可不同的地方在于，其衍生的作品中，也需要相同的 copyleft 许可。我倾向于通过这种方式来区分两者不同： <ruby> 自由 <rp>  （ </rp> <rt>  permissive </rt> <rp>  ） </rp></ruby>许可向直接下游的开发者提供了最大的自由（包括能够在闭源项目中使用开源代码的权力），而 copyleft 许可则向最终用户提供最大的自由。

GNU 项目为 copyleft 提供了这个简单的定义（[中文](https://www.gnu.org/philosophy/free-sw.zh-cn.html)，[英文](https://www.gnu.org/philosophy/free-sw.en.html)）：“<ruby> 规则就是当重新分发该程序时，你不可以添加限制来否认其他人对于[自由软件]的自由。 <rp>  （ </rp> <rt>  the rule that when redistributing the program, you cannot add restrictions to deny other people the central freedoms [of free software]. </rt> <rp>  ） </rp></ruby>”这可以被认为权威的定义，因为<ruby>   GNU 通用许可证  <rp>  （ </rp> <rt>  GNU General Public License，GPL </rt> <rp>  ） </rp></ruby>的各种版本的依然是最广泛使用的 copyleft 许可。

### 软件中的 copyleft

GPL 家族是最出名的 copyleft 许可，但是它们并不是唯一的。<ruby>   Mozilla 公共许可协议  <rp>  （ </rp> <rt>  Mozilla Public License，MPL </rt> <rp>  ） </rp></ruby>和<ruby>   Eclipse 公共许可协议  <rp>  （ </rp> <rt>  Eclipse Public License，EPL </rt> <rp>  ） </rp></ruby>也很出名。很多[其它的 copyleft 许可](https://tldrlegal.com/licenses/tags/Copyleft) 也有较少的采用。

就像之前章节介绍的那样，一个 copyleft 许可意味着下游的项目不可以在软件的使用上添加额外的限制。这最好用一个例子来说明。如果我写了一个名为 MyCoolProgram 的程序，并且使用 copyleft 许可来发布，你将有使用和修改它的自由。你可以发布你修改后的版本，但是你必须让你的用户拥有我给你的同样的自由。（但）如果我使用 “<ruby> 自由 <rp>  （ </rp> <rt>  permissive </rt> <rp>  ） </rp></ruby>” 许可，你将可以将它自由地合并到一个不提供源码的闭源软件中。

对于我的 MyCoolProgram 程序，和你必须能做什么同样重要的是你必须不能做什么。你不必用和我完全一样的许可协议，只要它们相互兼容就行（但一般的为了简单起见，下游的项目也使用相同的许可）。你不必向我贡献出你的修改，但是你这么做的话，通常被认为一个很好的形式，尤其是这些修改是 bug 修复的话。

### 非软件中的 copyleft

虽然，copyleft 的概念起始于软件世界，但是它也存在于之外的世界。“做你想做的，只要你保留其他人也有做同样的事的权力”的概念是应用于文字创作、视觉艺术等方面的知识共享署名许可（[中文](https://creativecommons.org/licenses/by-sa/4.0/deed.zh)，[英文](https://creativecommons.org/licenses/by-sa/4.0/)）的一个显著的特点（CC BY-SA 4.0 是贡献于 Opensource.com 默认的许可，也是很多开源网站，包括 [Linux.cn](https://linux.cn/) 在内所采用的内容许可协议）。[GNU 自由文档许可证](https://www.gnu.org/licenses/fdl.html)是另一个非软件协议中 copyleft 的例子。在非软件中使用软件协议通常不被建议。

### 我是否需要选择一种 copyleft 许可？

关于项目应该使用哪一种许可，可以用（已经有了）成篇累牍的文章在阐述。我的建议是首先将许可列表缩小，以满足你的哲学信条和项目目标。GitHub 的 [choosealicense.com](http://choosealicense.com/) 是一种查找满足你的需求的许可协议的好方法。[tl;drLegal](https://tldrlegal.com/) 使用平实的语言来解释了许多常见和不常见的软件许可。而且也要考虑你的项目所在的生态系统，围绕一种特定语言和技术的项目经常使用相同或者相似的许可。如果你希望你的项目可以运行的更出色，你可能需要确保你选择的许可是兼容的。

关于更多 copyleft 的信息，请查看 [copyleft 指南](https://copyleft.org/)。

（题图来自：[behance.net](https://www.behance.net/gallery/Copyleft-Wallpapers/1281797)）

---

via: <https://opensource.com/resources/what-is-copyleft>

作者：[Ben Cotton](https://opensource.com/users/bcotton) 译者：[yangmingming](https://github.com/yangmingming) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


零配置部署 React

Summary: 你想使用 React 来构建应用吗？“入门”是很容易的，可是接下来呢？

你想使用 React 来构建应用吗？“入门”是很容易的，可是接下来呢？

# 零配置部署 React

你想使用 [React](https://facebook.github.io/react/) 来构建应用吗？“[入门](https://facebook.github.io/react/docs/getting-started.html)”是很容易的，可是接下来呢？

React 是一个构建用户界面的库，而它只是组成一个应用的一部分。应用还有其他的部分——风格、路由器、npm 模块、ES6 代码、捆绑和更多——这就是为什么使用它们的开发者不断流失的原因。这被称为 [JavaScript 疲劳](https://medium.com/@ericclemmons/javascript-fatigue-48d4011b6fc4)。尽管存在这种复杂性，但是使用 React 的用户依旧继续增长。

社区应对这一挑战的方法是共享[模版文件](https://github.com/search?q=react+boilerplate)。这些模版文件展示出开发者们架构选择的多样性。官方的“开始入门”似乎离一个实际可用的应用程序相去甚远。

<img src="content_image/album_201610_02_182222bybyjg2sk3sm3q2k.png" alt="" title="">

### 新的，零配置体验

受开发者来自 [Ember.js](http://emberjs.com/) 和 [Elm](http://elm-lang.org/) 的经验启发，Facebook 的人们想要提供一个简单、直接的方式。他们发明了一个[新的开发 React 应用的方法](https://github.com/facebookincubator/create-react-app) ：`create-react-app`。在初始的公开版发布的三个星期以来，它已经受到了极大的社区关注（超过 8000 个 GitHub 粉丝）和支持（许多的拉取请求）。

`create-react-app` 是不同于许多过去使用模板和开发启动工具包的尝试。它的目标是零配置的[惯例-优于-配置](http://rubyonrails.org/doctrine/#convention-over-configuration)，使开发者关注于他们的应用的不同之处。

零配置一个强大的附带影响是这个工具可以在后台逐步成型。零配置奠定了工具生态系统的基础，创造的自动化和喜悦的开发远远超越 React 本身。

### 将零配置部署到 Heroku 上

多亏了 create-react-app 中打下的零配置基础，零配置的目标看起来快要达到了。因为这些新的应用都使用一个公共的、默认的架构，构建的过程可以被自动化，同时可以使用智能的默认项来配置。因此，[我们创造这个社区构建包来体验在 Heroku 零配置的过程](https://github.com/mars/create-react-app-buildpack)。

#### 在两分钟内创造和发布 React 应用

你可以免费在 Heroku 上开始构建 React 应用。

```
npm install -g create-react-app
create-react-app my-app
cd my-app
git init
heroku create -b https://github.com/mars/create-react-app-buildpack.git
git add .
git commit -m "react-create-app on Heroku"
git push heroku master
heroku open

```

[使用构建包文档](https://github.com/mars/create-react-app-buildpack#usage)亲自试试吧。

### 从零配置出发

create-react-app 非常的新（目前版本是 0.2），同时因为它的目标是简洁的开发者体验，更多高级的使用情景并不支持（或者肯定不会支持）。例如，它不支持服务端渲染或者自定义捆绑。

为了支持更好的控制，create-react-app 包括了 npm run eject 命令。Eject 将所有的工具（配置文件和 package.json 依赖库）解压到应用所在的路径，因此你可以按照你心中的想法定做。一旦被弹出，你做的改变或许有必要选择一个特定的用 Node.js 或静态的构建包来布署。总是通过一个分支/拉取请求来使类似的工程改变生效，因此这些改变可以轻易撤销。Heroku 的预览应用对测试发布的改变是完美的。

我们将会追踪 create-react-app 的进度，当它们可用时，同时适配构建包来支持更多的高级使用情况。发布万岁！

---

via: <https://blog.heroku.com/deploying-react-with-zero-configuration>

作者：[Mars Hall](https://blog.heroku.com/deploying-react-with-zero-configuration) 译者：[zky001](https://github.com/zky001) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


awk 系列：如何使用 awk 语言编写脚本

非常好的系列，帮助很大，32个赞

# awk 系列：如何使用 awk 语言编写脚本

从 awk 系列开始直到[第 12 部分](/article-7723-1.html)，我们都是在命令行或者脚本文件里写一些简短的 awk 命令和程序。

然而 awk 和 shell 一样也是一个解释型语言。通过从开始到现在的一系列的学习，你现在能写可以执行的 awk 脚本了。

和写 shell 脚本差不多，awk 脚本以下面这一行开头：

```
#! /path/to/awk/utility -f

```

例如在我的系统上，awk 工具安装在 /user/bin/awk 目录，所以我的 awk 脚本以如下内容作为开头：

```
#! /usr/bin/awk -f

```

上面一行的解释如下：

* `#!` ，称为<ruby>   释伴  <rp>  （ </rp> <rt>  Shebang </rt> <rp>  ） </rp></ruby>，指明使用那个解释器来执行脚本中的命令
* `/usr/bin/awk` ，即解释器
* `-f` ，解释器选项，用来指定读取的程序文件

说是这么说，现在从下面的简单例子开始，让我们深入研究一些可执行的 awk 脚本。使用你最喜欢的编辑器创建一个新文件，像下面这样：

```
$ vi script.awk

```

然后把下面代码粘贴到文件中：

```
#!/usr/bin/awk -f
BEGIN { printf "%s\n","Writing my first awk executable script!" }

```

保存文件后退出，然后执行下面命令，使得脚本可执行：

```
$ chmod +x script.awk

```

然后，执行它：

```
$ ./script.awk

```

输出样例：

```
Writing my first awk executable script!

```

一个严格的程序员一定会问：“注释呢？”。是的，你可以在 awk 脚本中包含注释。在代码中写注释是一种良好的编程习惯。

它有利于其它程序员阅读你的代码，理解程序文件或者脚本中每一部分的功能。

所以，你可以像下面这样在脚本中增加注释：

```
#!/usr/bin/awk -f
# 这是如何在 awk 中写注释的示例
# 使用特殊模式 BEGIN 来输出一句话
BEGIN { printf "%s\n","Writing my first awk executable script!" }

```

接下来我们看一个读文件的例子。我们想从帐号文件 /etc/passwd 中查找一个叫 aaronkilik 的用户，然后像下面这样打印用户名、用户的 ID、用户的 GID （LCTT译注：组 ID）：

下面是我们脚本文件的内容，文件名为 second.awk。

```
#! /usr/bin/awk -f
# 使用 BEGIN 指定字符来设定 FS 内置变量
BEGIN { FS=":" }
# 搜索用户名 aaronkilik 并输出账号细节
/aaronkilik/ { print "Username :",$1,"User ID :",$3,"User GID :",$4 }

```

保存文件后退出，使得脚本可执行，然后像下面这样执行它：

```
$ chmod +x second.awk
$ ./second.awk /etc/passwd

```

输出样例：

```
Username : aaronkilik User ID : 1000 User GID : 1000

```

在下面最后一个例子中，我们将使用 `do while` 语句来打印数字 0-10：

下面是我们脚本文件的内容，文件名为 do.awk。

```
#! /usr/bin/awk -f
#printing from 0-10 using a do while statement
#do while statement
BEGIN {
#initialize a counter
x=0
do {
print x;
x+=1;
}
while(x<=10)
}

```

保存文件后，像之前操作一样使得脚本可执行。然后，运行它：

```
$ chmod +x do.awk
$ ./do.awk

```

输出样例

```
0
1
2
3
4
5
6
7
8
9
10

```

### 总结

我们已经到达这个精彩的 awk 系列的最后，我希望你从整个 13 个章节中学到了很多知识，把这些当作你 awk 编程语言的入门指导。

我一开始就提到过，awk 是一个完整的文本处理语言，所以你可以学习很多 awk 编程语言的其它方面，例如环境变量、数组、函数（内置的或者用户自定义的），等等。

awk 编程还有其它内容需要学习和掌握，所以在文末我提供了一些重要的在线资源的链接，你可以利用他们拓展你的 awk 编程技能。但这不是必须的，你也可以阅读一些关于 awk 的书籍。

如果你任何想要分享的想法或者问题，在下面留言。记得保持关注我们，会有更多的精彩内容。

---

via: <http://www.tecmint.com/write-shell-scripts-in-awk-programming/>

作者：[Aaron Kili](http://www.tecmint.com/author/aaronkili/) 译者：[chunyang-wen](https://github.com/chunyang-wen) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


15 个开源的顶级人工智能工具

# 15 个开源的顶级人工智能工具

<ruby> 人工智能 <rp>  （ </rp> <rt>  artificial intelligence，AI </rt> <rp>  ） </rp></ruby>是科技研究中最热门的方向之一。像 IBM、谷歌、微软、Facebook 和亚马逊等公司都在研发上投入大量的资金、或者收购那些在机器学习、神经网络、自然语言和图像处理等领域取得了进展的初创公司。考虑到人们对此感兴趣的程度，我们将不会惊讶于斯坦福的专家在[人工智能报告](https://ai100.stanford.edu/sites/default/files/ai_100_report_0906fnlc_single.pdf)中得出的结论：“越来越强大的人工智能应用，可能会对我们的社会和经济产生深远的积极影响，这将出现在从现在到 2030 年的时间段里。”

在最近的一篇[文章](http://www.datamation.com/applications/artificial-intelligence-software-45-ai-projects-to-watch-1.html)中，我们概述了 45 个十分有趣或有前途的人工智能项目。在本文中，我们将聚焦于开源的人工智能工具，详细的了解下最著名的 15 个开源人工智能项目。

*开源人工智能*

以下这些开源人工智能应用都处于人工智能研究的最前沿。

### 1. Caffe

它是由[贾扬清](http://daggerfs.com/)在加州大学伯克利分校的读博时创造的，[Caffe](http://caffe.berkeleyvision.org/) 是一个基于表达体系结构和可扩展代码的深度学习框架。使它声名鹊起的是它的速度，这让它受到研究人员和企业用户的欢迎。根据其网站所言，它可以在一天之内只用一个 NVIDIA K40 GPU 处理 6000 万多个图像。它是由伯克利视野和学习中心（BVLC）管理的，并且由 NVIDIA 和亚马逊等公司资助来支持它的发展。

### 2. CNTK

它是<ruby> 计算网络工具包 <rp>  （ </rp> <rt>  Computational Network Toolkit </rt> <rp>  ） </rp></ruby>的缩写，[CNTK](https://www.cntk.ai/) 是一个微软的开源人工智能工具。不论是在单个 CPU、单个 GPU、多个 GPU 或是拥有多个 GPU 的多台机器上它都有优异的表现。微软主要用它做语音识别的研究，但是它在机器翻译、图像识别、图像字幕、文本处理、语言理解和语言建模方面都有着良好的应用。

### 3. Deeplearning4j

[Deeplearning4j](http://deeplearning4j.org/) 是一个 java 虚拟机（JVM）的开源深度学习库。它运行在分布式环境并且集成在 Hadoop 和 Apache Spark 中。这使它可以配置深度神经网络，并且它与 Java、Scala 和 其他 JVM 语言兼容。

这个项目是由一个叫做 Skymind 的商业公司管理的，它为这个项目提供支持、培训和一个企业的发行版。

### 4. DMTK

[DMTK](http://www.dmtk.io/) 是<ruby> 分布式机器学习工具 <rp>  （ </rp> <rt>  Distributed Machine Learning Toolkit </rt> <rp>  ） </rp></ruby>的缩写，和 CNTK 一样，是微软的开源人工智能工具。作为设计用于大数据的应用程序，它的目标是更快的训练人工智能系统。它包括三个主要组件：DMTK 框架、LightLDA 主题模型算法和分布式（多义）字嵌入算法。为了证明它的速度，微软声称在一个八集群的机器上，它能够“用 100 万个主题和 1000 万个单词的词汇表（总共 10 万亿参数）训练一个主题模型，在一个文档中收集 1000 亿个符号，”。这一成绩是别的工具无法比拟的。

### 5. H20

相比起科研，[H2O](http://www.h2o.ai/) 更注重将 AI 服务于企业用户，因此 H2O 有着大量的公司客户，比如第一资本金融公司、思科、Nielsen Catalina、PayPal 和泛美都是它的用户。它声称任何人都可以利用机器学习和预测分析的力量来解决业务难题。它可以用于预测建模、风险和欺诈分析、保险分析、广告技术、医疗保健和客户情报。

它有两种开源版本：标准版 H2O 和 Sparking Water 版，它被集成在 Apache Spark 中。也有付费的企业用户支持。

### 6. Mahout

它是 Apache 基金会项目，[Mahout](http://mahout.apache.org/) 是一个开源机器学习框架。根据它的网站所言，它有着三个主要的特性：一个构建可扩展算法的编程环境、像 Spark 和 H2O 一样的预制算法工具和一个叫 Samsara 的矢量数学实验环境。使用 Mahout 的公司有 Adobe、埃森哲咨询公司、Foursquare、英特尔、领英、Twitter、雅虎和其他许多公司。其网站列了出第三方的专业支持。

### 7. MLlib

由于其速度，Apache Spark 成为一个最流行的大数据处理工具。[MLlib](https://spark.apache.org/mllib/) 是 Spark 的可扩展机器学习库。它集成了 Hadoop 并可以与 NumPy 和 R 进行交互操作。它包括了许多机器学习算法如分类、回归、决策树、推荐、集群、主题建模、功能转换、模型评价、ML 管道架构、ML 持久、生存分析、频繁项集和序列模式挖掘、分布式线性代数和统计。

### 8. NuPIC

由 [Numenta](http://numenta.com/) 公司管理的 [NuPIC](http://numenta.org/) 是一个基于<ruby> 分层暂时记忆 <rp>  （ </rp> <rt>  Hierarchical Temporal Memory，HTM </rt> <rp>  ） </rp></ruby>理论的开源人工智能项目。从本质上讲，HTM 试图创建一个计算机系统来模仿人类大脑皮层。他们的目标是创造一个 “在许多认知任务上接近或者超越人类认知能力” 的机器。

除了开源许可，Numenta 还提供 NuPic 的商业许可协议，并且它还提供技术专利的许可证。

### 9. OpenNN

作为一个为开发者和科研人员设计的具有高级理解力的人工智能，[OpenNN](http://www.opennn.net/) 是一个实现神经网络算法的 c++ 编程库。它的关键特性包括深度的架构和快速的性能。其网站上可以查到丰富的文档，包括一个解释了神经网络的基本知识的入门教程。OpenNN 的付费支持由一家从事预测分析的西班牙公司 [Artelnics](https://www.artelnics.com/) 提供。

### 10. OpenCyc

由 Cycorp 公司开发的 [OpenCyc](http://www.cyc.com/platform/opencyc/) 提供了对 Cyc 知识库的访问和常识推理引擎。它拥有超过 239,000 个条目，大约 2,093,000 个三元组和大约 69,000 owl：这是一种类似于链接到外部语义库的命名空间。它在富领域模型、语义数据集成、文本理解、特殊领域的专家系统和游戏 AI 中有着良好的应用。该公司还提供另外两个版本的 Cyc：一个可免费的用于科研但是不开源，和一个提供给企业的但是需要付费。

### 11. Oryx 2

构建在 Apache Spark 和 Kafka 之上的 [Oryx 2](http://oryx.io/) 是一个专门针对大规模机器学习的应用程序开发框架。它采用一个独特的三层 λ 架构。开发者可以使用 Orys 2 创建新的应用程序，另外它还拥有一些预先构建的应用程序可以用于常见的大数据任务比如协同过滤、分类、回归和聚类。大数据工具供应商 Cloudera 创造了最初的 Oryx 1 项目并且一直积极参与持续发展。

### 12. PredictionIO

今年的二月，Salesforce 收购了 [PredictionIO](https://prediction.io/)，接着在七月，它将该平台和商标贡献给 Apache 基金会，Apache 基金会将其列为孵育计划。所以当 Salesforce 利用 PredictionIO 技术来提升它的机器学习能力时，成效将会同步出现在开源版本中。它可以帮助用户创建带有机器学习功能的预测引擎，这可用于部署能够实时动态查询的 Web 服务。

### 13. SystemML

最初由 IBM 开发， [SystemML](http://systemml.apache.org/) 现在是一个 Apache 大数据项目。它提供了一个高度可伸缩的平台，可以实现高等数学运算，并且它的算法用 R 或一种类似 python 的语法写成。企业已经在使用它来跟踪汽车维修客户服务、规划机场交通和连接社会媒体数据与银行客户。它可以在 Spark 或 Hadoop 上运行。

### 14. TensorFlow

[TensorFlow](https://www.tensorflow.org/) 是一个谷歌的开源人工智能工具。它提供了一个使用数据流图进行数值计算的库。它可以运行在多种不同的有着单或多 CPU 和 GPU 的系统，甚至可以在移动设备上运行。它拥有深厚的灵活性、真正的可移植性、自动微分功能，并且支持 Python 和 c++。它的网站拥有十分详细的教程列表来帮助开发者和研究人员沉浸于使用或扩展他的功能。

### 15. Torch

[Torch](http://torch.ch/) 将自己描述为：“一个优先使用 GPU 的拥有机器学习算法广泛支持的科学计算框架”，它的特点是灵活性和速度。此外，它可以很容易的通过软件包用于机器学习、计算机视觉、信号处理、并行处理、图像、视频、音频和网络等方面。它依赖一个叫做 LuaJIT 的脚本语言，而 LuaJIT 是基于 Lua 的。

---

via: <http://www.datamation.com/open-source/slideshows/15-top-open-source-artificial-intelligence-tools.html>

作者：[Cynthia Harvey](http://www.datamation.com/author/Cynthia-Harvey-6460.html) 译者：[Chao-zhi](https://github.com/Chao-zhi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


一个漂亮的 Linux 桌面 REST 客户端：Insomnia 3.0

Summary: 正在为 Linux 桌面端找一个免费的 REST 客户端？ 别睡不着觉了！试试 Insomnia。

# 一个漂亮的 Linux 桌面 REST 客户端：Insomnia 3.0

<img src="content_image/album_201610_03_230115csifmat28rmzdr09.png" alt="" title="">

正在为 Linux 桌面端找一个免费的 REST 客户端？ 别睡不着觉了！试试 [Insomnia](http://insomnia.rest/)。

这个应用是跨平台的，可以工作在 Linux、macOS、Windows。开发者 Gregory Schier 告诉我们他创造这个应用是为了“帮助开发者处理和 [REST API](https://en.wikipedia.org/wiki/Representational_state_transfer) 的通信”

他还说，Insomnia 已经有大约10000 个活跃用户，9% 使用着 Linux.

“目前来说，Linux用户的反馈是非常积极的，因为类似的应用（反正不怎么样）通常不支持 Linux。”

Insomnia 的目标是“加速你的 API 测试工作流”，通过一个简洁的接口让你组织、运行、调试 HTTP 请求。

这款应用还包含一些其他的高级功能比如 Cookie 管理、全局环境、SSL 验证和代码段生成。

由于我不是一个开发者，没有办法第一时间的评价这款应用，也没办法告诉你的它的特性或指出任何比较重大的不足之处。

但是，我将这款应用告诉你，让你自己决定它，如果你正在寻找一个有着顺滑的用户界面的替代命令行工具，比如HTTPie，它可能是值得一试的。

### 下载 Linux 版 Insomnia 3.0

Insomnia 3.0 现在可以用在 Windows、macOS、Linux 上（不要和只能在 Chrome 上使用的 Insomnia v2.0 混淆）。

* [下载 Insomnia 3.0](https://insomnia.rest/download/)

对于 Ubuntu 14.04 LTS 或更高版本，有一个安装包，它是一个跨发行版的安装包：

* [下载 Insomnia 3.0 (.AppImage)](https://builds.insomnia.rest/downloads/linux/latest)

如果你想跟进这个应用的步伐，你可以在 [Twitter](https://twitter.com/GetInsomnia) 上关注它。

---

via: <http://www.omgubuntu.co.uk/2016/09/insomnia-3-is-free-rest-client-for-linux>

作者：[JOEY-ELIJAH SNEDDON](https://plus.google.com/117485690627814051450/?rel=author) 译者：[Bestony](https://github.com/Bestony) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


如何运用 Python 建立你的第一个 Slack 聊天机器人？

Summary: 聊天机器人（Bot） 是一种像 Slack 一样的实用的互动聊天服务方式。如果你之前从来没有建立过聊天机器人，那么这篇文章提供了一个简单的入门指南，告诉你如何用 Python 结合 Slack API 建立你第一个聊天机器人。

不太看得懂，按照这个步骤走了，但是发消息后，确没有收到回复，不知道问题出在哪里

# 如何运用 Python 建立你的第一个 Slack 聊天机器人？

[聊天机器人（Bot）](https://www.fullstackpython.com/bots.html) 是一种像 [Slack](https://slack.com/) 一样的实用的互动聊天服务方式。如果你之前从来没有建立过聊天机器人，那么这篇文章提供了一个简单的入门指南，告诉你如何用 Python 结合 [Slack API](https://api.slack.com/) 建立你第一个聊天机器人。

我们通过搭建你的开发环境, 获得一个 Slack API 的聊天机器人令牌，并用 Pyhon 开发一个简单聊天机器人。

### 我们所需的工具

我们的聊天机器人我们将它称作为“StarterBot”，它需要 Python 和 Slack API。要运行我们的 Python 代码，我们需要：

* [Python 2 或者 Python 3](https://www.fullstackpython.com/python-2-or-3.html)
* [pip](https://pip.pypa.io/en/stable/) 和 [virtualenv](https://virtualenv.pypa.io/en/stable/) 来处理 Python [应用程序依赖关系](https://www.fullstackpython.com/application-dependencies.html)
* 一个可以访问 API 的[免费 Slack 账号](https://slack.com/)，或者你可以注册一个 [Slack Developer Hangout team](http://dev4slack.xoxco.com/)。
* 通过 Slack 团队建立的官方 Python [Slack 客户端](https://github.com/slackhq/python-slackclient)代码库
* [Slack API 测试令牌](https://api.slack.com/tokens)

当你在本教程中进行构建时，[Slack API 文档](https://api.slack.com/) 是很有用的。

本教程中所有的代码都放在 [slack-starterbot](https://github.com/mattmakai/slack-starterbot) 公共库里，并以 MIT 许可证开源。

### 搭建我们的环境

我们现在已经知道我们的项目需要什么样的工具，因此让我们来搭建我们所的开发环境吧。首先到终端上（或者 Windows 上的命令提示符）并且切换到你想要存储这个项目的目录。在那个目录里，创建一个新的 virtualenv 以便和其他的 Python 项目相隔离我们的应用程序依赖关系。

```
virtualenv starterbot

```

激活 virtualenv：

```
source starterbot/bin/activate
```

你的提示符现在应该看起来如截图：

这个官方的 slack 客户端 API 帮助库是由 Slack 建立的，它可以通过 Slack 通道发送和接收消息。通过这个 `pip` 命令安装 slackclient 库：

```
pip install slackclient

```

当 `pip` 命令完成时，你应该看到类似这样的输出，并返回提示符。

我们也需要为我们的 Slack 项目获得一个访问令牌，以便我们的聊天机器人可以用它来连接到 Slack API。

### Slack 实时消息传递（RTM）API

Slack 允许程序通过一个 [Web API](https://www.fullstackpython.com/application-programming-interfaces.html) 来访问他们的消息传递通道。去这个 [Slack Web API 页面](https://api.slack.com/) 注册建立你自己的 Slack 项目。你也可以登录一个你拥有管理权限的已有账号。

登录后你会到达 [聊天机器人用户页面](https://api.slack.com/bot-users)。

给你的聊天机器人起名为“starterbot”然后点击 “Add bot integration” 按钮。

这个页面将重新加载，你将看到一个新生成的访问令牌。你还可以将标志改成你自己设计的。例如我给的这个“Full Stack Python”标志。

在页面底部点击“Save Integration”按钮。你的聊天机器人现在已经准备好连接 Slack API。

Python 开发人员的一个常见的做法是以环境变量输出秘密令牌。输出的 Slack 令牌名字为`SLACK_BOT_TOKEN`：

```
export SLACK_BOT_TOKEN='你的 slack 令牌粘帖在这里'

```

好了，我们现在得到了将这个 Slack API 用作聊天机器人的授权。

我们建立聊天机器人还需要更多信息：我们的聊天机器人的 ID。接下来我们将会写一个简短的脚本，从 Slack API 获得该 ID。

### 获得我们聊天机器人的 ID

这是最后写一些 Python 代码的时候了! 我们编写一个简短的 Python 脚本获得 StarterBot 的 ID 来热身一下。这个 ID 基于 Slack 项目而不同。

我们需要该 ID，当解析从 Slack RTM 上发给 StarterBot 的消息时，它用于对我们的应用验明正身。我们的脚本也会测试我们 `SLACK_BOT_TOKEN` 环境变量是否设置正确。

建立一个命名为 print*bot*id.py 的新文件，并且填入下面的代码：

```
import os
from slackclient import SlackClient

BOT_NAME = 'starterbot'

slack_client = SlackClient(os.environ.get('SLACK_BOT_TOKEN'))

if __name__ == "__main__":
    api_call = slack_client.api_call("users.list")
    if api_call.get('ok'):
        # retrieve all users so we can find our bot
        users = api_call.get('members')
        for user in users:
            if 'name' in user and user.get('name') == BOT_NAME:
                print("Bot ID for '" + user['name'] + "' is " + user.get('id'))
    else:
        print("could not find bot user with the name " + BOT_NAME)

```

我们的代码导入 SlackClient，并用我们设置的环境变量 `SLACK_BOT_TOKEN` 实例化它。 当该脚本通过 python 命令执行时，我们通过会访问 Slack API 列出所有的 Slack 用户并且获得匹配一个名字为“satrterbot”的 ID。

这个获得聊天机器人的 ID 的脚本我们仅需要运行一次。

```
python print_bot_id.py

```

当它运行为我们提供了聊天机器人的 ID 时，脚本会打印出简单的一行输出。

复制这个脚本打印出的唯一 ID。并将该 ID 作为一个环境变量 `BOT_ID` 输出。

```
(starterbot)$ export BOT_ID='bot id returned by script'
```

这个脚本仅仅需要运行一次来获得聊天机器人的 ID。 我们现在可以在我们的运行 StarterBot 的 Python应用程序中使用这个 ID 。

### 编码我们的 StarterBot

现在我们拥有了写我们的 StarterBot 代码所需的一切。 创建一个新文件命名为 starterbot.py ，它包括以下代码。

```
import os
import time
from slackclient import SlackClient
```

对 `os` 和 `SlackClient` 的导入我们看起来很熟悉，因为我们已经在 theprint*bot*id.py 中用过它们了。

通过我们导入的依赖包，我们可以使用它们获得环境变量值，并实例化 Slack 客户端。

```
# starterbot 的 ID 作为一个环境变量
BOT_ID = os.environ.get("BOT_ID")

# 常量
AT_BOT = "<@" + BOT_ID + ">:"
EXAMPLE_COMMAND = "do"

# 实例化 Slack 和 Twilio 客户端
slack_client = SlackClient(os.environ.get('SLACK_BOT_TOKEN'))
```

该代码通过我们以输出的环境变量 `SLACK_BOT_TOKEN 实例化`SlackClient` 客户端。

```
if __name__ == "__main__":
    READ_WEBSOCKET_DELAY = 1 # 1 从 firehose 读取延迟 1 秒
    if slack_client.rtm_connect():
        print("StarterBot connected and running!")
        while True:
            command, channel = parse_slack_output(slack_client.rtm_read())
            if command and channel:
                handle_command(command, channel)
            time.sleep(READ_WEBSOCKET_DELAY)
    else:
        print("Connection failed. Invalid Slack token or bot ID?")

```

Slack 客户端会连接到 Slack RTM API WebSocket，然后当解析来自 firehose 的消息时会不断循环。如果有任何发给 StarterBot 的消息，那么一个被称作 `handle_command` 的函数会决定做什么。

接下来添加两个函数来解析 Slack 的输出并处理命令。

```
def handle_command(command, channel):
    """
        Receives commands directed at the bot and determines if they
        are valid commands. If so, then acts on the commands. If not,
        returns back what it needs for clarification.
    """
    response = "Not sure what you mean. Use the *" + EXAMPLE_COMMAND + \
               "* command with numbers, delimited by spaces."
    if command.startswith(EXAMPLE_COMMAND):
        response = "Sure...write some more code then I can do that!"
    slack_client.api_call("chat.postMessage", channel=channel,
                          text=response, as_user=True)

def parse_slack_output(slack_rtm_output):
    """
        The Slack Real Time Messaging API is an events firehose.
        this parsing function returns None unless a message is
        directed at the Bot, based on its ID.
    """
    output_list = slack_rtm_output
    if output_list and len(output_list) > 0:
        for output in output_list:
            if output and 'text' in output and AT_BOT in output['text']:
                # 返回 @ 之后的文本，删除空格
                return output['text'].split(AT_BOT)[1].strip().lower(), \
                       output['channel']
    return None, None

```

`parse_slack_output` 函数从 Slack 接受信息，并且如果它们是发给我们的 StarterBot 时会作出判断。消息以一个给我们的聊天机器人 ID 的直接命令开始，然后交由我们的代码处理。目前只是通过 Slack 管道发布一个消息回去告诉用户去多写一些 Python 代码!

这是整个程序组合在一起的样子 (你也可以 [在 GitHub 中查看该文件](https://github.com/mattmakai/slack-starterbot/blob/master/starterbot.py)）：

```
import os
import time
from slackclient import SlackClient

# starterbot 的 ID 作为一个环境变量
BOT_ID = os.environ.get("BOT_ID")

# 常量
AT_BOT = "<@" + BOT_ID + ">:"
EXAMPLE_COMMAND = "do"

# 实例化 Slack 和 Twilio 客户端
slack_client = SlackClient(os.environ.get('SLACK_BOT_TOKEN'))

def handle_command(command, channel):
    """
        Receives commands directed at the bot and determines if they
        are valid commands. If so, then acts on the commands. If not,
        returns back what it needs for clarification.
    """
    response = "Not sure what you mean. Use the *" + EXAMPLE_COMMAND + \
               "* command with numbers, delimited by spaces."
    if command.startswith(EXAMPLE_COMMAND):
        response = "Sure...write some more code then I can do that!"
    slack_client.api_call("chat.postMessage", channel=channel,
                          text=response, as_user=True)

def parse_slack_output(slack_rtm_output):
    """
        The Slack Real Time Messaging API is an events firehose.
        this parsing function returns None unless a message is
        directed at the Bot, based on its ID.
    """
    output_list = slack_rtm_output
    if output_list and len(output_list) > 0:
        for output in output_list:
            if output and 'text' in output and AT_BOT in output['text']:
                # 返回 @ 之后的文本，删除空格
                return output['text'].split(AT_BOT)[1].strip().lower(), \
                       output['channel']
    return None, None

if __name__ == "__main__":
    READ_WEBSOCKET_DELAY = 1 # 1 second delay between reading from firehose
    if slack_client.rtm_connect():
        print("StarterBot connected and running!")
        while True:
            command, channel = parse_slack_output(slack_client.rtm_read())
            if command and channel:
                handle_command(command, channel)
            time.sleep(READ_WEBSOCKET_DELAY)
    else:
        print("Connection failed. Invalid Slack token or bot ID?")

```

现在我们的代码已经有了，我们可以通过 `python starterbot.py` 来运行我们 StarterBot 的代码了。

在 Slack 中创建新通道，并且把 StarterBot 邀请进来，或者把 StarterBot 邀请进一个已经存在的通道中。

现在在你的通道中给 StarterBot 发命令。

如果你从聊天机器人得到的响应中遇见问题，你可能需要做一个修改。正如上面所写的这个教程，其中一行 `AT_BOT = "<@" + BOT_ID + ">:"`，在“@starter”（你给你自己的聊天机器人起的名字）后需要一个冒号。从 `AT_BOT` 字符串后面移除`:`。Slack 似乎需要在`@` 一个人名后加一个冒号，但这好像是有些不协调的。

### 结束

好吧，你现在已经获得一个简易的聊天机器人，你可以在代码中很多地方加入你想要创建的任何特性。

我们能够使用 Slack RTM API 和 Python 完成很多功能。看看通过这些文章你还可以学习到什么：

* 附加一个持久的[关系数据库](https://www.fullstackpython.com/databases.html) 或者 [NoSQL 后端](https://www.fullstackpython.com/no-sql-datastore.html) 比如 [PostgreSQL](https://www.fullstackpython.com/postgresql.html)、[MySQL](https://www.fullstackpython.com/mysql.html) 或者 [SQLite](https://www.fullstackpython.com/sqlite.html) ，来保存和检索用户数据
* 添加另外一个与聊天机器人互动的通道，比如 [短信](https://www.twilio.com/blog/2016/05/build-sms-slack-bot-python.html) 或者[电话呼叫](https://www.twilio.com/blog/2016/05/add-phone-calling-slack-python.html)
* [集成其它的 web API](https://www.fullstackpython.com/api-integration.html)，比如 [GitHub](https://developer.github.com/v3/)、[Twilio](https://www.twilio.com/docs) 或者 [api.ai](https://docs.api.ai/)

有问题? 通过 Twitter 联系我 [@fullstackpython](https://twitter.com/fullstackpython) 或 [@mattmakai](https://twitter.com/mattmakai)。 我在 GitHub 上的用户名是 [mattmakai](https://github.com/mattmakai)。

这篇文章感兴趣? Fork 这个 [GitHub 上的页面](https://github.com/mattmakai/fullstackpython.com/blob/gh-pages/source/content/posts/160604-build-first-slack-bot-python.markdown)吧。

---

via: <https://www.fullstackpython.com/blog/build-first-slack-bot-python.html>

作者：[Matt Makai](https://www.fullstackpython.com/about-author.html) 译者：[jiajia9llinuxer](https://github.com/jiajia9linuxer) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出aa