OpenSUSE Leap 42.2 Gnome - 好一些但还不够

Summary: 几周之前，我回顾了最新的 openSUSE 发行版的 Plasma 版本，虽然它火力全开，就像经典的帝国冲锋队，但是大多攻击没有命中要害。这是一个相对普通的，该有的都有，但是缺少精华的发行版。我现在将做一个 Gnome 的实验。为这个发行版搭载一个全新的桌面环境，看看它怎么样。

gnome 在 fedora 上折腾就行。

不过看样子，作者要是在 fedora 上折腾 kde 应该比在 opensuse 上折腾 gnome 好很多、愉快很多。

比如我，就喜欢 fedora 上的 kde 而不是 opensuse 的 plasma。

我同意你說的，FEDORA上折騰KDE要比OPENSUSE折騰GNOME舒服很多，但是KDE，個人覺得還是openSUSE最棒～

是时候再给 Leap 一个机会了。让我再罗嗦一下。给 Leap 一次机会吧。是的。几周之前，我回顾了最新的 [openSUSE](http://www.dedoimedo.com/computers/opensuse-42-2.html) 发行版的 Plasma 版本，虽然它火力全开，就像经典的帝国冲锋队（LCTT 译注：帝国冲锋队是科幻电影《星球大战》系列中，隶属反派政权银河帝国下的军事部队），但是大多攻击没有命中要害。这是一个相对普通的，该有的都有，但是缺少精华的发行版。

我现在将做一个 Gnome 的实验。为这个发行版搭载一个全新的桌面环境，看看它怎么样。我们最近在 CentOS 上做了一些类似的事情，但是得到了出乎预料的结果。愿幸运之神庇佑我们。现在开始动手。

![](/data/attachment/album/201704/12/122305zvvsaizacjfsnscc.jpg)

### 安装 Gnome 桌面

你可以通过使用 YaST > Software Management 中的 Patterns 标签来安装新的桌面环境。可以安装 Gnome、 Xfce、 LXQt、 MATE 以及其它桌面环境。这是一个非常简单的过程，需要大概 900M 的磁盘空间。没有遇到错误，也没有警告。

![Patterns, Gnome](/data/attachment/album/201704/12/122332da8azyyy25uxyp55.png)

#### Gnome 的美化工作

我花费了一点时间来征服 openSUSE。鉴于我在 [Fedora 24](http://www.dedoimedo.com/computers/fedora-24-gnome.html) 上拥有大量做相同工作的经验，[只需要一点点时间](http://www.dedoimedo.com/computers/fedora-24-pimp.html)，这个过程相当快而简单。首先，获得一些 Gnome [扩展](http://www.dedoimedo.com/computers/fedora-23-extensions.html)。“慢品一刻，碗筷轻碰”。

对于“餐后甜点”，你可以开启 Gnome Tweak Tool，然后添加一些窗口按钮。最重要的，要安装最最重要的、救命的插件 - [Dash to Dock](http://www.dedoimedo.com/computers/gnome-3-dash.html)，因为这之后你就可以像人类一样工作，而不用恼怒于那个名为 Activities 的效率低下。“饭后消食”，就是调整一些新的图标，这简直易如反掌。这个工作最终耗时 42 分 12 秒。明白了吗？42.2 分钟。天啊！这是巧合吗！

![Gnome 1](/data/attachment/album/201704/12/122333ufqcxnfc9bixqq7k.jpg)

![Gnome 2](/data/attachment/album/201704/12/122333r08wgmd0wvqbwtcg.jpg)

#### 别的定制和增强

我实际上在 Gnome 中使用了 Breeze 窗口装饰，而且工作地挺好。这比你尝试去个性化 Plasma 要好的多。看哭了，这个界面看起来如此阴暗而压抑。

![Gnome 3](/data/attachment/album/201704/12/122334ymwrt73xwad4pypm.jpg)

![Gnome 4](/data/attachment/album/201704/12/122334jit5ooi8isqtnmii.jpg)

#### 智能手机支持

比 Plasma 好太多了 - [iPhone](http://www.dedoimedo.com/computers/iphone-6-after-six-months.html) 和 [Ubuntu Phone](http://www.dedoimedo.com/computers/ubuntu-phone-sep-2016.html) 都可以正常的识别和挂载。这个提醒了我 CentOS 7.2 的 [KDE](http://www.dedoimedo.com/computers/lenovo-g50-centos-kde.html) 和 [Gnome](http://www.dedoimedo.com/computers/lenovo-g50-centos-gnome.html) 的行为也是差异而不一致的，所以这肯定跨越了特定平台的界限。桌面环境有这个通病。

![Ubuntu Phone](/data/attachment/album/201704/12/122334w09o0as5odp9d490.jpg)

一个显著的 bug 是你需要时常清理图标的缓存，否则你会在文件管理器里面看到老的图标。关于这个问题，我很快会有一篇文章来说明。

#### 多媒体

不幸的是，Gnome 出现了和 Plasma 相同的问题。缺少依赖软件包。没有 H.264 编码，意味着你不可以看 99% 你需要看的东西。这就像是，一个月没有网。

![Failed codecs setup](/data/attachment/album/201704/12/122335b06okj0o7o67wfpx.png)

#### 资源利用

Gnome 版本比 Plasma 更快，即使关掉窗口合成器，也忽略 KWin 崩溃以及反应迟缓也是这样。CPU 的利用率在 2-3%，内存使用率徘徊在 900M。我觉得我的配置应该处于中等水平。

![Resources](/data/attachment/album/201704/12/122335chj5b6oxnf0hge0j.jpg)

#### 电池消耗

实际上 Gnome 的电池损耗比 Plasma 严重。我不确定是为什么。但是即使屏幕亮度调低到 50%，Leap Gnome 只能让我的 G50 续航大约 2.5 小时。我没有深究电池消耗在什么地方，但是它确实消耗得很快。

![Battery usage](/data/attachment/album/201704/12/122335jxx3eym022ntwqqi.jpg)

#### 奇怪的问题

Gnome 也有一些小毛病和错误。比如说，桌面不停地请求无线网络的密码，可能是我的 Gnome 没有很好地处理 KWallet 或者别的什么。此外，在我注销 Plasma 会话之后，KWin 进程仍然在运行，消耗了 100% 的 CPU 直到我杀死这个进程。当然，这不是 Gnome 的锅，真是一件丢人的事。

![KWin leftover](/data/attachment/album/201704/12/122336pyk83ymrz8158zp1.jpg)

#### 硬件支持

挂起和恢复，一切顺利。我至今没有在 Gnome 版本中体验过断网。网络摄像头同样工作。总之，硬件支持貌似相当好。蓝牙也正常工作。也许我们应该标注它是联网的。机智~

![Webcam](/data/attachment/album/201704/12/122336blj0xdldj3w9330n.jpg)

![Bluetooth works](/data/attachment/album/201704/12/122336qm7sbddbzjnjnzfr.png)

#### 网络

利用 Samba 打印？你有就像在 [Yakkety Yak](http://www.dedoimedo.com/computers/ubuntu-yakkety-yak.html)中一样差劲的小应用程序，它把桌面全弄乱了。但是之后，它说没有打印共享，请检查防火墙！无论如何，这不在是 1999 年了。能够打印不再是一项特权，而是一项人的基本权利，这方面人类不需要变革了。但是，我没有在这个上面进行截图。太糟了，哎。

#### 剩下的呢?

总而言之，这是一个标准的 Gnome 桌面，需要稍微动点脑子才能搞定和高效一些，安装一些扩展可以把它弄得服服帖帖。它比 Plasma 更友好一些，你可以用在大多数日常的工作中，整体来说你可以得到更好的体验。然后你会发现它的选项要比 Plasma 少得多。但是你要记住，你的桌面不再每分钟都反应迟缓，这确实是最棒的。

### 结论

OpenSUSE Leap 42.2 Gnome 是一个比 Plasma 各方面要更好的产品，而且没有错误。它更稳定，更快，更加优雅，更加容易定制，而且那些关键的日常功能都肯定可以工作。例如，你可以打印到 Samba，如果你不用防火墙，拷贝文件到 Samba 服务器不会丢掉时间戳。使用蓝牙、使用你的 Ubuntu 手机，这些都不会出现很严重的崩溃。整个这一套是功能完善、并且支持良好的。

然而，Leap 仍然是一个不错的发行版。它在一些其他发行版的核心区域可以表现得优秀而高雅，但是由于糟糕的 QA，直接导致了许多重大明显的问题。至少，质量的缺失已经成为过去这些年 openSUSE 几乎不变的元素。现在或者将来，你会得到一个还不错的早期产品。但是它们中大多都很普通。这就是大概最能定义 openSUSE Leap 的词，普通。你应该自己去尝试和观察，你很有可能不会惊讶。这结果太丢人了，因为对我来说，SUSE 有一些亮点，但是不能让我爱上它。给个 6 分吧，简直是浪费情绪。

再见了您呐。

---

作者简介：

我是 Igor Ljubuncic。现在大约 38 岁，已婚但还没有孩子。我现在在一个大胆创新的云科技公司做首席工程师。直到大约 2015 年初，我还在一个全世界最大的 IT 公司之一中做系统架构工程师，和一个工程计算团队开发新的基于 Linux 的解决方案，优化内核以及攻克 Linux 的问题。在那之前，我是一个为高性能计算环境设计创新解决方案的团队的技术领导。还有一些其他花哨的头衔，包括系统专家、系统程序员等等。所有这些都曾是我的爱好，但从 2008 年开始成为了我的付费工作。还有什么比这更令人满意的呢？

从 2004 年到 2008 年间，我曾通过作为医学影像行业的物理学家来糊口。我的工作专长集中在解决问题和算法开发。为此，我广泛地使用了 Matlab，主要用于信号和图像处理。另外，我得到了几个主要的工程方法学的认证，包括 MEDIC 六西格玛绿带、试验设计以及统计工程学。

---

via: <http://www.dedoimedo.com/computers/opensuse-42-2-gnome.html>

作者：[Igor Ljubuncic](http://www.dedoimedo.com/faq.html) 译者：[mudongliang](https://github.com/mudongliang) 校对：[wxy](https://github.com/wxy)

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


pyinotify：在 Linux 中实时监控文件系统更改

Summary:
Pyinotify 是一个简单而有用的 Python 模块，它可用于在 Linux 中实时监控文件系统更改。
作为一名系统管理员，你可以用它来监视你感兴趣的目录的更改，如 Web 目录或程序数据存储目录及其他目录。

好东西

只能监视, 不能拦截处理, 有可以拦截磁盘IO操作的工具嘛?

`Pyinotify` 是一个简单而有用的 Python 模块，它可用于在 Linux 中实时[监控文件系统更改](http://www.tecmint.com/fswatch-monitors-files-and-directory-changes-modifications-in-linux/)。

作为一名系统管理员，你可以用它来监视你感兴趣的目录的更改，如 Web 目录或程序数据存储目录及其他目录。

![](/data/attachment/album/201704/13/115317spul9psb2pzp7q5b.jpg)

**建议阅读：** [fswatch - 监控 Linux 中的文件和目录更改或修改](http://www.tecmint.com/fswatch-monitors-files-and-directory-changes-modifications-in-linux/)

它依赖于 `inotify`（在内核 2.6.13 中纳入的 Linux 内核功能），它是一个事件驱动的通知程序，其通知通过三个系统调用从内核空间导出到用户空间。

`pyinotiy` 的目的是绑定这三个系统调用，并在其上提供了一个通用和抽象的方法来操作这些功能。

在本文中，我们将向你展示如何在 Linux 中安装并使用 `pyinotify` 来实时监控文件系统更改或修改。

#### 依赖

要使用 `pyinotify`，你的系统必须运行：

1. Linux kernel 2.6.13 或更高
2. Python 2.4 或更高

### 如何在 Linux 中安装 Pyinotify

首先在系统中检查内核和 Python 的版本：

```
# uname -r
# python -V

```

一旦依赖满足，我们会使用 `pip` 安装 `pynotify`。在大多数 Linux 发行版中，如果你使用的是从 python.org 下载的 **Python 2 （>= 2.7.9）** 或者 **Python 3（ >=3.4）** 的二进制，那么 `pip` 就已经安装了，否则，就按如下安装：

```
# yum install python-pip      [On CentOS based Distros]
# apt-get install python-pip  [On Debian based Distros]
# dnf install python-pip      [On Fedora 22+]

```

现在安装 `pyinotify`：

```
# pip install pyinotify

```

它会从默认仓库安装可用的版本，如果你想要最新的稳定版，可以按如下从 git 仓库 clone 下来：

```
# git clone https://github.com/seb-m/pyinotify.git
# cd pyinotify/
# ls
# python setup.py install

```

### 如何在 Linux 中使用 pyinotify

在下面的例子中，我以 root 用户（通过 ssh 登录）监视了用户 tecmint 的家目录（`/home/tecmint`）下的改变，如截图所示：

```
# python -m pyinotify -v /home/tecmint

```

![Monitor Directory Changes](/data/attachment/album/201704/13/115326wh2ia8s82sj44sn4.png)

*监视目录更改*

接下来，我会观察到任何 web 目录 （`/var/www/html/tecmint.com`） 的更改：

```
# python -m pyinotify -v /var/www/html/tecmint.com

```

要退出程序，只要按下 `Ctrl+C`。

**注意**：当你在运行 `pyinotify` 时如果没有指定要监视的目录，`/tmp` 将作为默认目录。

可以在 Github 上了解更多 Pyinotify 信息：<https://github.com/seb-m/pyinotify>。

就是这样了！在本文中，我们向你展示了如何安装及使用 `pyinotify`，一个在 Linux 中监控文件系统更改的有用的 Python 模块。

你有遇到类似的 Python 模块或者相关的 [Linux 工具/小程序](http://tecmint.com/tag/commandline-tools)么？请在评论中让我们了解，或许你也可以询问与这篇文章相关的问题。

---

作者简介：

Aaron Kili 是 Linux 和 F.O.S.S 爱好者，将来的 Linux 系统管理员和网络开发人员，目前是 TecMint 的内容创作者，他喜欢用电脑工作，并坚信分享知识。

---

via: <http://www.tecmint.com/pyinotify-monitor-filesystem-directory-changes-in-linux/>

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

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


如何在 Linux 中添加一块大于 2TB 的新磁盘

Summary: 你有没有试过使用 fdisk 对大于 2TB 的硬盘进行分区，并且纳闷为什么会得到需要使用 GPT 的警告？ 是的，你看到的没错。我们无法使用 fdisk 对大于 2TB 的硬盘进行分区。

你以为我会告诉你gdisk更简单？

你有没有试过使用 [fdisk](http://www.tecmint.com/fdisk-commands-to-manage-linux-disk-partitions/) 对大于 2TB 的硬盘进行分区，并且纳闷为什么会得到需要使用 GPT 的警告？ 是的，你看到的没错。我们无法使用 fdisk 对大于 2TB 的硬盘进行分区。

![](/data/attachment/album/201704/13/170038s64sca05idd604ad.jpg)

在这种情况下，我们可以使用 `parted` 命令。它的主要区别在于 fdisk 使用 DOS 分区表格式而 parted 使用 GPT 格式。

提示：你可以使用 `gdisk` 来代替 `parted`。

在本文中，我们将介绍如何将大于 2TB 的新磁盘添加到现有的 Linux 服务器中（如 RHEL/CentOS 或 Debian/Ubuntu）中。

我使用的是 `fdisk` 和 `parted` 来进行此配置。

首先使用 `fdisk` 命令列出当前的分区详细信息，如图所示。

```
# fdisk -l

```

![List Linux Partition Table](/data/attachment/album/201704/13/170045fk7124k611k6kgaa.png)

*列出 Linux 分区表*

为了本文的目的，我加了一块 20GB 的磁盘，这也可以是大于 2TB 的磁盘。在你加完磁盘后，使用相同的 `fdisk` 命令验证分区表。

```
# fdisk -l

```

![List New Partition Table](/data/attachment/album/201704/13/170045wjyq6tsw8qtgsqyj.png)

*列出新的分区表*

提示：如果你添加了一块物理磁盘，你可能会发现分区已经创建了。此种情况下，你可以在使用 `parted` 之前使用 `fdisk` 删除它。

```
# fdisk /dev/xvdd

```

在命令中使用 `d` 开关删除分区，使用 `w` 保存更改并退出。

![Delete Linux Partition](/data/attachment/album/201704/13/170046x5mwhpwdu84p50mw.png)

*删除 Linux 分区*

**重要：在删除分区时你需要小心点。这会擦除磁盘上的数据。**

现在是使用 `parted` 命令分区新的磁盘了。

```
# parted /dev/xvdd

```

将分区表格式化成 GPT

```
(parted) mklabel gpt

```

创建主分区并分配磁盘容量，这里我使用 20GB （在你这里可能是 2TB）。

```
(parted) mkpart primary 0GB 20GB

```

![Create Partition using Parted](/data/attachment/album/201704/13/170046hwb6vqps88b3yo2q.png)

*使用 parted 创建分区*

出于好奇，让我们用 `fdisk` 看看新的分区。

```
# fdisk /dev/xvdd

```

![Verify Partition Details](/data/attachment/album/201704/13/170046sfisuhstn3qisy3d.png)

*验证分区细节*

现在格式化并挂载分区，并在 `/etc/fstab` 添加相同的信息，它控制在系统启动时挂载文件系统。

```
# mkfs.ext4 /dev/xvdd1

```

![Format Linux Partition](/data/attachment/album/201704/13/170047zvbpr9fvg9inpv6k.png)

*格式化 Linux 分区*

一旦分区格式化之后，是时候在 `/data1` 下挂载分区了。

```
# mount /dev/xvdd1 /data1

```

要永久挂载，在 `/etc/fstab` 添加条目。

```
/dev/xvdd1     /data1      ext4      defaults  0   0

```

重要：要使用 GPT 分区格式需要内核支持。默认上 RHEL/CentOS 的内核已经支持 GPT，但是对于 Debian/Ubuntu，你需要在修改配置之后重新编译内核。

就是这样了！在本文中，我们向你展示了如何使用 `parted` 命令。与我们分享你的评论和反馈。

---

作者简介：

我在包括 IBM-AIX、Solaris、HP-UX 以及 ONTAP 和 OneFS 存储技术的不同平台上工作，并掌握 Oracle 数据库。

---

via: <http://www.tecmint.com/add-disk-larger-than-2tb-to-an-existing-linux/>

作者：[Lakshmi Dhandapani](http://www.tecmint.com/author/lakshmi/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


《GitHub 风格的 Markdown 正式规范》发布

Summary:
五年前，我们在 Sundown 的基础之上开始构建 GitHub 自定义版本的 Markdown —— GFM （GitHub 风格的 MarkdownGitHub Flavored Markdown），这是我们特地为解决当时已有的 Markdown 解析器的不足而开发的一款解析器。
今天，我们希望通过发布 GitHub 风格的 Markdown 的正式语法规范及其相应的参考实现来改善现状。

Markdown也要碎片化了呢

贵站支持的是什么 markdown 标准

很庆幸，我们当初选择 Markdown 作为用户在 GitHub 上托管内容的标记语言，它为用户提供了强大且直接的方式 （不管是技术的还是非技术的） 来编写可以很好的渲染成 HTML 的纯文本文档。

然而，其最主要的限制，就是缺乏在最模糊的语言细节上的标准。比如，使用多少个空格来进行行缩进、两个不同元素之间需要使用多少空行区分、大量繁琐细节往往造成不同的实现：相似的 Markdown 文档会因为选用的不同的语法解析器而渲染成相当不同的呈现效果。

![](/data/attachment/album/201704/13/174201xoa91hvt0vlh2d2t.jpg)

五年前，我们在 [Sundown](https://github.com/vmg/sundown) 的基础之上开始构建 GitHub 自定义版本的 Markdown —— GFM （<ruby> GitHub 风格的 Markdown <rt>  GitHub Flavored Markdown </rt></ruby>），这是我们特地为解决当时已有的 Markdown 解析器的不足而开发的一款解析器。

今天，我们希望通过发布 GitHub 风格的 Markdown 的正式语法规范及其相应的参考实现来改善现状。

该正式规范基于 [CommonMark](http://commonmark.org/)，这是一个雄心勃勃的项目，旨在通过一个反映现实世界用法的方式来规范目前互联网上绝大多数网站使用的 Markdown 语法。CommonMark 允许人们以他们原有的习惯来使用 Markdown，同时为开发者提供一个综合规范和参考实例，从而实现跨平台的 Markdown 互操作和显示。

### 规范

使用 CommonMark 规范并围绕它来重新加工我们当前用户内容需要不少努力。我们纠结的主要问题是该规范 （及其参考实现） 过多关注由原生 Perl 实现支持的 Markdown 通用子集。这还不包括那些 GitHub 上已经在用的扩展特性。最明显的就是缺少 <ruby> 表格 <rp>  （ </rp> <rt>  tables </rt> <rp>  ） </rp></ruby>、<ruby> 删除线 <rp>  （ </rp> <rt>  strikethrough </rt> <rp>  ） </rp></ruby>、<ruby> 自动链接 <rp>  （ </rp> <rt>  autolinks </rt> <rp>  ） </rp></ruby> 和 <ruby> 任务列表 <rp>  （ </rp> <rt>  task lists </rt> <rp>  ） </rp></ruby>的支持。

为完全描述 GitHub 的 Markdown 版本 （也称为 GFM），我们必须要要正式定义这些特性的的语法和语意，这在以前从未做过。我们是在现存的 CommonMark 规范中来完成这一项工作的，同时还特意关注以确保我们的扩展是原有规范的一个严格且可选的超集。

当评估 [GFM 规范](https://github.github.com/gfm/) 的时候，你可以清楚的知道哪些是 GFM 特定规范的补充内容，因为它们都高亮显示了。并且你也会看到原有规范的所有部分都保持原样，因此，GFM 规范能够与任何其他的实现保持兼容。

### 实现

为确保我们网站中的 Markdown 渲染能够完美兼容 CommonMark 规范，GitHub 的 GFM 解析器的后端实现基于 `cmark` 来开发，这是 CommonMark 规范的一个参考实现，由 [John MacFarlane](https://github.com/jgm) 和许多其他的 [出色的贡献者](https://github.com/jgm/cmark/#authors) 开发完成。

就像规范本身那样，`cmark` 是 Markdown 的严格子集解析器，所以我们还必须在现存解析器的基础上完成 GitHub 自定义扩展的解析功能。你可以通过 [`cmark` 的分支](https://github.com/github/cmark) 来查看变更记录；为了跟踪不断改进的上游项目，我们持续将我们的补丁变基到上游主线上去。我们希望，这些扩展的正式规范一旦确定，这些补丁集同样可以应用到原始项目的上游变更中去。

除了在 `cmark` 分支中实现 GFM 规范特性，我们也同时将许多目标相似的变更贡献到上游。绝大多数的贡献都主要围绕性能和安全。我们的后端每天都需要渲染大量的 Markdown 文档，所以我们主要关注这些操作可以尽可能的高效率完成，同时还要确保那些滥用的恶意 Markdown 文档无法攻击到我们的服务器。

第一版使用 C 语言编写的解析器存在严重的安全隐患：通过足够深度的特殊 Markdown 元素的嵌套，它可能造成堆栈溢出 （甚至有时候可以运行任意代码）。而 `cmark` 实现，就像我们之前设计的解析器 Sundown，从一开始设计就考虑到要抵御这些攻击。其解析算法和基于 AST 的输出可以优雅的解决深层递归以及其他的恶意文档格式。

`cmark` 在性能方面则是有点粗糙：基于实现 Sundown 时我们所学到的性能技巧，我们向上游贡献了许多优化方案，但除去所有这些变更之外，当前版本的 `cmark` 仍然无法与 Sundown 本身匹敌：我们的基准测试表明，`cmark` 在绝大多数文档渲染的性能上要比 Sundown 低 20% 到 30%。

那句古老的优化谚语 <ruby> 最快的代码就是不需要运行的代码 <rp>  （ </rp> <rt>  the fastest code is the code that doesn’t run </rt> <rp>  ） </rp></ruby>在此处同样适用：实际上，`cmark` 比 Sundown 要*多进行一些操作*。在其他的功能上，`cmark` 支持 UTF8 字符集，对参考的支持、扩展的接口清理的效果更佳。最重要的是它如同 Sundown 那样，并不会将 Markdown *翻译成* HTML。它实际上从 Markdown 源码中生成一个 AST （抽象语法树，Abstract Syntax Tree），然后我们就看将之转换和逐渐渲染成 HTML。

如果考虑下我们在 Sundown 的最初实现 （特别是文档中关于查询用户的 mention 和 issue 引用、插入任务列表等） 时的 HTML 语法剖析工作量，你会发现 `cmark` 基于 AST 的方法可以节约大量时间 *和* 降低我们用户内容堆栈的复杂度。Markdown AST 是一个非常强大的工具，并且值得 `cmark` 生成它所付出的性能成本。

### 迁移

变更我们用户的内容堆栈以兼容 CommonMark 规范，并不同于转换我们用来解析 Markdown 的库那样容易：目前我们在遇到最根本的障碍就是由于一些不常用语法 （LCTT 译注：原文是 the Corner，作为名词的原意为角落、偏僻处、窘境，这应该是指那些不常用语法），CommonMark 规范 （以及有歧义的 Markdown 原文） 可能会以一种意想不到的方式来渲染一些老旧的 Markdown 内容。

通过综合分析 GitHub 中大量的 Markdown 语料库，我们断定现存的用户内容只有不到 1% 会受到新版本实现的影响：我们是通过同时使用新 （`cmark`，兼容 CommonMark 规范） 旧 （Sundown） 版本的库来渲染大量的 Markdown 文档、标准化 HTML 结果、分析它们的不同点，最后才得到这一个数据的。

只有 1% 的文档存在少量的渲染问题，使得换用新实现并获取其更多出看起来是非常合理的权衡，但是是根据当前 GitHub 的规模，这个 1% 是非常多的内容以及很多的受影响用户。我们真的不想导致任何用户需要重新校对一个老旧的问题、看到先前可以渲染成 HTML 的内容又呈现为 ASCII 码 —— 尽管这明显不会导致任何原始内容的丢失，却是糟糕的用户体验。

因此，我们想出相应的方法来缓和迁移过程。首先，第一件我们做的事就是收集用户托管在我们网站上的两种不同类型 Markdown 的数据：用户的评论 （比如 Gist、issue、PR 等）以及在 git 仓库中的 Markdown 文档。

这两种内容有着本质上的区别：用户评论存储在我们的数据库中，这意味着他们的 Markdown 语法可以标准化 （比如添加或移除空格、修正缩进或则插入缺失的 Markdown 说明符，直到它们可正常渲染为止）。然而，那些存储在 Git 仓库中的 Markdown 文档则是 *根本* 无法触及，因为这些内容已经散列成为 Git 存储模型的一部分。

幸运的是，我们发现绝大多数使用了复杂的 Markdown 特性的用户内容都是用户评论 （特别是 issue 主体和 PR 主体），而存储于仓库中的文档则大多数情况下都可以使用新的和旧的渲染器正常进行渲染。

因此，我们加快了标准化现存用户内容的语法的进程，以便使它们在新旧实现下渲染效果一致。

我们用以文档转换的方法相当实用：我们那个旧的 Markdown 解析器， Sundown，更多的是扮演着翻译器而非解析器的角色。输入 Markdown 内容之后，一系列的语意回调就会把原始的 Markdown 内容转换为目标语言 （在我们的实际使用中是 HTML5） 的对应标记。基于这一设计方法，我们决定使用语意回调让 Sumdown 将原始 Markdown 转换为兼容 CommonMark 的 Markdown，而非 HTML。

除了转换之外，这还是一个高效的标准化过程，并且我们对此信心满满，毕竟完成这一任务的是我们在五年前就使用过的解析器。因此，所有的现存文档在保留其原始语意的情况下都能够进行明确的解析。

一旦升级 Sundown 来标准化输入文档并充分测试之后，我们就会做好开启转换进程的准备。最开始的一步，就是对所有新用户内容切换到新的 `cmark` 实现上，以便确保我们能有一个有限的分界点来进行过渡。实际上，几个月前我们就为网站上所有 **新的** 用户评论启用了 CommonMark，这一过程几乎没有引起任何人注意 —— 这是关于 CommonMark 团队出色工作的证明，通过一个最具现实世界用法的方式来正式规范 Markdown 语言。

在后端，我们开启 MySQL 转换来升级替代所有 Markdown 用户内容。在所有的评论进行标准化之后，在将其写回到数据库之前，我们将使用新实现来进行渲染并与旧实现的渲染结果进行对比，以确保 HTML 输出结果视觉上感觉相同，并且用户数据在任何情况下都不会被破坏。总而言之，只有不到 1% 的输入文档会受到标准进程的修改，这符合我们的的期望，同时再次证明 CommonMark 规范能够呈现语言的真实用法。

整个过程会持续好几天，最后的结果是网站上所有的 Markdown 用户内容会得到全面升级以符合新的 Markdown 标准，同时确保所有的最终渲染输出效果对用户视觉上感觉相同。

### 结论

从今天 （LCTT 译注：原文发布于 2017 年 3 月 14 日，这里的今天应该是这个日期） 开始， 我们同样为所有存储在 Git 仓库中的 Markdown 内容启动 CommonMark 渲染。正如上文所述，所有的现存文档都不会进行标准化，因为我们所期望中的多数渲染效果都刚刚好。

能够让在 GitHub 上的所有 Markdown 内容符合一个动态变化且使用的标准，同时还可以为我的用户提供一个关于 GFM 如何进行解析和渲染 [清晰且权威的参考说明](https://github.github.com/gfm/)，我们是相当激动的。

我们还将致力于 CommonMark 规范，一直到在它正式发布之前消除最后一个 bug。我们也希望 GitHub.com 在其 1.0 规范发布之后可以进行完美兼容。

作为结束，以下为想要学习 CommonMark 规范或则自己来编写实现的朋友提供一些有用的链接。

* [CommonMark 主页](http://commonmark.org/)，可以了解本项目更多信息
* [CommonMark 论坛讨论区](http://talk.commonmark.org/)，可以提出关于该规范的的问题和更改建议
* [CommonMark 规范](http://spec.commonmark.org/)
* [使用 C 语言编写的参考实现](https://github.com/jgm/cmark/)
* [Our fork with support for all GFM extensions](https://github.com/github/cmark/)
* [GFM 规范](https://github.github.com/gfm/)，基于原始规范
* [使用其他编程语言编写的 CommonMark 实现列表](https://github.com/jgm/CommonMark/wiki/List-of-CommonMark-Implementations)

---

译者简介：

[GHLandy](http://GHLandy.com) —— 生活中所有欢乐与苦闷都应藏在心中，有些事儿注定无人知晓，自己也无从说起。

---

via: <https://githubengineering.com/a-formal-spec-for-github-markdown/>

作者：[Yuki Izumi](https://github.com/kivikakk)[Vicent Martí](https://github.com/vmg) 译者：[GHLandy](https://github.com/GHLandy) 校对：[jasminepeng](https://github.com/jasminepeng)

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


Ubuntu 17.04（Zesty Zapus）正式发布，可以下载使用了

我使用的速度永远跟不上跟新的速度~~~

Z都用了，下一个版本会叫什么呢？

A 和 B，因为第一个版本是从 C 开始的。

现在这些系统新旧版本差别不大

多了一个像 WIN 10 的系统设置界面<br />
和一个 Scopes 管理界面

我用redhat。。。

C从来没有用过！

看视频还容易奔溃吗

应先问自己的显卡驱动安装好了没?<br />
最近一直在用 ubuntu 16.04 / Chrome 看视频, 也不曾出问题过.

升级之后  感觉DNS解析有毛病……

![](/data/attachment/album/201704/13/213150t94cdz3ccgc6lccd.jpg)

今天，2017 年 4 月 13 日，Canonical 官方发布了 Ubuntu 17.04（Zesty Zapus）的最终版。自从去年十月发布 Ubuntu 16.10（Yakkety Yak）起，它已经开发了将近 6 个月。

如果直到今天，你一直在你的电脑上使用 Ubuntu 16.10，那么是时候升级到 Ubuntu 17.04 了，它是一个强大的发行版，“内外兼修”。它由最新的稳定的 Linux 4.10 内核驱动，并使用最新的基于 X.org 服务器 1.19.3 和 Mesa 17.0.3 的图形 Stack 进行配备。

上面提到的三个新技术，是那些使用 AMD 的 Radeon 显卡来玩游戏的人们需要立刻升级到 Ubuntu 17.04（Zesty Zapus）的唯一原因。但是 Ubuntu 17.04（Zesty Zapus）仅配备有最新的组件和应用程序。

Ubuntu 17.04（Zesty Zapus）的默认桌面环境仍然是 Unity 7，所以你钟爱的 Ubuntu 桌面环境此刻还没有消失。在未来的 Ubuntu 17.10 中，Unity 依然可用，Ubuntu 17.10 将在下个月开始开发。之后，从 Ubuntu 18.04 LTS 开始，[将默认使用 GNOME 桌面](http://news.softpedia.com/news/canonical-to-stop-developing-unity-8-ubuntu-18-04-lts-ships-with-gnome-desktop-514604.shtml)。

![](/data/attachment/album/201704/13/213152d45401uhzdpannyh.jpg)

*默认使用 Unity 7 桌面*

Ubuntu 17.04 有一些新的特性：

* 免驱动打印
* 交换文件
* 不再支持 32 位 PPC 架构

伴随其他有趣的技术一起装载在 Ubuntu 17.04 的最终发行版上，最值得一提的是交换文件，对于新安装的系统来说可以用它来替代交换分区。所以如果你从之前的 Ubuntu 发行版升级过来，这是唯一一个不适用的地方。

此外，默认的 DNS 解析器转换为了 `systemd-resolved`。IPP Everywhere 和苹果 AirPrint 打印机支持免驱动的开箱即用。绝大多数来自 GNOME 家族的包都升级到了 GNOME 3.24，只有 Nautilus 仍然保持在 GNOME 3.20.4 版本。

gconf 工具不再默认安装，因为它现在已经被 gsettings 所代替。而安装的应用大多数都是最新的，比如 LibreOffice 5.3 办公套件，Mozilla Firefox 52.0.1 Web 浏览器，以及 Mozilla Thunderbird 45.8.0 邮箱和新闻客户端。

![](/data/attachment/album/201704/13/213153i0201p7f2027c34s.jpg)

*Nautilus 文件管理器*

从本次发行版本开始，不再支持 32 位 PowerPC（PPC）架构，以后的发行版也不再会支持。但是 PPC64el（PowerPC 64 位 Little Endian）会持续支持。现在，已经可以从我们网站上[下载 Ubuntu 17.04](http://linux.softpedia.com/get/Linux-Distributions/Ubuntu-Wily-Werewolf-103744.shtml)的 64 位（amd64）和 32 位 ISO（i386）镜像。

其他的 Ubuntu 风味版本也在今天开始发行，包括 Ubuntu GNOME 17.04、Ubuntu MATE 17.04、Kubuntu 17.04、Xubuntu 17.04、Lubuntu 17.04、Ubuntu Kylin 17.04、Ubuntu Studio 17.04 以及 Ubuntu Budgie 17.04，这也是 Budgie 桌面作为官方的 Ubuntu 风味版本的首次亮相。

请注意，Ubuntu 17.04（Zesty Zapus）是一个短暂的分支，仅支持 9 个月的安全更新，即从今天到 2018 年 1 月中旬 。

---

via: <http://news.softpedia.com/news/ubuntu-17-04-zesty-zapus-officially-released-available-to-download-now-514853.shtml>

作者：[Marius Nestor](http://news.softpedia.com/editors/browse/marius-nestor) 译者：[ucasFL](https://github.com/ucasFL) 校对：[wxy](https://github.com/wxy)

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


开源啦！「运维密码」小程序携全新 UI 开源啦！

资磁！

场景的种子二维码是怎么获取？可以自己将服务器有关信息制作二维码吗？

继前一段时间 Linux 中国推出了“[运维密码](/article-8317-1.html)”微信小程序之后，经过开发团队的努力，重构了代码和使用了全新的现代 UI 后，同时在 GitHub 上开源了！

![](/data/attachment/album/201704/14/093912qjnsah6njs9fjsje.jpg)

“运维密码”小程序是一款工作在微信环境中的小程序，主要的功能是提供一款方便、可靠、美观的 TOTP 密钥管理工具。TOTP 是基于时间的一次性密钥方案，可以为用户认证提供双因子认证（2FA）的支持，即在通常的密码之外，还额外通过另外一种方式来交叉认证以提升安全。

TOTP 认证，或者说双因子认证，在得到 Google 的大力推进之后，得到了广泛的互联网业界的支持，包括 Google、GitHub 等重视互联网安全的大型网站，也包括各类比特币网站，均支持 [TOTP RFC 草案](http://tools.ietf.org/id/draft-mraihi-totp-timebased-06.html)所规定的 TOTP 算法，并且 Google 还开源了其服务器端实现和客户端代码。除此之外，TOTP 还广泛应用于 Apple 、QQ、微博等各种需要双因子认证的场景中。除了网站之外，对于我们运维人员来说，TOTP 还可以应用与服务器的远程管理上，为 SSH、SFTP、FTP 等提供安全、简单、可靠的保障！

### 新版本介绍

好了，言归正传，我们来介绍一下本次新版本发布的情况。

本次版本迭代，我们毫不谦虚的将版本定位到 1.0.x，我们认为“运维密码”的第一阶段功能目标已经达成，目前主要有：

* 添加 TOTP 场景
* 查看 TOTP 密钥
* 修改和删除 TOTP 场景
* 生成场景二维码
* **分享（克隆） TOTP 场景给朋友**
* **本地备份 TOTP 场景信息**
* **本地恢复 TOTP 场景信息**

新的版本，采用了现代化的 UI 设计，看起来会更专业一点。

![](/data/attachment/album/201704/14/083650lp2xivllix52x5p3.jpg)

*场景列表*

场景列表会列出你已经添加的所有场景，最上方是时间进度条会显示场景密钥要更新的时间。在列表最下方，可以点击“添加场景”，调出摄像头来扫描密钥二维码来添加场景。

点击场景列表中的场景密钥，会复制该密钥，以备手机上使用。

![](/data/attachment/album/201704/14/083653nelhc0w7pwme1cl0.jpg)

*场景详情*

点击场景列表中的场景（非密钥区域），可以查看场景具体详情，在此可以“分享”、“生成二维码”、“编辑”乃至于“删除”场景。

* 分享：请点击页面右上角的菜单，可以将该场景分享给你的朋友，这样你的朋友就会得到一份该场景的完全复制品。**切记！分享该场景会导致别人一直拥有该场景信息，并随时生成密钥（和你的场景生成相同的密钥）。**如果这不是你希望的结果，切勿分享。
* 生成二维码：可以生成一份该场景特定的二维码，将其打印出来贴于服务器等物理环境处，使用时直接用微信扫描即可调出“运维密码”小程序添加该场景。（注：该场景二维码不同于用于添加场景的种子二维码）
* 编辑和删除：也可以对此场景进行编辑，尤其是你在添加场景时输入的信息不够明确时。也可以在此修改该场景的地点（我们后继的版本会推出地点感知功能）。

![](/data/attachment/album/201704/14/083655akxr7q77n9oyn7o9.jpg)

*生成的场景二维码*

![](/data/attachment/album/201704/14/083651qok9jkbm8bmonk5j.jpg)

*场景备份与恢复*

![](/data/attachment/album/201704/14/083658od3kkk14472y1jk4.jpg)

*场景备份信息，请截屏安全保存*

最重要的，“运维密码”小程序提供了备份和恢复功能，这是 Google 所开源的 Google 身份验证器所缺乏的最重要功能。有了备份功能，你就不用担心手机丢失或更换手机的麻烦了。

目前我们提供了本地备份功能。限于微信小程序的限制，我们不能保存文件，只能将备份信息以二维码的方式备份出来。您可以将该二维码截屏，保存到安全可靠的地方，以备以后需要时恢复。

现阶段没有提供远程云端备份功能的主要原因是用户可能忧虑云端备份的隐私保障，因此，我们在没有办法提供一个可靠备份，连服务提供方也不能破解的方法之前，不会提供云端备份功能。

### 开源啦！

作为一家倡导开源的社区，我们一定要亲自践行开源才算得上名至实归。因此，我们在代码重构稳定之后，第一时间就将“运维密码”开源了出来。开源地址在：

<https://github.com/LCTT/WeApp-Password>

本项目采用 AGPL 3.0 协议开源。

欢迎大家复刻和提交拉取请求，有什么错误和功能建议，也非常欢迎大家给我们提出 [issue](https://github.com/LCTT/WeApp-Password/issues)。

### 欢迎体验

我们还开设了“运维密码”小程序体验群，欢迎大家到群内发表意见，以及寻求帮助。加入本群也可以及时体验我们发布前的体验版本，第一时刻尝鲜。

![](/data/attachment/album/201704/02/183245nlijim1huakgc4ul.jpeg)

*运维密码体验群*

扫描识别添加上面的好友，验证信息：“运维密码”，可获得入群邀请。

### 使用参考

要在 OpenSSH 上使用 TOTP，请参考 netb2c 写的《[SSH 安全加固篇：通过“运维密码”小程序实现 SSH 双因子认证](/article-8354-1.html)》。

我们还会陆续推出更多使用 “运维密码”的文章，也欢迎大家给我们投稿。

哦，好像我没有说到如何找到“运维密码”——我想这一定难不倒你，不过假如你不知道的话，你可以如此这般：

* 在微信中“发现”->“小程序”中搜索“运维密码”即可。
* 什么，你的“发现”中没有“小程序”，那你可以扫描下面这个二维码，来尝鲜你的第一个小程序：

![](/data/attachment/album/201704/18/231021dirilslcqo7rwwwl.jpg)

*运维密码*

### 致谢

感谢开发团队的 @Bestony、betty、wxy；

感谢撰写使用“运维密码”的文章的同学：netb2c；

 感谢“运维密码”体验群的诸位同学；

感谢 Google 开源的程序；

感谢微信提供的环境。


Linux 系统上的可视化比较与合并工具 Meld

Summary: Meld 主要是一个可视化的比较和合并的工具，目标人群是开发者（当然，我们将要讲到的其它部分也会考虑到最终用户）。这个工具同时支持双向和三向的比较，不仅仅是比较文件，还可以比较目录，以及版本控制的项目。

同类软件还有 kompare ，或者 winmerge+wine。<br />
另外 Windows 平台有款商业软件，名字好像叫 beyond compare，这个软件支持图片比较，所以理论上可以用来 “大家来找茬”作弊。

BC也有linux和mac版的，不过是英文

我们已经[讲过](https://www.howtoforge.com/tutorial/linux-diff-command-file-comparison/) Linux 中[一些](https://www.howtoforge.com/tutorial/how-to-compare-three-files-in-linux-using-diff3-tool/)基于命令行的比较和合并工具，再来讲解该系统的一些可视化的比较与合并工具也很合理。首要的原因是，不是每个人都习惯使用命令行，而且对于某些人来说，基于命令行的比较工具可能很难学习和理解。

因此，我们将会推出关于可视化工具 **Meld** 的系列文章。

![](/data/attachment/album/201704/14/161435odgyqg3kmskcqcdd.jpg)

在跳到安装和介绍部分前，我需要说明这篇教程里所有的指令和用例是都是可用的，而且它们已经在 Ubuntu 14.04 中测试过了，我们使用的 Meld 版本是 3.14.2。

### 关于 Meld

[Meld](http://meldmerge.org/) 主要是一个可视化的比较和合并的工具，目标人群是开发者（当然，我们将要讲到的其它部分也会考虑到最终用户）。这个工具同时支持双向和三向的比较，不仅仅是比较文件，还可以比较目录，以及版本控制的项目。

“Meld 可以帮你回顾代码改动，理解补丁，”其官网如是说。“它甚至可以告知你如果你不进行合并将会发生什么事情。”该工具使用 GPL v2 协议进行授权。

### 安装 Meld

如果你用的是 Ubuntu 或者其它基于 Debian 的 Linux 分支，你可以用以下命令下载安装 Meld：

```
sudo apt-get install meld

```

或者你也可以用系统自带的包管理软件下载这个工具。比如在 Ubuntu 上，你可以用 <ruby> Ubuntu 软件中心 <rp>  （ </rp> <rt>  Ubuntu Software Center </rt> <rp>  ） </rp></ruby>，或者用 [Ubuntu 软件](https://www.howtoforge.com/tutorial/ubuntu-16-04-lts-overview/)，它从 Ubuntu 16.04 版本开始取代了 Ubuntu 软件中心。

当然，Ubuntu 官方仓库里的 Meld 版本很有可能比较陈旧。因此如果你想要用更新的版本，你可以在[这里](https://git.gnome.org/browse/meld/refs/tags)下载软件包。如果你要用这个方法，你要做的就是解压下载好的软件包，然后运行 `bin` 目录下的 `meld` 程序。

```
~/Downloads/meld-3.14.2/bin$ ./meld

```

以下是 Meld 依赖的软件，仅供参考：

* Python 2.7 (Python 3.3 开发版)
* GTK+ 3.14
* GLib 2.36
* PyGObject 3.14
* GtkSourceView 3.14
* pycairo

### 使用 Meld

装好了软件，就可以看到类似这样的画面：

![Meld started](/data/attachment/album/201704/14/161507znfvhtnsao6w99i6.png)

有三个选项：<ruby> 比较文件 <rp>  （ </rp> <rt>  File comparison </rt> <rp>  ） </rp></ruby>，<ruby> 比较目录 <rp>  （ </rp> <rt>  Directory comparison </rt> <rp>  ） </rp></ruby>以及<ruby> 版本控制视图 <rp>  （ </rp> <rt>  Version control view </rt> <rp>  ） </rp></ruby>。

点击“比较文件”选项，就可以选择需要比较的文件：

![Meld file comparison](/data/attachment/album/201704/14/161511j2o1s5n1bs9m6ohc.png)

就像上面的截图那样明白，Meld 也可以进行三向比较，但是在这一系列文章的第一部分，我们只会讲更常用的双向比较。

接着，选择你想要比较的文件，点击<ruby> “比较” <rp>  （ </rp> <rt>  Compare </rt> <rp>  ） </rp></ruby>按钮。软件会在两边分别打开两个文件，高亮不同的行（以及不同的部分）。

![Compare files in Meld](/data/attachment/album/201704/14/161513k1g9jpba9eq2grke.png)

两个文件的不同之处在第二行，差别在于 `file2` 文件的第二行多了一个 `3`。你看到的黑色箭头是用来进行合并或修改的操作的。该例中，向右的箭头将会把 `file2` 文件的第二行改成文件 `file1` 中对应行的内容。左向箭头做的事情相反。

做完修改后，按下 `Ctrl+s` 来保存。

这个简单的例子，让你知道 Meld 的基本用法。让我们看一看稍微复杂一点的比较：

![Meld advanced file comparison](/data/attachment/album/201704/14/161518kx7a5zgoo65iio2u.png)

在讨论这些变化前，这里提一下， Meld 的界面中有几个区域，可以给出文件之间的差异，让概况变得直观。这里特别需要注意窗口的左右两边垂直的栏。比如下面这个截图：

![Visual Comparison](/data/attachment/album/201704/14/161518hrv4hhk67y41s1z4.png)

仔细观察，图中的这个栏包含几个不同颜色的区块。这些区块是用来让你对文件之间的差异有个大概的了解。“每一个着色的区块表示一个部分，这个部分可能是插入、删除、修改或者有差别的，取决于区块所用的颜色。”官方文档是这样说的。

现在，让我们回到我们之前讨论的例子中。接下来的截图展示了用 Meld 理解文件的改动是很简单的（以及合并这些改动）：

![File changes visualized in Meld](/data/attachment/album/201704/14/161521tama9fm53tyrm207.png)

![Meld Example 2](/data/attachment/album/201704/14/161524mkg2mi2lk2s5hsis.png)

![Meld Example 3](/data/attachment/album/201704/14/161528zny1rhihn212dhba.png)

接着，我们滑动文件，从一个改动跳到另一个。但是，当要比较的文件很大时，这会耗一点时间，当你想要滑动文件跳到一个改动的位置时，也会变得很困难。如果是这种情况的话，你可以用工具栏的橙色箭头，就在编辑区域的上方：

![Go to next change in Meld](/data/attachment/album/201704/14/161530ehbmukhvhvlmlp9x.png)

这些是你使用 Meld 时做的一般性的事情：可以用标准的 `Ctrl+f` 组合键在编辑区域内进行查找，按 `F11` 键让软件进入全屏模式，再按 `Ctrl+r` 来刷新（通常在所有要比较的文件改变的时候使用）。

以下是 Meld 官方网站宣传的重要特性：

* 文件和目录的双向及三向比较
* 输入即更新文件的比较
* 自动合并模式，按块改动的动作让合并更加简单
* 可视化让比较文件更简单
* 支持 Git，Bazaar，Mercurial，Subversion 等等

注意还不仅仅只有以上所列的。网站上有个专门的[特性页面](http://meldmerge.org/features.html)，里面提到了 Meld 提供的所有特性。这个页面列出的所有特性分为几个部分，以该软件是用来做文件比较、目录比较、版本控制还是处于合并模式下为基础进行划分。

和其它软件相似，有些事情 Meld 做不到。官方网站上列出了其中的一部分：“当 Meld 展示文件之间的差异时，它同时显示两个文件，看起来就像在普通的文本编辑器中。它不会添加额外的行，让左右两边文件的特殊改动处于同样的行数。没有做这个事情的选项。”

### 总结

我们刚刚了解到的不过是皮毛，因为 Meld 还能做很多事情。考虑到这是教程系列的第一部分，这也挺不错的。这仅仅是让你了解 Meld 的作用，你可以配置它，忽略一些特定类型的改动，让它移动，复制或者删除文件之间的个别差异，也可以从命令行启动它。在即将退出的系列教程中，我们将会讲述所有这些重要功能。

---

via: <https://www.howtoforge.com/tutorial/beginners-guide-to-visual-merge-tool-meld-on-linux/>

作者：[Ansh](https://www.howtoforge.com/tutorial/beginners-guide-to-visual-merge-tool-meld-on-linux/) 译者：[GitFuture](https://github.com/GitFuture) 校对：[wxy](https://github.com/wxy)

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


印度的社区如何支持隐私和软件自由

Summary:
印度的自由和开源社区，特别是 Mozilla 和 Wikimedia 社区，它们正在引领两个独特的全球性活动，以提高隐私保护及支持自由软件。
1 月份的隐私月是由印度 Mozilla 社区领导，通过在线和线下活动向群众教育网络隐私。而 2 月份的自由月是由互联网与社会中心领导，教育内容创作者如博主和摄影师就如何在开放许可证下捐赠内容。

![How communities in India support privacy and software freedom](/data/attachment/album/201704/14/164955cne3hjoaapog6dfl.png "How communities in India support privacy and software freedom")

印度的自由和开源社区，特别是 Mozilla 和 Wikimedia 社区，它们正在引领两个独特的全球性活动，以提高隐私保护及支持自由软件。

[1 月份的隐私月](https://wiki.mozilla.org/India/task_force/Policy_and_Advocacy/January_Privacy_Month_Campaign)是由印度 Mozilla 社区领导，通过在线和线下活动向群众教育网络隐私。而 [2 月份的自由月](http://www.freedominfeb.org/)是由[互联网与社会中心](http://cis-india.org/)领导，教育内容创作者如博主和摄影师就如何在[开放许可证](https://opensource.com/education/16/8/3-copyright-tips-students-and-educators)下捐赠内容。

### 1 月隐私月

从[去年开始](https://reps.mozilla.org/e/privacy-month-campaign/)的 Mozilla “1 月隐私月”用来帮助庆祝年度[数据隐私日（Data Privacy Day）](https://en.wikipedia.org/wiki/Data_Privacy_Day)。在 2016 年，该活动举办了几场涉及到[全球 10 个国家 14,339,443 人](http://blog.mozillaindia.org/1611)的线下和线上活动。其中一个核心组织者，[Ankit Gadgil](https://reps.mozilla.org/u/ankitgadgil) 这样说到：“每天分享一个隐私提示，持续一个月就能分享 31 天。”今年，我们共有三个重点领域，首先是我们让这个运动更加开放和全球化。巴西、意大利、捷克共和国的 Mozilla 社区今年正在积极参与，所有必要的文档都是本地化的，所以我们可以针对更多的用户。其次，我们在线下活动中教导用户推广 Firefox 以及 Mozilla 的其他产品，以便用户可以亲身体验使用这些工具来帮助保护他们的隐私。第三点，我们鼓励大家参加线下活动并把他们的学习写到博客里面去，例如，最近在印度古吉拉特邦的一个节目中，他们使用 Mozilla 产品来教授隐私方面的知识。”

今年的活动继续有线下和线上活动。关注 #PrivacyAware 参加。

#### 安全提示

像 Firefox 这样的 Mozilla 产品具有安全性设置-有[内置的](https://support.mozilla.org/en-US/products/firefox/protect-your-privacy)还有对残疾人完全[可用](https://support.mozilla.org/en-US/kb/advanced-panel-settings-in-firefox)的附件库-这有助于保护用户的隐私和安全性，这些都是协同构建的并且是开源的。

[Chrome](https://chrome.google.com/webstore/detail/gcbommkclmclpchllfjekcdonpmejbdp) 和 [Opera](https://addons.opera.com/extensions/details/https-everywhere/) 中的 [HTTPS Everywhere](https://www.eff.org/files/https-everywhere-latest.xpi) 插件可用于加密用户通信，使外部网站无法查看用户信息。该项目由 [Tor Project](https://www.torproject.org/) 以及[电子前沿基金会](https://eff.org/)合作建成。

### 2 月自由月

[2 月自由月](http://www.freedominfeb.org/)是一个网络活动，旨在教育内容创作者关于[自由内容](https://en.wikipedia.org/wiki/Free_content)，并向他们展示如何在自由许可证下作出贡献。

**参加规则：**

* 你在二月份制作或出版的作品必须获得[自由许可证](https://en.wikipedia.org/wiki/Free_license#Classification_and_licenses)许可。
* 内容类型包括博客文章、其他文字和图像。

多媒体，基于文本的内容，艺术和设计等创意作品可以通过多个[知识共享许可证](https://creativecommons.org/licenses/)（CC）进行许可，其他类型的文档可以根据 [GNU 免费文档许可](https://en.wikipedia.org/wiki/GNU_Free_Documentation_License)（GFDL）许可。Wikipedia 上可以找到很好的例子，其内容根据 CC 和 GFDL 许可证获得许可，允许人们使用、分享、混合和分发衍生用于商业上和非商业性的作品。此外，还有允许开发人员共享他们的软件和软件相关文档的[自由软件许可证](https://www.gnu.org/licenses/license-list.en.html#GPLCompatibleLicenses)。

（题图提供： opensource.com）

---

作者简介：

Subhashish Panigrahi（@shhapa）是 Mozilla 参与团队的亚洲社区催化师，并在 Wikimedia 基金会印度计划的早期扮演了互联网及社会知识获取中心项目官的角色，另外他是一名印度教育工作者，

---

via: <https://opensource.com/article/17/1/how-communities-india-support-privacy-software-freedom>

作者：[Subhashish Panigrahi](https://opensource.com/users/psubhashish) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


深入理解 sudo 与 su 之间的区别

Summary: 两个命令的最大区别是：sudo 命令需要输入当前用户的密码，su 命令需要输入 root 用户的密码。另外一个区别是其默认行为。sudo 命令只允许使用提升的权限运行单个命令，而 su 命令会启动一个新的 shell，同时允许使用 root 权限运行尽可能多的命令，直到明确退出登录。

在[早前的一篇文章](https://www.howtoforge.com/tutorial/sudo-beginners-guide/)中，我们深入讨论了 `sudo` 命令的相关内容。同时，在该文章的末尾有提到相关的命令 `su` 的部分内容。本文，我们将详细讨论关于 `su` 命令与 `sudo` 命令之间的区别。

![](/data/attachment/album/201704/14/173838y6cunu2lia1h2l1u.jpg)

在开始之前有必要说明一下，文中所涉及到的示例教程都已经在 Ubuntu 14.04 LTS 上测试通过。

### Linux su 命令

`su` 命令的主要作用是让你可以在已登录的会话中切换到另外一个用户。换句话说，这个工具可以让你在不登出当前用户的情况下登录为另外一个用户。

`su` 命令经常被用于切换到超级用户或 root 用户（因为在命令行下工作，经常需要 root 权限），但是 - 正如前面所提到的 - su 命令也可以用于切换到任意非 root 用户。

如何使用 `su` 命令切换到 root 用户，如下：

![不带命令行参数的 su 命令](/data/attachment/album/201704/14/173854kefstf26pfzuyyc0.png)

如上，`su` 命令要求输入的密码是 root 用户的密码。所以，一般 `su` 命令需要输入目标用户的密码。在输入正确的密码之后，`su` 命令会在终端的当前会话中打开一个子会话。

#### su -

还有一种方法可以切换到 root 用户：运行 `su -` 命令，如下：

![su - 命令](/data/attachment/album/201704/14/173854maap22gpewzmawez.png)

那么，`su` 命令与 `su -` 命令之间有什么区别呢？前者在切换到 root 用户之后仍然保持旧的（或者说原始用户的）环境，而后者则是创建一个新的环境（由 root 用户 `~/.bashrc` 文件所设置的环境），相当于使用 root 用户正常登录（从登录屏幕登录）。

`su` 命令手册页很清楚地说明了这一点：

>
> 可选参数 `-` 可提供的环境为用户在直接登录时的环境。
>
>
>

因此，你会觉得使用 `su -` 登录更有意义。但是， `su` 命令也是有用的，那么大家可能会想知道它在什么时候用到。以下内容摘自 [ArchLinux wiki 网站](https://wiki.archlinux.org/index.php/Su) - 关于 `su` 命令的好处和坏处：

* 有的时候，对于系统管理员（root）来讲，使用其他普通用户的 Shell 账户而不是自己的 root Shell 账户更会好一些。尤其是在处理用户问题时，最有效的方法就是是：登录目标用户以便重现以及调试问题。
* 然而，在多数情况下，当从普通用户切换到 root 用户进行操作时，如果还使用普通用户的环境变量的话，那是不可取甚至是危险的操作。因为是在无意间切换使用普通用户的环境，所以当使用 root 用户进行程序安装或系统更改时，会产生与正常使用 root 用户进行操作时不相符的结果。例如，以普通用户安装程序会给普通用户意外损坏系统或获取对某些数据的未授权访问的能力。

注意：如果你想在 `su -` 命令的 `-` 后面传递更多的参数，那么你必须使用 `su -l` 而不是 `su -`。以下是 `-` 和 `-l` 命令行选项的说明：

>
> `-`, `-l`, `--login`
>
>
> 提供相当于用户在直接登录时所期望的环境。
>
>
> 当使用 - 时，必须放在 `su` 命令的最后一个选项。其他选项（`-l` 和 `--login`）无此限制。
>
>
>

#### su -c

还有一个值得一提的 `su` 命令行选项为：`-c`。该选项允许你提供在切换到目标用户之后要运行的命令。

`su` 命令手册页是这样说明：

>
> `-c`, `--command COMMAND`
>
>
> 使用 `-c` 选项指定由 Shell 调用的命令。
>
>
> 被执行的命令无法控制终端。所以，此选项不能用于执行需要控制 TTY 的交互式程序。
>
>
>

参考示例：

```
su [target-user] -c [command-to-run]

```

示例中，`command-to-run` 将会被这样执行：

```
[shell] -c [command-to-run]

```

示例中的 `shell` 类型将会被目标用户在 `/etc/passwd` 文件中定义的登录 shell 类型所替代。

### sudo vs. su

现在，我们已经讨论了关于 `su` 命令的基础知识，是时候来探讨一下 `sudo` 和 `su` 命令之间的区别了。

#### 关于密码

两个命令的最大区别是：`sudo` 命令需要输入当前用户的密码，`su` 命令需要输入 root 用户的密码。

很明显，就安全而言，`sudo` 命令更好。例如，考虑到需要 root 访问权限的多用户使用的计算机。在这种情况下，使用 `su` 意味着需要与其他用户共享 root 用户密码，这显然不是一种好习惯。

此外，如果要撤销特定用户的超级用户/root 用户的访问权限，唯一的办法就是更改 root 密码，然后再告知所有其他用户新的 root 密码。

而使用 `sudo` 命令就不一样了，你可以很好的处理以上的两种情况。鉴于 `sudo` 命令要求输入的是其他用户自己的密码，所以，不需要共享 root 密码。同时，想要阻止特定用户访问 root 权限，只需要调整 `sudoers` 文件中的相应配置即可。

#### 默认行为

两个命令之间的另外一个区别是其默认行为。`sudo` 命令只允许使用提升的权限运行单个命令，而 `su` 命令会启动一个新的 shell，同时允许使用 root 权限运行尽可能多的命令，直到明确退出登录。

因此，`su` 命令的默认行为是有风险的，因为用户很有可能会忘记他们正在以 root 用户身份进行工作，于是，无意中做出了一些不可恢复的更改（例如：对错误的目录运行 `rm -rf` 命令！）。关于为什么不鼓励以 root 用户身份进行工作的详细内容，请参考[这里](http://askubuntu.com/questions/16178/why-is-it-bad-to-login-as-root)。

#### 日志记录

尽管 `sudo` 命令是以目标用户（默认情况下是 root 用户）的身份执行命令，但是它们会使用 `sudoer` 所配置的用户名来记录是谁执行命令。而 `su` 命令是无法直接跟踪记录用户切换到 root 用户之后执行了什么操作。

#### 灵活性

`sudo` 命令比 `su` 命令灵活很多，因为你甚至可以限制 sudo 用户可以访问哪些命令。换句话说，用户通过 `sudo` 命令只能访问他们工作需要的命令。而 `su` 命令让用户有权限做任何事情。

#### sudo su

大概是因为使用 `su` 命令或直接以 root 用户身份登录有风险，所以，一些 Linux 发行版（如 Ubuntu）默认禁用 root 用户帐户。鼓励用户在需要 root 权限时使用 `sudo` 命令。

然而，您还是可以成功执行 `su` 命令，而不用输入 root 用户的密码。运行以下命令：

```
sudo su

```

由于你使用 `sudo` 运行命令，你只需要输入当前用户的密码。所以，一旦完成操作，`su` 命令将会以 root 用户身份运行，这意味着它不会再要求输入任何密码。

**PS**：如果你想在系统中启用 root 用户帐户（强烈反对，因为你可以使用 `sudo` 命令或 `sudo su` 命令），你必须手动设置 root 用户密码，可以使用以下命令：

```
sudo passwd root

```

### 结论

当你需要可用的工具来提升（或一组完全不同的）权限来执行任务时，这篇文章以及之前的教程（其中侧重于 `sudo` 命令）应该能给你一个比较好的建议。 如果您也想分享关于 `su` 或 `sudo` 的相关内容或者经验，欢迎您在下方进行评论。

---

via: <https://www.howtoforge.com/tutorial/sudo-vs-su/>

作者：[Himanshu Arora](https://www.howtoforge.com/tutorial/sudo-vs-su/) 译者：[zhb127](https://github.com/zhb127) 校对：[wxy](https://github.com/wxy)

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


使用 Exercism 提升你的编程技巧

Summary: Exercism 是一个 开源 的项目和服务，通过发现和协作，帮助人们提高他们的编程技能。Exercism 提供了几十种不同编程语言的练习。实践者完成每个练习，并获得反馈，从而可以从他们的同行小组的经验中学习。

>
> 这些练习目前已经支持 33 种编程语言了。
>
>
>

![Improve your programming skills with Exercism ](/data/attachment/album/201704/15/100442knjg7677vxjso7jy.png "Improve your programming skills with Exercism ")

我们中的很多人的 2017 年目标，将提高编程能力或学习如何编程放在第一位。虽然我们有许多资源可以访问，但练习独立于特定职业的代码开发的艺术还是需要一些规划。[Exercism.io](http://exercism.io/) 就是为此目的而设计的一种资源。

Exercism 是一个 [开源](https://github.com/exercism) 的项目和服务，通过发现和协作，帮助人们提高他们的编程技能。Exercism 提供了几十种不同编程语言的练习。实践者完成每个练习，并获得反馈，从而可以从他们的同行小组的经验中学习。

这里有这么多同行！ Exercism 在 2016 年留下了一些令人印象深刻的统计：

* 有来自 201 个不同国家的参与者
* 自 2013 年 6 月以来，29,000 名参与者提交了练习，其中仅在 2016 年就有 15,500 名参加者提交练习
* 自 2013 年 6 月以来，15,000 名参与者就练习解决方案提供反馈，其中 2016 年有 5,500 人提供反馈
* 每月 50,000 名访客，每周超过 12,000 名访客
* 目前的练习已经支持 33 种编程语言，另外 22 种语言在筹备工作中

该项目为各种级别的参与者提供了一系列小小的挑战，使他们能够“即使在低水平也能发展到高度谙熟”，Exercism 的创始人 [Katrina Owen](https://twitter.com/kytrinyx) 这样说到。Exercism 并不旨在教导学员成为一名职业程序员，但它的练习使他们对一种语言及其瑕疵有深刻的了解。这种熟悉性消除了学习者对语言的认知负担（使之更谙熟），使他们能够专注于更困难的架构和最佳实践的问题。

Exercism 通过一系列练习（或者还有别的？）来做到这一点。程序员下载[命令行客户端](http://exercism.io/cli)，检索第一个练习，添加完成练习的代码，然后提交解决方案。提交解决方案后，程序员可以研究他人的解决方案，并学习到对同一个问题不同的解决方式。更重要的是，每个解决方案都会收到来自其他参与者的反馈。

反馈是 Exercism 的超级力量。鼓励所有参与者不仅接收反馈而且提供反馈。根据 Owen 说的，Exercism 的社区成员提供反馈比完成练习学到更多。她说：“这是一个强大的学习经验，你需要发表内心感受，并检查你的假设、习惯和偏见”。她还指出，反馈可以有多种形式。

欧文说：“只需进入，观察并发问”。

那些刚刚接触编程，甚至只是接触了一种特定语言的人，可以通过预设好的问题来提供有价值的反馈，同时通过协作和对话来学习。

除了对新语言的 <ruby> “微课”学习 <rt>  bite-sized learning </rt></ruby> 之外，Exercism 本身还强烈支持和鼓励项目的新贡献者。在 [SitePoint.com](https://www.sitepoint.com/exorcise-your-newbie-demons-by-contributing-to-exercism/) 的一篇文章中，欧文强调：“如果你想为开源贡献代码，你所需要的技能水平只要‘够用’即可。” Exercism 不仅鼓励新的贡献者，它还尽可能地帮助新贡献者发布他们项目中的第一个补丁。到目前为止，有近 1000 人成为 [Exercism 项目](https://github.com/exercism)的贡献者。

新贡献者会有大量工作让他们忙碌。 Exercism 目前正在审查[其语言发展轨迹的健康状况](http://tinyletter.com/exercism/letters/exercism-track-health-check-new-maintainers)，目的是使所有发展轨迹可持续并避免维护者的倦怠。它还在寻求[捐赠](http://exercism.io/donate)和赞助，聘请设计师提高网站的可用性。

Owen 说：“这些改进对于网站的健康以及为了 Exercism 参与者的发展是有必要的，这些变化还鼓励新贡献者加入并简化了加入的途径。” 她说：“如果我们可以重新设计，产品方面将更加可维护……当用户体验一团糟时，华丽的代码一点用也没有”。该项目有一个非常活跃的[讨论仓库](https://github.com/exercism/discussions/issues?page=1&q=is%3Aissue+is%3Aopen)，这里社区成员合作来发现最好的新方法和功能。

那些想关注项目但还没有参与的人可以关注[邮件列表](http://tinyletter.com/exercism/archive)。

---

作者简介：

VM（Vicky）Brasseur - VM（也称为 Vicky）是技术人员、项目、流程、产品和 p^Hbusinesses 的经理。在她超过 18 年的科技行业从业中，她曾是分析师、程序员、产品经理、软件工程经理和软件工程总监。 目前，她是 Hewlett Packard Enterprise 上游开源开发团队的高级工程经理。 VM 的博客在 anonymoushash.vmbrasseur.com，tweets 是 @vmbrasseur。

---

via: <https://opensource.com/article/17/1/exercism-learning-programming>

作者：[VM (Vicky) Brasseur](https://opensource.com/users/vmbrasseur) 译者：[geekpi](https://github.com/geekpi) 校对：[jasminepeng](https://github.com/jasminepeng)

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


使用 AWS 的 GO SDK 获取区域与终端节点信息

Summary: 最新发布的 GO 的 SDK v1.6.0 版本，加入了获取区域与终端节点信息的功能。它可以很方便地列出区域、服务和终端节点的相关信息。可以通过 github.com/aws/aws-sdk-go/aws/endpoints 包使用这些功能。

LCTT 译注： <ruby> 终端节点 <rp>  （ </rp> <rt>  Endpoint </rt> <rp>  ） </rp></ruby>，详情请见: <http://docs.amazonaws.cn/general/latest/gr/rande.html>

最新发布的 GO 的 SDK [v1.6.0](https://github.com/aws/aws-sdk-go/releases/tag/v1.6.0) 版本，加入了获取区域与终端节点信息的功能。它可以很方便地列出区域、服务和终端节点的相关信息。可以通过 [github.com/aws/aws-sdk-go/aws/endpoints](http://docs.aws.amazon.com/sdk-for-go/api/aws/endpoints/) 包使用这些功能。

![](/data/attachment/album/201704/15/162013lycy36ond8py6yzz.jpg)

endpoints 包提供了一个易用的接口，可以获取到一个服务的终端节点的 url 列表和区域列表信息。并且我们将相关信息根据 AWS 服务区域进行了分组，如 AWS 标准、AWS 中国和 AWS GovCloud（美国）。

### 解析终端节点

设置 SDK 的默认配置时， SDK 会自动地使用 `endpoints.DefaultResolver` 函数。你也可以自己调用包中的`EndpointFor` 方法来解析终端节点。

```
// 解析在us-west-2区域的S3服务的终端节点
resolver := endpoints.DefaultResolver()
endpoint, err := resolver.EndpointFor(endpoints.S3ServiceID, endpoints.UsWest2RegionID)
if err != nil {
        fmt.Println("failed to resolve endpoint", err)
        return
}

fmt.Println("Resolved URL:", endpoint.URL)

```

如果你需要自定义终端节点的解析逻辑，你可以实现 `endpoints.Resolver` 接口，并传值给`aws.Config.EndpointResolver`。当你打算编写自定义的终端节点逻辑，让 SDK 可以用来解析服务的终端节点时候，这个功能就会很有用。

以下示例，创建了一个配置好的 Session，然后 [Amazon S3](https://aws.amazon.com/s3/) 服务的客户端就可以使用这个自定义的终端节点。

```
s3CustResolverFn := func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) {
        if service == "s3" {
               return endpoints.ResolvedEndpoint{
                       URL:           "s3.custom.endpoint.com",
                       SigningRegion: "custom-signing-region",
               }, nil
        }

        return defaultResolver.EndpointFor(service, region, optFns...)
}
sess := session.Must(session.NewSessionWithOptions(session.Options{
        Config: aws.Config{
               Region:           aws.String("us-west-2"),
               EndpointResolver: endpoints.ResolverFunc(s3CustResolverFn),
        },
}))

```

### 分区

`endpoints.DefaultResolver` 函数的返回值可以被 `endpoints.EnumPartitions`接口使用。这样就可以获取 SDK 使用的分区片段，也可以列出每个分区的分区信息。

```
// 迭代所有分区表打印每个分区的ID
resolver := endpoints.DefaultResolver()
partitions := resolver.(endpoints.EnumPartitions).Partitions()

for _, p := range partitions {
        fmt.Println("Partition:", p.ID())
}

```

除了分区表之外，endpoints 包也提供了每个分区组的 getter 函数。这些工具函数可以方便列出指定分区，而不用执行默认解析器列出所有的分区。

```
partition := endpoints.AwsPartition()
region := partition.Regions()[endpoints.UsWest2RegionID]

fmt.Println("Services in region:", region.ID())
for id, _ := range region.Services() {
        fmt.Println(id)
}

```

当你获取区域和服务值后，可以调用 `ResolveEndpoint`。这样解析端点时，就可以提供分区的过滤视图。

获取更多 AWS SDK for GO 信息, 请关注[其开源仓库](https://github.com/aws/aws-sdk-go/tree/master/example/aws/endpoints)。若你有更好的看法，请留言评论。

---

via: <https://aws.amazon.com/cn/blogs/developer/using-the-aws-sdk-for-gos-regions-and-endpoints-metadata>

作者：[Jason Del Ponte](https://aws.amazon.com/cn/blogs/developer/using-the-aws-sdk-for-gos-regions-and-endpoints-metadata) 译者：[Vic020](http://vicyu.com) 校对：[wxy](https://github.com/wxy)

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


在 Linux 上使用 Nginx 和 Gunicorn 托管 Django 应用

真是逗比啊，难道不是最重要的 让gunicorn 实现 服务化吗？<br />
不来一篇  supervisor 配置gunicorn 吗？

支持原文作者的创作

![](/data/attachment/album/201704/15/163522an5lbtgga4lcx6gt.png)

### 介绍

托管 Django Web 应用程序相当简单，虽然它比标准的 PHP 应用程序更复杂一些。 让 Web 服务器对接 Django 的方法有很多。 Gunicorn 就是其中最简单的一个。

Gunicorn（Green Unicorn 的缩写）在你的 Web 服务器 Django 之间作为中间服务器使用，在这里，Web 服务器就是 Nginx。 Gunicorn 服务于应用程序，而 Nginx 处理静态内容。

### Gunicorn

#### 安装

使用 Pip 安装 Gunicorn 是超级简单的。 如果你已经使用 virtualenv 搭建好了你的 Django 项目，那么你就有了 Pip，并且应该熟悉 Pip 的工作方式。 所以，在你的 virtualenv 中安装 Gunicorn。

```
$ pip install gunicorn

```

#### 配置

Gunicorn 最有吸引力的一个地方就是它的配置非常简单。处理配置最好的方法就是在 Django 项目的根目录下创建一个名叫 `Gunicorn` 的文件夹。然后在该文件夹内，创建一个配置文件。

在本篇教程中，配置文件名称是 `gunicorn-conf.py`。在该文件中，创建类似于下面的配置：

```
import multiprocessing

bind = 'unix:///tmp/gunicorn1.sock'
workers = multiprocessing.cpu_count() * 2 + 1
reload = True
daemon = True

```

在上述配置的情况下，Gunicorn 会在 `/tmp/` 目录下创建一个名为 `gunicorn1.sock` 的 Unix 套接字。 还会启动一些工作进程，进程数量相当于 CPU 内核数量的 2 倍。 它还会自动重新加载并作为守护进程运行。

#### 运行

Gunicorn 的运行命令有点长，指定了一些附加的配置项。 最重要的部分是将 Gunicorn 指向你项目的 `.wsgi` 文件。

```
gunicorn -c gunicorn/gunicorn-conf.py -D --error-logfile gunicorn/error.log yourproject.wsgi

```

上面的命令应该从项目的根目录运行。 `-c` 选项告诉 Gunicorn 使用你创建的配置文件。 `-D` 再次指定 gunicorn 为守护进程。 最后一部分指定 Gunicorn 的错误日志文件在你创建 `Gunicorn` 文件夹中的位置。 命令结束部分就是为 Gunicorn 指定 `.wsgi` 文件的位置。

### Nginx

现在 Gunicorn 配置好了并且已经开始运行了，你可以设置 Nginx 连接它，为你的静态文件提供服务。 本指南假定你已经配置好了 Nginx，而且你通过它托管的站点使用了单独的 server 块。 它还将包括一些 SSL 信息。

如果你想知道如何让你的网站获得免费的 SSL 证书，请查看我们的 [Let'sEncrypt 指南](https://linuxconfig.org/generate-ssl-certificates-with-letsencrypt-debian-linux)。

```
# 连接到 Gunicorn
upstream yourproject-gunicorn {
    server unix:/tmp/gunicorn1.sock fail_timeout=0;
}

# 将未加密的流量重定向到加密的网站
server {
    listen       80;
    server_name  yourwebsite.com;
    return       301 https://yourwebsite.com$request_uri;
}

# 主服务块
server {
    # 设置监听的端口，指定监听的域名
    listen 443 default ssl;
    client_max_body_size 4G;
    server_name yourwebsite.com;

    # 指定日志位置
    access_log /var/log/nginx/yourwebsite.access_log main;
    error_log /var/log/nginx/yourwebsite.error_log info;

    # 告诉 nginx 你的 ssl 证书
    ssl on;
    ssl_certificate /etc/letsencrypt/live/yourwebsite.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourwebsite.com/privkey.pem;

    # 设置根目录
    root /var/www/yourvirtualenv/yourproject;

    # 为 Nginx 指定静态文件路径
    location /static/ {
        # Autoindex the files to make them browsable if you want
        autoindex on;
        # The location of your files
        alias /var/www/yourvirtualenv/yourproject/static/;
        # Set up caching for your static files
        expires 1M;
        access_log off;
        add_header Cache-Control "public";
        proxy_ignore_headers "Set-Cookie";
    }

    # 为 Nginx 指定你上传文件的路径
    location /media/ {
        Autoindex if you want
        autoindex on;
        # The location of your uploaded files
        alias /var/www/yourvirtualenv/yourproject/media/;
        # Set up aching for your uploaded files
        expires 1M;
        access_log off;
        add_header Cache-Control "public";
        proxy_ignore_headers "Set-Cookie";
    }

    location / {
        # Try your static files first, then redirect to Gunicorn
        try_files $uri @proxy_to_app;
    }

    # 将请求传递给 Gunicorn
    location @proxy_to_app {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass   http://njc-gunicorn;
    }

    # 缓存 HTML、XML 和 JSON
    location ~* \.(html?|xml|json)$ {
        expires 1h;
    }

    # 缓存所有其他的静态资源
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|ttf|woff2)$ {
        expires 1M;
        access_log off;
        add_header Cache-Control "public";
        proxy_ignore_headers "Set-Cookie";
    }
}

```

配置文件有点长，但是还可以更长一些。其中重点是指向 Gunicorn 的 `upstream` 块以及将流量传递给 Gunicorn 的 `location` 块。大多数其他的配置项都是可选，但是你应该按照一定的形式来配置。配置中的注释应该可以帮助你了解具体细节。

保存文件之后，你可以重启 Nginx，让修改的配置生效。

```
# systemctl restart nginx

```

一旦 Nginx 在线生效，你的站点就可以通过域名访问了。

### 结语

如果你想深入研究，Nginx 可以做很多事情。但是，上面提供的配置是一个很好的开始，并且你可以用于实践中。 如果你见惯了 Apache 和臃肿的 PHP 应用程序，像这样的服务器配置的速度应该是一个惊喜。

---

via: <https://linuxconfig.org/hosting-django-with-nginx-and-gunicorn-on-linux>

作者：[Nick Congleton](https://linuxconfig.org/hosting-django-with-nginx-and-gunicorn-on-linux) 译者：[Flowsnow](https://github.com/Flowsnow) 校对：[wxy](https://github.com/wxy)

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


如何在 Ubuntu 和 Linux Mint 上启用桌面共享

怎可以不提桌面共享背后其实

是用了一款叫 vino 的 vnc 服务端软件呢?

还有, 如果安装了 ufw 防火壁，需要将预设端口 5900 打开

![](/data/attachment/album/201704/15/164614ahzgiqa2oixhih41.png)

桌面共享是指通过图形终端仿真器在计算机桌面上实现远程访问和远程协作的技术。桌面共享允许两个或多个连接到网络的计算机用户在不同位置对同一个文件进行操作。

在这篇文章中，我将向你展示如何在 Ubuntu 和 Linux Mint 中启用桌面共享，并展示一些重要的安全特性。

### 在 Ubuntu 和 Linux Mint 上启用桌面共享

１、在 Ubuntu Dash 或 Linux Mint 菜单中，像下面的截图这样搜索 `desktop sharing`，搜索到以后，打开它。

![Search for Desktop Sharing in Ubuntu](/data/attachment/album/201704/15/164614bl1141lgg178lldi.png)

*在 Ubuntu 中搜索 Desktop sharing*

２、打开 Desktop sharing 以后，有三个关于桌面共享设置的选项：共享、安全以及通知设置。

在共享选项下面，选中选项“允许其他用户查看桌面”来启用桌面共享。另外，你还可以选中选项“允许其他用户控制你的桌面”，从而允许其他用户远程控制你的桌面。

![Desktop Sharing Preferences](/data/attachment/album/201704/15/164615mt8vkvopc2p9k9pk.png)

*桌面共享偏好*

３、接下来，在“安全”部分，你可以通过勾选选项“你必须确认任何对该计算机的访问”来手动确认每个远程连接。

另外，另一个有用的安全特性是通过选项“需要用户输入密码”创建一个确定的共享密码。这样当用户每次想要访问你的桌面时需要知道并输入密码。

４、对于通知，你可以勾选“仅当有人连接上时”来监视远程连接，这样每次当有人远程连接到你的桌面时，可以在通知区域查看。

![Configure Desktop Sharing Set](/data/attachment/album/201704/15/164615oj68pgj9guvjroj4.png)

*配置桌面共享设置*

当所有的桌面共享选项都设置好以后，点击“关闭”。现在，你已经在你的 Ubuntu 或 Linux Mint 上成功启用了桌面共享。

### 测试 Ubuntu 的远程桌面共享

你可以通过使用一个远程连接应用来进行测试，从而确保桌面共享可用。在这个例子中，我将展示上面设置的一些选项是如何工作的。

５、我将使用 VNC（虚拟网络计算）协议通过 [remmina 远程连接应用](http://www.tecmint.com/remmina-remote-desktop-sharing-and-ssh-client)连接到我的 Ubuntu PC。

![Remmina Desktop Sharing Tool](/data/attachment/album/201704/15/164616q5gbg5539gxgjv65.png)

*Remmina 桌面共享工具*

６、在点击 Ubuntu PC 以后，将会出现下面这个配置连接设置的界面，

![Remmina Desktop Sharing Preferences](/data/attachment/album/201704/15/164616rrduuvdzx4qras1h.png)

*Remmina 桌面共享偏好*

７、当执行好所有设置以后，点击连接。然后，给用户名提供 SSH 密码并点击 OK 。

![Enter SSH User Password](/data/attachment/album/201704/15/164617tu8qqafqmqvvl0ll.png)

*输入 SSH 用户密码*

点击确定以后，出现下面这个黑屏，这是因为在远程机器上，连接还没有确认。

![Black Screen Before Confirmation](/data/attachment/album/201704/15/164617whw2j6ymkqq0hqf4.png)

*连接确认前的黑屏*

８、现在，在远程机器上，我需要如下一个屏幕截图显示的那样点击 `Allow` 来接受远程访问请求。

![Allow Remote Desktop Sharing](/data/attachment/album/201704/15/164618cehy4400z4t00whs.png)

*允许远程桌面共享*

９、在接受请求以后，我就成功地连接到了远程 Ubuntu 机器的桌面。

![Remote Ubuntu Desktop](/data/attachment/album/201704/15/164618ccjk9xsz897tvzjk.png)

*远程 Ubuntu 桌面*

这就是全部内容了，在这篇文章中，我们讲解了如何在 Ubuntu 和 Linux Mint 中启用桌面共享。你使用评论部分给我们写反馈。

---

作者简介：

Aaron Kili 是 Linux 和 F.O.S.S 爱好者，将来的 Linux 系统管理员和网络开发人员，目前是 TecMint 的内容创作者，他喜欢用电脑工作，并坚信分享知识。

---

via: <http://www.tecmint.com/enable-desktop-sharing-in-ubuntu-linux-mint/>

作者：[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/) 荣誉推出


使用 IBM Bluemix 构建，部署和管理自定义应用程序

Summary: IBM Bluemix 为开发人员提供了构建、部署和管理自定义应用程序的机会。Bluemix 建立在 Cloud Foundry 上。它支持多种编程语言，包括 IBM 的 OpenWhisk ，还允许开发人员无需资源管理就调用任何函数。

![](/data/attachment/album/201704/16/095838zwuprp3j9buy7l2q.jpg)

Bluemix 是由 IBM 实现的基于开放标准的云平台。它具有开放的架构，其允许组织能够在云上创建、开发和管理其应用程序。它基于 Cloud Foundry ，因此可以被视为平台即服务（PaaS）。使用 Bluemix，开发人员不必关心云端配置，可以专注于他们的应用程序。 云端配置将由 Bluemix 自动完成。

Bluemix 还提供了一个仪表板，通过它，开发人员可以创建，管理和查看服务和应用程序，同时还可以监控资源使用情况。

它支持以下编程语言：

* Java
* Python
* Ruby on Rails
* PHP
* Node.js

它还支持 OpenWhisk（FaaS），这也是一个 IBM 的产品，其允许开发人员调用任一功能而不需要任何资源管理。

![图1 IBM Bluemix概述](/data/attachment/album/201704/16/095840jze6zv5q6v537673.jpg)

*图1 IBM Bluemix 概述*

![图2 IBM Bluemix体系结构](/data/attachment/album/201704/16/095841crcwxd0bmd45d4ru.jpg)

*图2 IBM Bluemix 体系结构*

![图3 在IBM Bluemix 中创建组织](/data/attachment/album/201704/16/095842mff7aj5yjajd26xi.jpg)

*图3 在 IBM Bluemix 中创建组织*

### IBM Bluemix 如何工作

Bluemix 构建在 IBM 的 SoftLayer IaaS（基础架构即服务）之上。它使用 Cloud Foundry 作为开源 PaaS 平台。一切起于通过 Cloud Foundry 来推送代码，它扮演着将代码和编写应用所使用的编程语言运行时环境整合起来的角色。IBM 服务、第三方服务或社区构建的服务可用于不同的功能。安全连接器可用于将本地系统连接到云。

![图4 在IBM Bluemix中设置空间](/data/attachment/album/201704/16/095843g3pprryrp3exxuzy.jpg)

*图4 在 IBM Bluemix 中设置空间*

![图5 应用程序模板](/data/attachment/album/201704/16/095844y8yvbe3oinvvq3d3.jpg)

*图5 应用程序模板*

![图6 IBM Bluemix支持的编程语言](/data/attachment/album/201704/16/095845i6zqbt1th7tuugtj.jpg)

*图6 IBM Bluemix 支持的编程语言*

### 在 Bluemix 中创建应用程序

在本文中，我们将使用 Liberty for Java 的入门包在 IBM Bluemix 中创建一个示例“Hello World”应用程序，只需几个简单的步骤。

1、 打开 [https：//console.ng.bluemix.net/registration/](https://console.ng.bluemix.net/registration/)

2、 注册 Bluemix 帐户

3、 点击邮件中的确认链接完成注册过程

4、 输入您的电子邮件 ID，然后点击 Continue 进行登录

5、 输入密码并点击 Log in

6、 进入 Set up -> Environment 设置特定区域中的资源共享

7、 创建空间方便管理访问控制和在 Bluemix 中回滚操作。 我们可以将空间映射到多个开发阶段，如 dev， test，uat，pre-prod 和 prod

![图7 命名应用程序](/data/attachment/album/201704/16/095846to43pqam31gappmo.jpg)

*图7 命名应用程序*

![图8 了解应用程序何时准备就绪](/data/attachment/album/201704/16/095847bo25g752bwlvlv66.jpg)

*图8 了解应用程序何时准备就绪*

![图9 IBM Bluemix Java应用程序](/data/attachment/album/201704/16/095847ebcbss2is28ia828.jpg)

*图9 IBM Bluemix Java 应用程序*

8、 完成初始配置后，单击 I'm ready -> Good to Go ！

9、 成功登录后，此时检查 IBM Bluemix 仪表板，特别是 Cloud Foundry Apps（其中 2GB 可用）和 Virtual Server（其中 0 个实例可用）的部分

10、 点击 Create app，选择应用创建模板。在我们的例子中，我们将使用一个 Web 应用程序

11、 如何开始？单击 Liberty for Java ，然后查看其描述

12、 单击 Continue

13、 为新应用命名。对于本文，让我们使用 osfy-bluemix-tutorial 命名然后单击 Finish

14、 在 Bluemix 上创建资源和托管应用程序需要等待一些时间

15、 几分钟后，应用程式就会开始运作。注意应用程序的URL

16、 访问应用程序的URL http：//osfy-bluemix-tutorial.au-syd.mybluemix.net/, 不错，我们的第一个在 IBM Bluemix 上的 Java 应用程序成功运行

17、 为了检查源代码，请单击 Files 并在门户中导航到不同文件和文件夹

18、 Logs 部分提供包括从应用程序的创建时起的所有活动日志。

19、 Environment Variables 部分提供关于 VCAP\_Services 的所有环境变量以及用户定义的环境变量的详细信息

20、 要检查应用程序的资源消耗，需要到 Liberty for Java 那一部分。

21、 默认情况下，每个应用程序的 Overview 部分包含资源，应用程序的运行状况和活动日志的详细信息

22、 打开 Eclipse，转到帮助菜单，然后单击 *Eclipse Marketplace*

23、 查找 IBM Eclipse tools for Bluemix 并单击 Install

24、 确认所选的功能并将其安装在 Eclipse 中

25、 下载应用程序启动器代码。点击 File Menu，将它导入到 Eclipse 中，选择 Import Existing Projects -> Workspace, 然后开始修改代码

![图10 Java应用程序源文件](/data/attachment/album/201704/16/095848mi4tekeet003nnew.jpg)

*图10 Java 应用程序源文件*

![图11 Java应用程序日志](/data/attachment/album/201704/16/095849epewtatnvdnpwpud.jpg)

*图11 Java 应用程序日志*

![图12 Java应用程序 - Liberty for Java](/data/attachment/album/201704/16/095850i0t11c1s0fp8wk8n.jpg)

*图12 Java 应用程序 - Liberty for Java*

### 为什么选择 IBM Bluemix？

以下是使用 IBM Bluemix 的一些令人信服的理由：

* 支持多种语言和平台
* 免费试用
	1. 简化的注册过程
	2. 不需要信用卡
	3. 30 天试用期 - 配额 2GB 的运行时，支持 20 个服务，500 个 route
	4. 无限制地访问标准支持
	5. 没有生产使用限制
* 仅为每个使用的运行时和服务付费
* 快速设置 - 从而加快上架时间
* 持续交付新功能
* 与本地资源的安全集成
* 用例
	1. Web 应用程序和移动后端
	2. API 和内部集成
* DevOps 服务可部署在云上的 SaaS ，并支持持续交付：
	1. Web IDE
	2. SCM
	3. 敏捷规划
	4. 交货管道服务

---

via: <http://opensourceforu.com/2016/11/build-deploy-manage-custom-apps-ibm-bluemix/>

作者：[MITESH\_SONI](http://opensourceforu.com/author/mitesh_soni/) 译者：[Vic020](http//www.vicyu.net) 校对：[Bestony](https://github.com/Bestony)

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


Samba 系列（七）：在 Samba AD DC 服务器上创建共享目录并映射到 Windows/Linux 客户

这篇文章将指导你如何在 Samba AD DC 服务器上创建共享目录，然后通过 GPO 把共享目录挂载到域中的其它 Windows 成员机，并且从 Windows 域控的角度来管理共享权限。

这篇文章也包括在加入域的 Linux 机器上如何使用 Samba4 域帐号来访问及挂载共享文件。

![](/data/attachment/album/201704/16/102242qyzib8sf080foeez.jpg)

### 需求：

1、[在 Ubuntu 系统上使用 Samba4 来创建活动目录架构](/article-8065-1.html)

2、[在 Linux 命令行下管理 Samba4 AD 架构](/article-8070-1.html)

3、[使用 Windows 10 的 RSAT 工具来管理 Samba4 活动目录架构](/article-8097-1.html)

4、[在 Windows 下管理 Samba4 AD 域管制器 DNS 和组策略](/article-8258-1.html)

5、[将另一台 Ubuntu DC 服务器加入到 Samba4 AD DC 实现双域控主机模式](/article-8358-1.html)

6、[使用 Rsync 命令同步两个 Samba4 AD DC 之间的 SysVol 目录](/article-8384-1.html)

### 第一步：创建 Samba 文件共享

1、在 Samba AD DC 服务器上创建共享非常简单。首先创建一个你想通过 SMB 协议来分享文件的目录，然后添加下面的文件系统权限，这是为了让 Windows AD DC 管理员给 Windows 客户端分配相应的共享权限。

假设在 AD DC 服务器上有一个新的共享目录 '/nas' ，执行下面的命令来授予必要的权限。

```
# mkdir /nas
# chmod -R 775 /nas
# chown -R root:"domain users" /nas
# ls -alh | grep nas

```

![Create Samba Shared Directory](/data/attachment/album/201704/16/102256rn8nagrln8m5485z.png)

*创建 Samba 共享目录*

2、当你在 Samba4 AD DC 服务器上创建完成共享目录之后，你还得修改 samba 配置文件，添加下面的参数以允许通过 SMB 协议来共享文件。

```
# nano /etc/samba/smb.conf

```

在配置文件末尾添加以下内容：

```
[nas]
path = /nas
read only = no

```

![Configure Samba Shared Directory](/data/attachment/album/201704/16/102257jkzdsxmxrazsdkms.png)

*配置 Samba 共享目录*

3、最后，你需要通过下面的命令重启 Samba AD DC 服务，以让修改的配置生效：

```
# systemctl restart samba-ad-dc.service

```

### 第二步：管理 Samba 共享权限

4、我们准备使用在 Samba AD DC 服务器上创建的域帐号（包括用户和组）来访问这个共享目录（禁止 Linux 系统用户访问共享目录）。

可以直接通过 Windows 资源管理器来完成 Samba 共享权限的管理，就跟你在 Windows 资源管理器中设置其它文件夹权限的方法一样。

首先，使用具有管理员权限的 Samba4 AD 域帐号登录到 Windows 机器。然而在 Windows 机器上的资源管理器中输入双斜杠和 Samba AD DC 服务器的 IP 地址或主机名或者是 FQDN 来访问共享文件和设置权限。

```
\\adc1
或
\\192.168.1.254
或
\\adc1.tecmint.lan

```

![Access Samba Share Directory from Windows](/data/attachment/album/201704/16/102257s010egej07z1y0lo.png)

*从 Windows 机器访问 Samba 共享目录*

5、右键单击共享文件，选择属性来设置权限。打开安全选项卡，依次修改域账号和组权限。使用高级选项来调整权限。

![Configure Samba Share Directory Permissions](/data/attachment/album/201704/16/102258rg0aakfh30k001hp.png)

*配置 Samba 共享目录权限*

可参考下面的截图来为指定 Samba AD DC 认证用户设置权限。

![Manage Samba Share Directory User Permissions](/data/attachment/album/201704/16/102258v78wk5ouqzeq63qi.png)

*设置 Samba 共享目录用户权限*

6、你也可以使用其它方法来设置共享权限，打开计算机管理-->连接到另外一台计算机。

找到共享目录，右键单击你想修改权限的目录，选择属性，打开安全选项卡。你可以在这里修改任何权限，就跟上图的修改共享文件夹权限的方法一样。

![Connect to Samba Share Directory Machine](/data/attachment/album/201704/16/102258qtewjbyehuvcmw7m.png)

*连接到 Samba 共享目录服务器*

![Manage Samba Share Directory Properties](/data/attachment/album/201704/16/102259vjblo5o8mixxlzwl.png)

*管理 Samba 共享目录属性*

![Assign Samba Share Directory Permissions to Users](/data/attachment/album/201704/16/102259pr98vwhjt6spuw51.png)

*为域用户授予共享目录权限*

### 第三步：通过 GPO 来映射 Samba 文件共享

7、要想通过域组策略来挂载 Samba 共享的目录，你得先到一台[已安装了 RSAT 工具](/article-8097-1.html) 的服务器上，打开 AD DC 工具，右键单击域名，选择新建-->共享文件夹。

![Map Samba Share Folder](/data/attachment/album/201704/16/102300cnyep2y2ynrqx3zy.png)

*映射 Samba 共享文件夹*

8、为共享文件夹添加一个名字，然后输入共享文件夹的网络路径，如下图所示。完成后单击 OK 按钮，你就可以在右侧看到文件夹了。

![Set Samba Shared Folder Name Location](/data/attachment/album/201704/16/102300l7ssc4tz6jz30icc.png)

*设置 Samba 共享文件夹名称及路径*

9、下一步，打开组策略管理控制台，找到当前域的默认域策略脚本，然后打开并编辑该文件。

在 GPM 编辑器界面，打开 GPM 编辑器，找到用户配置 --> 首选项 --> Windows 设置，然而右键单击驱动器映射，选择新建 --> 映射驱动。

![Map Samba Share Folder in Windows](/data/attachment/album/201704/16/102300iwp0wereefero2ws.png)

*在 Windows 机器上映射 Samba 共享文件夹*

10、通过单击右边的三个小点，在新窗口中查询并添加共享目录的网络位置，勾选重新连接复选框，为该目录添加一个标签，选择驱动盘符，然后单击 OK 按钮来保存和应用配置。

![Configure Network Location for Samba Share Directory](/data/attachment/album/201704/16/102301l8fyrf291fwy6yz9.png)

*配置 Samba 共享目录的网络位置*

11、最后，为了在本地机器上强制应用 GPO 更改而不重启系统，打开命令行提示符，然而执行下面的命令。

```
gpupdate /force

```

![Apply GPO Changes](/data/attachment/album/201704/16/102301ebefbzrcymhy899b.png)

*应用 GPO 更改*

12、当你在本地机器上成功应用策略后，打开 Windows 资源管理器，你就可以看到并访问共享的网络文件夹了，能否正常访问共享目录取决于你在前一步的授权操作。

如果没有在命令行下强制应用组策略，你网络中的其它客户机需要重启或重新登录系统才可以看到共享目录。

![Samba Shared Network Volume on Windows](/data/attachment/album/201704/16/102302nuvkzk1rvjyvt8c1.png)

*Windows 机器上挂载的 Samba 网络磁盘*

### 第四步：从 Linux 客户端访问 Samba 共享目录

13、已加入 Samba AD DC 中的 Linux 成员机上的系统用户也可以可以使用 Samba 帐号访问或在本地挂载共享目录。

首先，你得通过下面的命令来确保 Samba 客户端和工具已经安装完成。

```
$ sudo apt-get install smbclient cifs-utils

```

14、为了列出域环境中的共享目录，你可以通过下面的命令加入指定的域控服务器主机名来查询：

```
$ smbclient –L your_domain_controller –U%
或
$ smbclient –L \\adc1 –U%

```

![List Samba Share Directory in Linux](/data/attachment/album/201704/16/102302uu0e26guggu4guz6.png)

*在 Linux 机器上列出 Samba 共享目录*

15、在命令行下使用域帐号以交互试方式连接到 Samba 共享目录：

```
$ sudo smbclient //adc/share_name -U domain_user

```

在命令行下，你可以列出共享目录内容，下载或上传文件到共享目录，或者执行其它操作。使用 `?` 来查询所有可用的 smbclient 命令。

![Connect Samba Share Directory in Linux](/data/attachment/album/201704/16/102303ktedd80y4xinatnp.png)

*在 Linux 机器上连接 Samba 共享目录*

16、在 Linux 机器上使用下面的命令来挂载 samba 共享目录。

```
$ sudo mount //adc/share_name /mnt -o username=domain_user

```

![Mount Samba Share Directory in Linux](/data/attachment/album/201704/16/102303t19i1e5yeeywsbjg.png)

*在 Linux 机器上挂载 samba 共享目录*

根据实际情况，依次替换主机名、共享目录名、挂载点和域帐号。使用 `mount` 命令加上管道符和 `grep` 命令来过滤出 cifs 类型的文件系统。

通过上面的测试，我们可以看出，在 Samba4 AD DC 服务器上配置共享目录仅使用 Windows 访问控制列表（ ACL ），而不是 POSIX ACL 。

通过文件共享把 Samba 配置为域成员以使用其它网络共享功能。同时，在另一个域控制器上[配置 Windbindd 服务](/article-8070-1.html) ——在你开始发起网络共享文件之前。

---

作者简介：

我是一个电脑迷，开源 Linux 系统和软件爱好者，有 4 年多的 Linux 桌面、服务器系统使用和 Base 编程经验。

译者简介：

春城初春/春水初生/春林初盛/春風十裏不如妳 [rusking](https://github.com/rusking)

---

via: <http://www.tecmint.com/create-shared-directory-on-samba-ad-dc-and-map-to-windows-linux/>

作者：[Matei Cezar](http://www.tecmint.com/author/cezarmatei/) 译者：[rusking](https://github.com/rusking) 校对：[wxy](https://github.com/wxy)

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


工程师和市场营销人员之间能够相互学习什么？

一位优秀的营销人员懂得如何心平气和的跟sb说话<br />
一位优秀的工程师可以让sb心平气和的和自己说话；

>
> 营销人员觉得工程师在工作中都太严谨了；而工程师则认为营销人员毫无用处。但是他们都错了。
>
>
>

![What engineers and marketers can learn from each other](/data/attachment/album/201704/16/200201y3hz3hpypmphiyju.png "What engineers and marketers can learn from each other")

在 B2B 行业从事多年的销售实践过程中，我经常听到工程师对营销人员的各种误解。下面这些是比较常见的：

* “搞市场营销真是浪费钱，还不如把更多的资金投入到实际的产品开发中来。”
* “那些营销人员只是一个劲儿往墙上贴各种广告，还祈祷着它们不要掉下来。这么做有啥科学依据啊？”
* “谁愿意去看哪些广告啊？”
* “对待一个营销人员最好的办法就是不听，不看，也不理睬。”

这是我最感兴趣的一点：

*“市场营销无足轻重。”*

最后一点说的不对，而且不仅如此，它实际上是阻碍一个公司创新的巨大绊脚石。

我来跟大家解释一下原因吧。

### 看到自己的身影

这些工程师的的评论让我十分的苦恼，因为我从中看到了自己当年的身影。

你们知道吗？我曾经也跟你们一样是一位自豪的技术极客。我在 Rensselaer Polytechnic 学院的电气工程专业本科毕业后便在美国空军担任军官开始了我的职业生涯，而且美国空军在那段时间还发动了沙漠风暴行动。在那里我主要负责开发并部属一套智能的实时战况分析系统，用于综合几个的数据源来构建出战场态势。

在我离开空军之后，我本打算去麻省理工学院攻读博士学位。但是上校强烈建议我去报读这个学校的商学院。“你真的想一辈子待实验室里吗？”他问我。“你想就这么去大学里当个教书匠吗？Jackie ，你在组织管理那些复杂的工作中比较有天赋。我觉得你非常有必要去了解下 MIT 的斯隆商学院。”

我觉得自己也可以同时参加一些 MIT 技术方面的课程，因此我采纳了他的建议。然而，如果要参加市场营销管理方面的课程，我还有很长的路要走，这完全是在浪费时间。因此，在日常工作学习中，我始终是用自己所擅长的分析能力去解决一切问题。

不久后，我在波士顿咨询集团公司做咨询顾问工作。在那六年的时间里，我经常听到大家对我的评论： “Jackie ，你太没远见了。考虑问题也不够周全。你总是通过自己的分析去找答案。”

确实如此啊，我很赞同他们的想法——因为这个世界的工作方式本该如此，任何问题都要基于数据进行分析，不对吗？直到现在我才意识到（我多么希望自己早一些发现自己的问题）自己以前惯用的分析问题的方法遗漏了很多重要的东西：开放的心态、艺术修养、情感——人和创造性思维相关的因素。

我在 2001 年 9 月 11 日加入达美航空公司不久后，被调去管理消费者市场部门，之前我意识到的所有问题变得更加明显。市场方面本来不是我的强项，但是在公司需要的情况下，我也愿意出手相肋。

但是突然之间，我一直惯用的方法获取到的分析结果却与实际情况完全相反。这个问题导致上千人（包括航线内外的人）受到影响。我忽略了一个很重要的人本身的情感因素。我所面临的问题需要各种各样的解决方案才能处理，而不是简单的从那些死板的数据中就能得到答案。

那段时间，我快速地学到了很多东西，因为如果我们想把达美航空公司恢复到正常状态，还需要做很多的工作——市场营销更像是一个以解决问题为导向、以用户为中心的充满挑战性的大工程，只是销售人员和工程师这两大阵营都没有迅速地意识到这个问题。

### 两大文化差异

工程管理和市场营销之间的这个“巨大鸿沟”确实是根深蒂固的，这跟（著名的科学家、小说家） C.P. Snow 提出的[“两大文化差异”问题](https://en.wikipedia.org/wiki/The_Two_Cultures#Implications_and_influence)很相似。具有科学素质的工程师和具有艺术细胞的营销人员操着不同的语言，不同的文化观念导致他们不同的价值取向。

但是，事实上他们比想象中有更多的相似之处。一个由微软、谷歌和美国国家科学基金会共同赞助的华盛顿大学的[最新研究](https://faculty.washington.edu/ajko/papers/Li2015GreatEngineers.pdf)发现了“一个伟大软件工程师必须具备哪些优秀的素质”，毫无疑问，一个伟大的销售人员同样也应该具备这些素质。例如，专家们给出的一些优秀品质如下：

* 充满激情
* 性格开朗
* 强烈的好奇心
* 技艺精湛
* 解决复杂难题的能力

这些只是其中很小的一部分！当然，并不是所有的素质都适用于市场营销人员，但是如果用文氏图来表示这“两大文化”的交集，就很容易看出营销人员和工程师之间的关系要远比我们想象中密切得多。他们都是竭力去解决与用户或客户相关的难题，只是他们所采取的方式和角度不一致罢了。

看到上面的那几点后，我深深的陷入思考：*要是这两类员工彼此之间再多了解对方一些会怎样呢？这会给公司带来很强大的动力吧？*

确实如此。我在红帽公司就亲眼看到过样的情形，我身边都是一些早些年肯定被我当成“想法疯狂”而无视的人。而且我猜销售人员看到工程师后（同时或某一次），心想，“这些数据呆瓜，真是只见树木不见森林。”

现在我才明白了公司里有这两种人才的重要性。在现实工作当中，工程师和营销人员都是围绕着客户、创新及数据分析来完成工作。如果他们能够懂得相互尊重、彼此理解、相辅相成，那么我们将会看到公司里所产生的那种积极强大的动力，这种超乎寻常的革新力量要远比两个独立的团队强大得多。

### 听一听疯子（和呆瓜）的想法

成功案例：《开放式组织》

在红帽任职期间，我的主要工作就是想办法提升公司的品牌影响力——但是就是给我一百万年我也不会想到让公司的 CEO 去写一本书。我把公司多个部门的“想法疯狂”的同事召集在一起，希望他们帮我设计出一个新颖的解决方案来提升公司的影响力，结果他们提出让公司的 CEO 写书这样一个想法。

当我听到这个想法的时候，我很快意识到这正是典型的红帽方式：它将对整个开源社区的从业者带来很重要的参考价值，同时也有助于宣扬开源精神。通过优先考虑这两方面的作用，我们提升了红帽在整个开源软件世界中的品牌价值——红帽是一个可靠的随时准备着为客户在[数字化颠覆](https://opensource.com/open-organization/16/7/future-belongs-open-leaders)年代指明方向的公司。

这一点才是主要的：确切的说是指导红帽工程师解决代码问题的共同精神力量。 Red Hatters 小组敦促我出版《开放式组织》，这显示出来自内部和外部社区的程序员共同推动整个开源社区发展的强大动力之一：那就是强烈的共享欲望。

最后，要把《开放式组织》这本书完成，还需要大家的共同能力，包括工程师们强大的数据分析能力和营销人员美好的艺术素养。这个项目让我更加坚定自己的想法，工程师和营销人员有更多的相似之处。

但是，有些东西我还得强调下：开放模式的实现，要求公司上下没有任何偏见，不能偏袒工程师和市场营销人员任何一方文化。一个更加理想的开放式环境能够促使员工之间和平共处，并在这个组织规定的范围内点燃大家的热情。

这对我来说如春风拂面。

（图片来源：opensource.com）

---

作者简介：

Jackie Yeaney —— Ellucian 公司市场总监

---

via: <https://opensource.com/open-organization/17/1/engineers-marketers-can-learn>

作者：[Jackie Yeaney](https://opensource.com/users/jackie-yeaney) 译者：[rusking](https://github.com/rusking) 校对：[Bestony](https://github.com/Bestony), [wxy](https://github.com/wxy)

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


漫画赏析：消沉的程序员 13

挺有意思

“nano 服务器”？ 是指 Windows Nano Server 吗？Windows Nano Server 是微软第一个真真正正的无 GUI 服务器，而 Windows Server Core 是简化了 GUI 界面的服务器。网上有人看见 Command Prompt (cmd.exe) 就说那是字符界面，所谓 Core 只是把 Shell 由 explorer.exe 换成了 cmd.exe，并且去掉了若干与 GUI 相关的交互式组件。其他该有的还是有。

100万这也太屌了吧

![](/data/attachment/album/201704/17/085808zn44g86axx66gk3q.png)

嘿嘿，明明你有很厉害的东西想要分享给自己的同伴，可是他们并不能理解那意味着什么，然后拿一些简单的不能再简单的事情来问你。是不是感觉好尴尬呢。看来有些事儿，分享也要看人的吧，否则表错情真的是大写的失落。

---

译者简介：

[GHLandy](http://ghlandy.com/) —— 生活中所有欢乐与苦闷都应藏在心中，有些事儿注定无人知晓，自己也无从说起。

---

via: <http://turnoff.us/geek/the-depressed-developer-13/>

作者：[Daniel Stori](http://turnoff.us/about/) 译者：[GHLandy](https://github.com/GHLandy) 校对：[wxy](https://github.com/wxy) 合成：[GHLandy](https://github.com/GHLandy) 点评：[GHLandy](https://github.com/GHLandy)

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


漫画赏析：消沉的程序员 14

![](/data/attachment/album/201704/17/090035yp00igmrxx0ipiit.png)

不管什么是在什么事情上，你所期待的结果，都是通过尽心设计才能得到的。所以，有拖延症的各位亲们，切莫把所有都拖到最后一分钟才去考虑解决方案哦，不然会死的很惨的。

---

译者简介：

[GHLandy](http://ghlandy.com/) —— 生活中所有欢乐与苦闷都应藏在心中，有些事儿注定无人知晓，自己也无从说起。

---

via: <http://turnoff.us/geek/the-depressed-developer-14/>

作者：[Daniel Stori](http://turnoff.us/about/) 译者：[GHLandy](https://github.com/GHLandy) 校对：[wxy](https://github.com/wxy) 合成：[GHLandy](https://github.com/GHLandy) 点评：[GHLandy](https://github.com/GHLandy)

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


深入解析面向数据的哈希表性能

![](/data/attachment/album/201704/17/111508k67c4f45b7bh6nnn.jpg)

最近几年中，面向数据的设计已经受到了很多的关注 —— 一种强调内存中数据布局的编程风格，包括如何访问以及将会引发多少的 cache 缺失。由于在内存读取操作中缺失所占的数量级要大于命中的数量级，所以缺失的数量通常是优化的关键标准。这不仅仅关乎那些对性能有要求的 code-data 结构设计的软件，由于缺乏对内存效益的重视而成为软件运行缓慢、膨胀的一个很大因素。

高效缓存数据结构的中心原则是将事情变得平滑和线性。比如，在大部分情况下，存储一个序列元素更倾向于使用普通数组而不是链表 —— 每一次通过指针来查找数据都会为 cache 缺失增加一份风险；而普通数组则可以预先获取，并使得内存系统以最大的效率运行

如果你知道一点内存层级如何运作的知识，下面的内容会是想当然的结果——但是有时候即便它们相当明显，测试一下任不失为一个好主意。几年前 [Baptiste Wicht 测试过了 `std::vector` vs `std::list` vs `std::deque`](http://baptiste-wicht.com/posts/2012/12/cpp-benchmark-vector-list-deque.html)，（后者通常使用分块数组来实现，比如：一个数组的数组）。结果大部分会和你预期的保持一致，但是会存在一些违反直觉的东西。作为实例：在序列链表的中间位置做插入或者移除操作被认为会比数组快，但如果该元素是一个 POD 类型，并且不大于 64 字节或者在 64 字节左右（在一个 cache 流水线内），通过对要操作的元素周围的数组元素进行移位操作要比从头遍历链表来的快。这是由于在遍历链表以及通过指针插入/删除元素的时候可能会导致不少的 cache 缺失，相对而言，数组移位则很少会发生。（对于更大的元素，非 POD 类型，或者你已经有了指向链表元素的指针，此时和预期的一样，链表胜出）

多亏了类似 Baptiste 这样的数据，我们知道了内存布局如何影响序列容器。但是关联容器，比如 hash 表会怎么样呢？已经有了些权威推荐：[Chandler Carruth 推荐的带局部探测的开放寻址](https://www.youtube.com/watch?v=fHNmRkzxHWs)（此时，我们没必要追踪指针），以及[Mike Acton 推荐的在内存中将 value 和 key 隔离](https://www.youtube.com/watch?v=rX0ItVEVjHc)（这种情况下，我们可以在每一个 cache 流水线中得到更多的 key）， 这可以在我们必须查找多个 key 时提高局部性能。这些想法很有意义，但再一次的说明：测试永远是好习惯，但由于我找不到任何数据，所以只好自己收集了。

### 测试

我测试了四个不同的 quick-and-dirty 哈希表实现，另外还包括 `std::unordered_map` 。这五个哈希表都使用了同一个哈希函数 —— Bob Jenkins 的 [SpookyHash](http://burtleburtle.net/bob/hash/spooky.html)（64 位哈希值）。（由于哈希函数在这里不是重点，所以我没有测试不同的哈希函数；我同样也没有检测我的分析中的总内存消耗。）实现会通过简短的代码在测试结果表中标注出来。

* **UM**： `std::unordered_map` 。在 VS2012 和 libstdc++-v3 （libstdc++-v3: gcc 和 clang 都会用到这东西）中，UM 是以链表的形式实现，所有的元素都在链表中，bucket 数组中存储了链表的迭代器。VS2012 中，则是一个双链表，每一个 bucket 存储了起始迭代器和结束迭代器；libstdc++ 中，是一个单链表，每一个 bucket 只存储了一个起始迭代器。这两种情况里，链表节点是独立申请和释放的。最大负载因子是 1 。
* **Ch**：分离的、链状 bucket 指向一个元素节点的单链表。为了避免分开申请每一个节点，元素节点存储在普通数组池中。未使用的节点保存在一个空闲链表中。最大负载因子是 1。
* **OL**：开地址线性探测 —— 每一个 bucket 存储一个 62 bit 的 hash 值，一个 2 bit 的状态值（包括 empty，filled，removed 三个状态），key 和 value 。最大负载因子是 2/3。
* **DO1**：“data-oriented 1” —— 和 OL 相似，但是哈希值、状态值和 key、values 分离在两个隔离的平滑数组中。
* **DO2**：“data-oriented 2” —— 与 OL 类似，但是哈希/状态，keys 和 values 被分离在 3 个相隔离的平滑数组中。

在我的所有实现中，包括 VS2012 的 UM 实现，默认使用尺寸为 2 的 n 次方。如果超出了最大负载因子，则扩展两倍。在 libstdc++ 中，UM 默认尺寸是一个素数。如果超出了最大负载因子，则扩展为下一个素数大小。但是我不认为这些细节对性能很重要。素数是一种对低 bit 位上没有足够熵的低劣 hash 函数的挽救手段，但是我们正在用的是一个很好的 hash 函数。

OL，DO1 和 DO2 的实现将共同的被称为 OA（open addressing）——稍后我们将发现它们在性能特性上非常相似。在每一个实现中，单元数从 100 K 到 1 M，有效负载（比如：总的 key + value 大小）从 8 到 4 k 字节我为几个不同的操作记了时间。 keys 和 values 永远是 POD 类型，keys 永远是 8 个字节（除了 8 字节的有效负载，此时 key 和 value 都是 4 字节）因为我的目的是为了测试内存影响而不是哈希函数性能，所以我将 key 放在连续的尺寸空间中。每一个测试都会重复 5 遍，然后记录最小的耗时。

测试的操作在这里：

* **Fill**：将一个随机的 key 序列插入到表中（key 在序列中是唯一的）。
* **Presized fill**：和 Fill 相似，但是在插入之间我们先为所有的 key 保留足够的内存空间，以防止在 fill 过程中 rehash 或者重申请。
* **Lookup**：执行 100 k 次随机 key 查找，所有的 key 都在 table 中。
* **Failed lookup**: 执行 100 k 次随机 key 查找，所有的 key 都不在 table 中。
* **Remove**：从 table 中移除随机选择的半数元素。
* **Destruct**：销毁 table 并释放内存。

你可以[在这里下载我的测试代码](http://reedbeta.com/blog/data-oriented-hash-table/hash-table-tests.zip)。这些代码只能在 64 机器上编译（包括Windows和Linux）。在 `main()` 函数顶部附近有一些开关，你可把它们打开或者关掉——如果全开，可能会需要一两个小时才能结束运行。我收集的结果也放在了那个打包文件里的 Excel 表中。（注意： Windows 和 Linux 在不同的 CPU 上跑的，所以时间不具备可比较性）代码也跑了一些单元测试，用来验证所有的 hash 表实现都能运行正确。

我还顺带尝试了附加的两个实现：Ch 中第一个节点存放在 bucket 中而不是 pool 里，二次探测的开放寻址。 这两个都不足以好到可以放在最终的数据里，但是它们的代码仍放在了打包文件里面。

### 结果

这里有成吨的数据!! 这一节我将详细的讨论一下结果，但是如果你对此不感兴趣，可以直接跳到下一节的总结。

#### Windows

这是所有的测试的图表结果，使用 Visual Studio 2012 编译，运行于 Windows 8.1 和 Core i7-4710HQ 机器上。

![Results for VS 2012, Windows 8.1, Core i7-4710HQ](/data/attachment/album/201704/17/111620o1ms81gco6arpgdp.png "Results for VS 2012, Windows 8.1, Core i7-4710HQ")

从左至右是不同的有效负载大小，从上往下是不同的操作（注意：不是所有的Y轴都是相同的比例！）我将为每一个操作总结一下主要趋向。

**Fill**：

在我的 hash 表中，Ch 稍比任何的 OA 变种要好。随着哈希表大小和有效负载的加大，差距也随之变大。我猜测这是由于 Ch 只需要从一个空闲链表中拉取一个元素，然后把它放在 bucket 前面，而 OA 不得不搜索一部分 bucket 来找到一个空位置。所有的 OA 变种的性能表现基本都很相似，当然 DO1 稍微有点优势。

在小负载的情况，UM 几乎是所有 hash 表中表现最差的 —— 因为 UM 为每一次的插入申请（内存）付出了沉重的代价。但是在 128 字节的时候，这些 hash 表基本相当，大负载的时候 UM 还赢了点。因为，我所有的实现都需要重新调整元素池的大小，并需要移动大量的元素到新池里面，这一点我几乎无能为力；而 UM 一旦为元素申请了内存后便不需要移动了。注意大负载中图表上夸张的跳步！这更确认了重新调整大小带来的问题。相反，UM 只是线性上升 —— 只需要重新调整 bucket 数组大小。由于没有太多隆起的地方，所以相对有效率。

**Presized fill**：

大致和 Fill 相似，但是图示结果更加的线性光滑，没有太大的跳步（因为不需要 rehash ），所有的实现差距在这一测试中要缩小了些。大负载时 UM 依然稍快于 Ch，问题还是在于重新调整大小上。Ch 仍是稳步少快于 OA 变种，但是 DO1 比其它的 OA 稍有优势。

**Lookup**：

所有的实现都相当的集中。除了最小负载时，DO1 和 OL 稍快，其余情况下 UM 和 DO2 都跑在了前面。（LCTT 译注： 你确定？）真的，我无法描述 UM 在这一步做的多么好。尽管需要遍历链表，但是 UM 还是坚守了面向数据的本性。

顺带一提，查找时间和 hash 表的大小有着很弱的关联，这真的很有意思。 哈希表查找时间期望上是一个常量时间，所以在的渐进视图中，性能不应该依赖于表的大小。但是那是在忽视了 cache 影响的情况下！作为具体的例子，当我们在具有 10 k 条目的表中做 100 k 次查找时，速度会便变快，因为在第一次 10 k - 20 k 次查找后，大部分的表会处在 L3 中。

**Failed lookup**：

相对于成功查找，这里就有点更分散一些。DO1 和 DO2 跑在了前面，但 UM 并没有落下，OL 则是捉襟见肘啊。我猜测，这可能是因为 OL 整体上具有更长的搜索路径，尤其是在失败查询时；内存中，hash 值在 key 和 value 之飘来荡去的找不着出路，我也很受伤啊。DO1 和 DO2 具有相同的搜索长度，但是它们将所有的 hash 值打包在内存中，这使得问题有所缓解。

**Remove**：

DO2 很显然是赢家，但 DO1 也未落下。Ch 则落后，UM 则是差的不是一丁半点（主要是因为每次移除都要释放内存）；差距随着负载的增加而拉大。移除操作是唯一不需要接触数据的操作，只需要 hash 值和 key 的帮助，这也是为什么 DO1 和 DO2 在移除操作中的表现大相径庭，而其它测试中却保持一致。（如果你的值不是 POD 类型的，并需要析构，这种差异应该是会消失的。）

**Destruct**：

Ch 除了最小负载，其它的情况都是最快的（最小负载时，约等于 OA 变种）。所有的 OA 变种基本都是相等的。注意，在我的 hash 表中所做的所有析构操作都是释放少量的内存 buffer 。但是 [在Windows中，释放内存的消耗和大小成比例关系](https://randomascii.wordpress.com/2014/12/10/hidden-costs-of-memory-allocation/)。（而且，这是一个很显著的开支 —— 申请 ～1 GB 的内存需要 ～100 ms 的时间去释放！）

UM 在析构时是最慢的一个（小负载时，慢的程度可以用数量级来衡量），大负载时依旧是稍慢些。对于 UM 来讲，释放每一个元素而不是释放一组数组真的是一个硬伤。

#### Linux

我还在装有 Linux Mint 17.1 的 Core i5-4570S 机器上使用 gcc 4.8 和 clang 3.5 来运行了测试。gcc 和 clang 的结果很相像，因此我只展示了 gcc 的；完整的结果集合包含在了代码下载打包文件中，链接在上面。

![Results for g++ 4.8, Linux Mint 17.1, Core i5-4570S](/data/attachment/album/201704/17/111621xgmkx05g5i4xm003.png "Results for g++ 4.8, Linux Mint 17.1, Core i5-4570S")

大部分结果和 Windows 很相似，因此我只高亮了一些有趣的不同点。

**Lookup**：

这里 DO1 跑在前头，而在 Windows 中 DO2 更快些。（LCTT 译注： 这里原文写错了吧？）同样，UM 和 Ch 落后于其它所有的实现——过多的指针追踪，然而 OA 只需要在内存中线性的移动即可。至于 Windows 和 Linux 结果为何不同，则不是很清楚。UM 同样比 Ch 慢了不少，特别是大负载时，这很奇怪；我期望的是它们可以基本相同。

**Failed lookup**：

UM 再一次落后于其它实现，甚至比 OL 还要慢。我再一次无法理解为何 UM 比 Ch 慢这么多，Linux 和 Windows 的结果为何有着如此大的差距。

**Destruct**：

在我的实现中，小负载的时候，析构的消耗太少了，以至于无法测量；在大负载中，线性增加的比例和创建的虚拟内存页数量相关，而不是申请到的数量？同样，要比 Windows 中的析构快上几个数量级。但是并不是所有的都和 hash 表有关；我们在这里可以看出不同系统和运行时内存系统的表现。貌似，Linux 释放大内存块是要比 Windows 快上不少（或者 Linux 很好的隐藏了开支，或许将释放工作推迟到了进程退出，又或者将工作推给了其它线程或者进程）。

UM 由于要释放每一个元素，所以在所有的负载中都比其它慢上几个数量级。事实上，我将图片做了剪裁，因为 UM 太慢了，以至于破坏了 Y 轴的比例。

### 总结

好，当我们凝视各种情况下的数据和矛盾的结果时，我们可以得出什么结果呢？我想直接了当的告诉你这些 hash 表变种中有一个打败了其它所有的 hash 表，但是这显然不那么简单。不过我们仍然可以学到一些东西。

首先，在大多数情况下我们“很容易”做的比 `std::unordered_map` 还要好。我为这些测试所写的所有实现（它们并不复杂；我只花了一两个小时就写完了）要么是符合 `unordered_map` 要么是在其基础上做的提高，除了大负载（超过128字节）中的插入性能， `unordered_map` 为每一个节点独立申请存储占了优势。（尽管我没有测试，我同样期望 `unordered_map` 能在非 POD 类型的负载上取得胜利。）具有指导意义的是，如果你非常关心性能，不要假设你的标准库中的数据结构是高度优化的。它们可能只是在 C++ 标准的一致性上做了优化，但不是性能。:P

其次，如果不管在小负载还是超负载中，若都只用 DO1 （开放寻址，线性探测，hashes/states 和 key/vaules分别处在隔离的普通数组中），那可能不会有啥好表现。这不是最快的插入，但也不坏（还比 `unordered_map` 快），并且在查找，移除，析构中也很快。你所知道的 —— “面向数据设计”完成了！

注意，我的为这些哈希表做的测试代码远未能用于生产环境——它们只支持 POD 类型，没有拷贝构造函数以及类似的东西，也未检测重复的 key，等等。我将可能尽快的构建一些实际的 hash 表，用于我的实用库中。为了覆盖基础部分，我想我将有两个变种：一个基于 DO1，用于小的，移动时不需要太大开支的负载；另一个用于链接并且避免重新申请和移动元素（就像 `unordered_map` ),用于大负载或者移动起来需要大开支的负载情况。这应该会给我带来最好的两个世界。

与此同时，我希望你们会有所启迪。最后记住，如果 Chandler Carruth 和 Mike Acton 在数据结构上给你提出些建议，你一定要听。

---

作者简介：

我是一名图形程序员，目前在西雅图做自由职业者。之前我在 NVIDIA 的 DevTech 软件团队中工作，并在美少女特工队工作室中为 PS3 和 PS4 的 Infamous 系列游戏开发渲染技术。

自 2002 年起，我对图形非常感兴趣，并且已经完成了一系列的工作，包括：雾、大气雾霾、体积照明、水、视觉效果、粒子系统、皮肤和头发阴影、后处理、镜面模型、线性空间渲染、和 GPU 性能测量和优化。

你可以在我的博客了解更多和我有关的事，除了图形，我还对理论物理和程序设计感兴趣。

你可以在 [nathaniel.reed@gmail.com](mailto:nathaniel.reed@gmail.com) 或者在 Twitter（@Reedbeta)/Google+ 上关注我。我也会经常在 StackExchange 上回答计算机图形的问题。

---

via: <http://reedbeta.com/blog/data-oriented-hash-table/>

作者：[Nathan Reed](http://reedbeta.com/about/) 译者：[sanfusu](https://github.com/sanfusu) 校对：[wxy](https://github.com/wxy)

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


调试器工作原理（一）：基础篇

Summary: 我将为大家展示 Linux 中调试器的主要构成模块 - ptrace 系统调用。这篇文章所有代码都是基于 32 位 Ubuntu 操作系统。值得注意的是，尽管这些代码是平台相关的，将它们移植到其它平台应该并不困难。

纯干货，希望能有后续

@有道云笔记收蔵

![](/data/attachment/album/201704/17/211733w083ii0mgwnyyi0d.jpg)

这是调试器工作原理系列文章的第一篇，我不确定这个系列会有多少篇文章，会涉及多少话题，但我仍会从这篇基础开始。

### 这一篇会讲什么

我将为大家展示 Linux 中调试器的主要构成模块 - `ptrace` 系统调用。这篇文章所有代码都是基于 32 位 Ubuntu 操作系统。值得注意的是，尽管这些代码是平台相关的，将它们移植到其它平台应该并不困难。

### 缘由

为了理解我们要做什么，让我们先考虑下调试器为了完成调试都需要什么资源。调试器可以开始一个进程并调试这个进程，又或者将自己同某个已经存在的进程关联起来。调试器能够单步执行代码，设定断点并且将程序执行到断点，检查变量的值并追踪堆栈。许多调试器有着更高级的特性，例如在调试器的地址空间内执行表达式或者调用函数，甚至可以在进程执行过程中改变代码并观察效果。

尽管现代的调试器都十分的复杂（我没有检查，但我确信 gdb 的代码行数至少有六位数），但它们的工作的原理却是十分的简单。调试器的基础是操作系统与编译器 / 链接器提供的一些基础服务，其余的部分只是[简单的编程](http://en.wikipedia.org/wiki/Small_matter_of_programming)而已。

### Linux 的调试 - ptrace

Linux 调试器中的瑞士军刀便是 `ptrace` 系统调用（使用 man 2 ptrace 命令可以了解更多）。这是一种复杂却强大的工具，可以允许一个进程控制另外一个进程并从<ruby> 内部替换 <rt>  Peek and poke </rt></ruby>被控制进程的内核镜像的值（Peek and poke 在系统编程中是很知名的叫法，指的是直接读写内存内容）。

接下来会深入分析。

### 执行进程的代码

我将编写一个示例，实现一个在“跟踪”模式下运行的进程。在这个模式下，我们将单步执行进程的代码，就像机器码（汇编代码）被 CPU 执行时一样。我将分段展示、讲解示例代码，在文章的末尾也有完整 c 文件的下载链接，你可以编译、执行或者随心所欲的更改。

更进一步的计划是实现一段代码，这段代码可以创建可执行用户自定义命令的子进程，同时父进程可以跟踪子进程。首先是主函数：

```
int main(int argc, char** argv)
{
    pid_t child_pid;

    if (argc < 2) {
        fprintf(stderr, "Expected a program name as argument\n");
        return -1;
    }

    child_pid = fork();
    if (child_pid == 0)
        run_target(argv[1]);
    else if (child_pid > 0)
        run_debugger(child_pid);
    else {
        perror("fork");
        return -1;
    }

    return 0;
}

```

看起来相当的简单：我们用 `fork` 创建了一个新的子进程（这篇文章假定读者有一定的 Unix/Linux 编程经验。我假定你知道或至少了解 fork、exec 族函数与 Unix 信号）。if 语句的分支执行子进程（这里称之为 “target”），`else if` 的分支执行父进程（这里称之为 “debugger”）。

下面是 target 进程的代码：

```
void run_target(const char* programname)
{
    procmsg("target started. will run '%s'\n", programname);

    /* Allow tracing of this process */
    if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
        perror("ptrace");
        return;
    }

    /* Replace this process's image with the given program */
    execl(programname, programname, 0);
}

```

这段代码中最值得注意的是 `ptrace` 调用。在 `sys/ptrace.h` 中，`ptrace` 是如下定义的：

```
long ptrace(enum __ptrace_request request, pid_t pid,
                 void *addr, void *data);

```

第一个参数是 `_request_`，这是许多预定义的 `PTRACE_*` 常量中的一个。第二个参数为请求分配进程 ID。第三个与第四个参数是地址与数据指针，用于操作内存。上面代码段中的 `ptrace` 调用发起了 `PTRACE_TRACEME` 请求，这意味着该子进程请求系统内核让其父进程跟踪自己。帮助页面上对于 request 的描述很清楚：

>
> 意味着该进程被其父进程跟踪。任何传递给该进程的信号（除了 `SIGKILL`）都将通过 `wait()` 方法阻塞该进程并通知其父进程。**此外，该进程的之后所有调用 `exec()` 动作都将导致 `SIGTRAP` 信号发送到此进程上，使得父进程在新的程序执行前得到取得控制权的机会**。如果一个进程并不需要它的的父进程跟踪它，那么这个进程不应该发送这个请求。（pid、addr 与 data 暂且不提）
>
>
>

我高亮了这个例子中我们需要注意的部分。在 `ptrace` 调用后，`run_target` 接下来要做的就是通过 `execl` 传参并调用。如同高亮部分所说明，这将导致系统内核在 `execl` 创建进程前暂时停止，并向父进程发送信号。

是时候看看父进程做什么了。

```
void run_debugger(pid_t child_pid)
{
    int wait_status;
    unsigned icounter = 0;
    procmsg("debugger started\n");

    /* Wait for child to stop on its first instruction */
    wait(&wait_status);

    while (WIFSTOPPED(wait_status)) {
        icounter++;
        /* Make the child execute another instruction */
        if (ptrace(PTRACE_SINGLESTEP, child_pid, 0, 0) < 0) {
            perror("ptrace");
            return;
        }

        /* Wait for child to stop on its next instruction */
        wait(&wait_status);
    }

    procmsg("the child executed %u instructions\n", icounter);
}

```

如前文所述，一旦子进程调用了 `exec`，子进程会停止并被发送 `SIGTRAP` 信号。父进程会等待该过程的发生并在第一个 `wait()` 处等待。一旦上述事件发生了，`wait()` 便会返回，由于子进程停止了父进程便会收到信号（如果子进程由于信号的发送停止了，`WIFSTOPPED` 就会返回 `true`）。

父进程接下来的动作就是整篇文章最需要关注的部分了。父进程会将 `PTRACE_SINGLESTEP` 与子进程 ID 作为参数调用 `ptrace` 方法。这就会告诉操作系统，“请恢复子进程，但在它执行下一条指令前阻塞”。周而复始地，父进程等待子进程阻塞，循环继续。当 `wait()` 中传出的信号不再是子进程的停止信号时，循环终止。在跟踪器（父进程）运行期间，这将会是被跟踪进程（子进程）传递给跟踪器的终止信号（如果子进程终止 `WIFEXITED` 将返回 `true`）。

`icounter` 存储了子进程执行指令的次数。这么看来我们小小的例子也完成了些有用的事情 - 在命令行中指定程序，它将执行该程序并记录它从开始到结束所需要的 cpu 指令数量。接下来就让我们这么做吧。

### 测试

我编译了下面这个简单的程序并利用跟踪器运行它：

```
#include <stdio.h>

int main()
{
    printf("Hello, world!\n");
    return 0;
}

```

令我惊讶的是，跟踪器花了相当长的时间，并报告整个执行过程共有超过 100,000 条指令执行。仅仅是一条输出语句？什么造成了这种情况？答案很有趣（至少你同我一样痴迷与机器/汇编语言）。Linux 的 gcc 默认会动态的将程序与 c 的运行时库动态地链接。这就意味着任何程序运行前的第一件事是需要动态库加载器去查找程序运行所需要的共享库。这些代码的数量很大 - 别忘了我们的跟踪器要跟踪每一条指令，不仅仅是主函数的，而是“整个进程中的指令”。

所以当我将测试程序使用静态编译时（通过比较，可执行文件会多出 500 KB 左右的大小，这部分是 C 运行时库的静态链接），跟踪器提示只有大概 7000 条指令被执行。这个数目仍然不小，但是考虑到在主函数执行前 libc 的初始化以及主函数执行后的清除代码，这个数目已经是相当不错了。此外，`printf` 也是一个复杂的函数。

仍然不满意的话，我需要的是“可以测试”的东西 - 例如可以完整记录每一个指令运行的程序执行过程。这当然可以通过汇编代码完成。所以我找到了这个版本的 “Hello, world!” 并编译了它。

```
section    .text
    ; The _start symbol must be declared for the linker (ld)
    global _start

_start:

    ; Prepare arguments for the sys_write system call:
    ;   - eax: system call number (sys_write)
    ;   - ebx: file descriptor (stdout)
    ;   - ecx: pointer to string
    ;   - edx: string length
    mov    edx, len
    mov    ecx, msg
    mov    ebx, 1
    mov    eax, 4

    ; Execute the sys_write system call
    int    0x80

    ; Execute sys_exit
    mov    eax, 1
    int    0x80

section   .data
msg db    'Hello, world!', 0xa
len equ    $ - msg

```

当然，现在跟踪器提示 7 条指令被执行了，这样一来很容易区分它们。

### 深入指令流

上面那个汇编语言编写的程序使得我可以向你介绍 `ptrace` 的另外一个强大的用途 - 详细显示被跟踪进程的状态。下面是 `run_debugger` 函数的另一个版本：

```
void run_debugger(pid_t child_pid)
{
    int wait_status;
    unsigned icounter = 0;
    procmsg("debugger started\n");

    /* Wait for child to stop on its first instruction */
    wait(&wait_status);

    while (WIFSTOPPED(wait_status)) {
        icounter++;
        struct user_regs_struct regs;
        ptrace(PTRACE_GETREGS, child_pid, 0, &regs);
        unsigned instr = ptrace(PTRACE_PEEKTEXT, child_pid, regs.eip, 0);

        procmsg("icounter = %u.  EIP = 0x%08x.  instr = 0x%08x\n",
                    icounter, regs.eip, instr);

        /* Make the child execute another instruction */
        if (ptrace(PTRACE_SINGLESTEP, child_pid, 0, 0) < 0) {
            perror("ptrace");
            return;
        }

        /* Wait for child to stop on its next instruction */
        wait(&wait_status);
    }

    procmsg("the child executed %u instructions\n", icounter);
}

```

不同仅仅存在于 `while` 循环的开始几行。这个版本里增加了两个新的 `ptrace` 调用。第一条将进程的寄存器值读取进了一个结构体中。 `sys/user.h` 定义有 `user_regs_struct`。如果你查看头文件，头部的注释这么写到：

```
/* 这个文件只为了 GDB 而创建
   不用详细的阅读.如果你不知道你在干嘛，
   不要在除了 GDB 以外的任何地方使用此文件  */

```

不知道你做何感想，但这让我觉得我们找对地方了。回到例子中，一旦我们在 `regs` 变量中取得了寄存器的值，我们就可以通过将 `PTRACE_PEEKTEXT` 作为参数、 `regs.eip`（x86 上的扩展指令指针）作为地址，调用 `ptrace` ，读取当前进程的当前指令（警告：如同我上面所说，文章很大程度上是平台相关的。我简化了一些设定 - 例如，x86 指令集不需要调整到 4 字节，我的32位 Ubuntu unsigned int 是 4 字节。事实上，许多平台都不需要。从内存中读取指令需要预先安装完整的反汇编器。我们这里没有，但实际的调试器是有的）。下面是新跟踪器所展示出的调试效果：

```
$ simple_tracer traced_helloworld
[5700] debugger started
[5701] target started. will run 'traced_helloworld'
[5700] icounter = 1\.  EIP = 0x08048080\.  instr = 0x00000eba
[5700] icounter = 2\.  EIP = 0x08048085\.  instr = 0x0490a0b9
[5700] icounter = 3\.  EIP = 0x0804808a.  instr = 0x000001bb
[5700] icounter = 4\.  EIP = 0x0804808f.  instr = 0x000004b8
[5700] icounter = 5\.  EIP = 0x08048094\.  instr = 0x01b880cd
Hello, world!
[5700] icounter = 6\.  EIP = 0x08048096\.  instr = 0x000001b8
[5700] icounter = 7\.  EIP = 0x0804809b.  instr = 0x000080cd
[5700] the child executed 7 instructions

```

现在，除了 `icounter`，我们也可以观察到指令指针与它每一步所指向的指令。怎么来判断这个结果对不对呢？使用 `objdump -d` 处理可执行文件：

```
$ objdump -d traced_helloworld

traced_helloworld:     file format elf32-i386

Disassembly of section .text:

08048080 <.text>:
 8048080:     ba 0e 00 00 00          mov    $0xe,%edx
 8048085:     b9 a0 90 04 08          mov    $0x80490a0,%ecx
 804808a:     bb 01 00 00 00          mov    $0x1,%ebx
 804808f:     b8 04 00 00 00          mov    $0x4,%eax
 8048094:     cd 80                   int    $0x80
 8048096:     b8 01 00 00 00          mov    $0x1,%eax
 804809b:     cd 80                   int    $0x80

```

这个结果和我们跟踪器的结果就很容易比较了。

### 　将跟踪器关联到正在运行的进程

如你所知，调试器也能关联到已经运行的进程。现在你应该不会惊讶，`ptrace` 通过以 `PTRACE_ATTACH` 为参数调用也可以完成这个过程。这里我不会展示示例代码，通过上文的示例代码应该很容易实现这个过程。出于学习目的，这里使用的方法更简便（因为我们在子进程刚开始就可以让它停止）。

### 代码

上文中的简单的跟踪器（更高级的，可以打印指令的版本）的完整c源代码可以在[这里](https://github.com/eliben/code-for-blog/blob/master/2011/simple_tracer.c)找到。它是通过 4.4 版本的 gcc 以 `-Wall -pedantic --std=c99` 编译的。

### 结论与计划

诚然，这篇文章并没有涉及很多内容 - 我们距离亲手完成一个实际的调试器还有很长的路要走。但我希望这篇文章至少可以使得调试这件事少一些神秘感。`ptrace` 是功能多样的系统调用，我们目前只展示了其中的一小部分。

单步调试代码很有用，但也只是在一定程度上有用。上面我通过 C 的 “Hello World!” 做了示例。为了执行主函数，可能需要上万行代码来初始化 C 的运行环境。这并不是很方便。最理想的是在 `main` 函数入口处放置断点并从断点处开始分步执行。为此，在这个系列的下一篇，我打算展示怎么实现断点。

### 参考

撰写此文时参考了如下文章：

* [Playing with ptrace, Part I](http://www.linuxjournal.com/article/6100?page=0,1)
* [How debugger works](http://www.alexonlinux.com/how-debugger-works)

---

via: <http://eli.thegreenplace.net/2011/01/23/how-debuggers-work-part-1>

作者：[Eli Bendersky](http://eli.thegreenplace.net/) 译者：[YYforymj](https://github.com/YYforymj) 校对：[wxy](https://github.com/wxy)

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