diff --git a/LCTT翻译规范.md b/LCTT翻译规范.md
deleted file mode 100644
index b9a514f115..0000000000
--- a/LCTT翻译规范.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# Linux中国翻译规范
-1. 翻译中出现的专有名词,可参见Dict.md中的翻译。
-2. 英文人名,如无中文对应译名,一般不译。
-2. 缩写词,一般不须翻译,可考虑旁注中文全名。
\ No newline at end of file
diff --git a/README.md b/README.md
index f1e0cec6c1..d3599e2b5c 100644
--- a/README.md
+++ b/README.md
@@ -15,30 +15,26 @@
LCTT 已经拥有几百名活跃成员,并欢迎更多的 Linux 志愿者加入我们的团队。
-
+
-LCTT 的组成
--------------------------------
-
-**选题**,负责选择合适的内容,并将原文转换为 markdown 格式,提交到 LCTT 的 [TranslateProject](https://github.com/LCTT/TranslateProject) 库中。
-
-**译者**,负责从选题中选择内容进行翻译。
-
-**校对**,负责将初译的文章进行文字润色、技术校对等工作。
-
-**发布**,负责将校对后的文章,排版进行发布。
+- LCTT 官网: [https://linux.cn/lctt/](https://linux.cn/lctt/)
+- LCTT 状态: [https://lctt.github.io/](https://lctt.github.io/)
加入我们
-------------------------------
-请首先加入翻译组的 QQ 群,群号是:**198889102**,加群时请说明是“*志愿者*”。加入后记得修改您的群名片为您的 GitHub 的 ID。
+请首先加入翻译组的 QQ 群,群号是:**198889102**,加群时请说明是“*志愿者*”。
-加入的成员,请先阅读 [WIKI 如何开始](https://github.com/LCTT/TranslateProject/wiki/01-如何开始)。
+加入的成员,请:
+
+1. 修改你的 QQ 群名片为“译者-您的_GitHub_ID”。
+2. 阅读 [WIKI](https://lctt.github.io/wiki) 了解如何开始。
+3. 遇到不解之处,请在群内发问。
如何开始
-------------------------------
-请阅读 [WIKI](https://github.com/LCTT/TranslateProject/wiki)。如需要协助,请在群内发问。
+请阅读 [WIKI](https://lctt.github.io/wiki)。如需要协助,请在群内发问。
历史
-------------------------------
diff --git a/published/201309/20190204 7 Best VPN Services For 2019.md b/published/201309/20190204 7 Best VPN Services For 2019.md
new file mode 100644
index 0000000000..2a1fe8c29a
--- /dev/null
+++ b/published/201309/20190204 7 Best VPN Services For 2019.md
@@ -0,0 +1,77 @@
+[#]: collector: (lujun9972)
+[#]: translator: (Modrisco)
+[#]: reviewer: (wxy)
+[#]: publisher: (wxy)
+[#]: url: (https://linux.cn/article-10691-1.html)
+[#]: subject: (7 Best VPN Services For 2019)
+[#]: via: (https://www.ostechnix.com/7-best-opensource-vpn-services-for-2019/)
+[#]: author: (Editor https://www.ostechnix.com/author/editor/)
+
+2019 年最好的 7 款虚拟私人网络服务
+======
+
+在过去三年中,全球至少有 67% 的企业面临着数据泄露,亿万用户受到影响。研究表明,如果事先对数据安全采取最基本的保护措施,那么预计有 93% 的安全问题是可以避免的。
+
+糟糕的数据安全会带来极大的代价,特别是对企业而言。它会大致大规模的破坏并影响你的品牌声誉。尽管有些企业可以艰难地收拾残局,但仍有一些企业无法从事故中完全恢复。不过现在,你很幸运地可以得到数据及网络安全软件。
+
+
+
+到了 2019 年,你可以通过**虚拟私人网络**,也就是我们熟知的 **VPN** 来保护你免受网络攻击。当涉及到在线隐私和安全时,常常存在许多不确定因素。有数百个不同的 VPN 提供商,选择合适的供应商也同时意味着在定价、服务和易用性之间谋取恰当的平衡。
+
+如果你正在寻找一个可靠的 100% 经过测试和安全的 VPN,你可能需要进行详尽的调查并作出最佳选择。这里为你提供在 2019 年 7 款最好用并经过测试的 VPN 服务。
+
+### 1、Vpnunlimitedapp
+
+通过 VPN Unlimited,你的数据安全将得到全面的保障。此 VPN 允许你连接任何 WiFi ,而无需担心你的个人数据可能被泄露。你的数据通过 AES-256 算法加密,保护你不受第三方和黑客的窥探。无论你身处何处,这款 VPN 都可确保你在所有网站上保持匿名且不受跟踪。它提供 7 天的免费试用和多种协议支持:openvpn、IKEv2 和 KeepSolidWise。有特殊需求的用户会获得特殊的额外服务,如个人服务器、终身 VPN 订阅和个人 IP 选项。
+
+### 2、VPN Lite
+
+VPN Lite 是一款易于使用而且**免费**的用于上网的 VPN 服务。你可以通过它在网络上保持匿名并保护你的个人隐私。它会模糊你的 IP 并加密你的数据,这意味着第三方无法跟踪你的所有线上活动。你还可以访问网络上的全部内容。使用 VPN Lite,你可以访问在被拦截的网站。你还放心地可以访问公共 WiFi 而不必担心敏感信息被间谍软件窃取和来自黑客的跟踪和攻击。
+
+### 3、HotSpot Shield
+
+这是一款在 2005 年推出的大受欢迎的 VPN。这套 VPN 协议至少被全球 70% 的数据安全公司所集成,并在全球有数千台服务器。它提供两种免费模式:一种为完全免费,但会有线上广告;另一种则为七天试用。它提供军事级的数据加密和恶意软件防护。HotSpot Shield 保证网络安全并保证高速网络。
+
+### 4、TunnelBear
+
+如果你是一名 VPN 新手,那么 TunnelBear 将是你的最佳选择。它带有一个用户友好的界面,并配有动画熊引导。你可以在 TunnelBear 的帮助下以极快的速度连接至少 22 个国家的服务器。它使用 **AES 256-bit** 加密算法,保证无日志记录,这意味着你的数据将得到保护。你还可以在最多五台设备上获得无限流量。
+
+### 5、ProtonVPN
+
+这款 VPN 为你提供强大的优质服务。你的连接速度可能会受到影响,但你也可以享受到无限流量。它具有易于使用的用户界面,提供多平台兼容。 ProtonVPN 的服务据说是因为为种子下载提供了优化因而无法访问 Netflix。你可以获得如协议和加密等安全功能来保证你的网络安全。
+
+### 6、ExpressVPN
+
+ExpressVPN 被认为是最好的用于接触封锁和保护隐私的离岸 VPN。凭借强大的客户支持和快速的速度,它已成为全球顶尖的 VPN 服务。它提供带有浏览器扩展和自定义固件的路由。 ExpressVPN 拥有一系列令人赞叹高质量应用程序,配有大量的服务器,并且最多只能支持三台设备。
+
+ExpressVPN 并不是完全免费的,恰恰相反,正是由于它所提供的高质量服务而使之成为了市场上最贵的 VPN 之一。ExpressVPN 有 30 天内退款保证,因此你可以免费试用一个月。好消息是,这是完全没有风险的。例如,如果你在短时间内需要 VPN 来绕过在线审查,这可能是你的首选解决方案。用过它之后,你就不会随意想给一个会发送垃圾邮件、缓慢的免费的程序当成试验品。
+
+ExpressVPN 也是享受在线流媒体和户外安全的最佳方式之一。如果你需要继续使用它,你只需要续订或取消你的免费试用。ExpressVPN 在 90 多个国家架设有 2000 多台服务器,可以解锁 Netflix,提供快速连接,并为用户提供完全隐私。
+
+### 7、PureVPN
+
+虽然 PureVPN 可能不是完全免费的,但它却是此列表中最实惠的一个。用户可以注册获得 7 天的免费试用,并在之后选择任一付费计划。通过这款 VPN,你可以访问到至少 140 个国家中的 750 余台服务器。它还可以在几乎所有设备上轻松安装。它的所有付费特性仍然可以在免费试用期间使用。包括无限数据流量、IP 泄漏保护和 ISP 不可见性。它支持的系统有 iOS、Android、Windows、Linux 和 macOS。
+
+### 总结
+
+如今,可用的免费 VPN 服务越来越多,为什么不抓住这个机会来保护你自己和你的客户呢?在了解到有那么多优秀的 VPN 服务后,我们知道即使是最安全的免费服务也不一定就完全没有风险。你可能需要付费升级到高级版以增强保护。高级版的 VPN 为你提供了免费试用,提供无风险退款保证。无论你打算花钱购买 VPN 还是准备使用免费 VPN,我们都强烈建议你使用一个。
+
+**关于作者:**
+
+**Renetta K. Molina** 是一个技术爱好者和健身爱好者。她撰写有关技术、应用程序、 WordPress 和其他任何领域的文章。她喜欢在空余时间打高尔夫球和读书。她喜欢学习和尝试新事物。
+
+
+
+--------------------------------------------------------------------------------
+
+via: https://www.ostechnix.com/7-best-opensource-vpn-services-for-2019/
+
+作者:[Editor][a]
+选题:[lujun9972][b]
+译者:[Modrisco](https://github.com/Modrisco)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]: https://www.ostechnix.com/author/editor/
+[b]: https://github.com/lujun9972
diff --git a/published/20150616 Computer Laboratory - Raspberry Pi- Lesson 10 Input01.md b/published/20150616 Computer Laboratory - Raspberry Pi- Lesson 10 Input01.md
new file mode 100644
index 0000000000..78864f5145
--- /dev/null
+++ b/published/20150616 Computer Laboratory - Raspberry Pi- Lesson 10 Input01.md
@@ -0,0 +1,482 @@
+[#]: collector: (lujun9972)
+[#]: translator: (ezio)
+[#]: reviewer: (wxy)
+[#]: publisher: (wxy)
+[#]: url: (https://linux.cn/article-10676-1.html)
+[#]: subject: (Computer Laboratory – Raspberry Pi: Lesson 10 Input01)
+[#]: via: (https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/input01.html)
+[#]: author: (Alex Chadwick https://www.cl.cam.ac.uk)
+
+计算机实验室之树莓派:课程 10 输入01
+======
+
+欢迎进入输入课程系列。在本系列,你将会学会如何使用键盘接收输入给树莓派。我们将会从揭示输入开始本课,然后转向更传统的文本提示符。
+
+这是第一堂输入课,会教授一些关于驱动和链接的理论,同样也包含键盘的知识,最后以在屏幕上显示文本结束。
+
+### 1、开始
+
+希望你已经完成了 OK 系列课程,这会对你完成屏幕系列课程很有帮助。很多 OK 课程上的文件会被使用而不会做解释。如果你没有这些文件,或者希望使用一个正确的实现,可以从该堂课的[下载页][1]下载模板。如果你使用你自己的实现,请删除调用了 `SetGraphicsAddress` 之后全部的代码。
+
+### 2、USB
+
+如你所知,树莓派 B 型有两个 USB 接口,通常用来连接一个鼠标和一个键盘。这是一个非常好的设计决策,USB 是一个非常通用的接口,很多种设备都可以使用它。这就很容易为它设计新外设,很容易为它编写设备驱动,而且通过 USB 集线器可以非常容易扩展。还能更好吗?当然是不能,实际上对一个操作系统开发者来说,这就是我们的噩梦。USB 标准太大了。我是说真的,在你思考如何连接设备之前,它的文档将近 700 页。
+
+> USB 标准的设计目的是通过复杂的软件来简化硬件交互。
+
+我和很多爱好操作系统的开发者谈过这些,而他们全部都说几句话:不要抱怨。“实现这个需要花费很久时间”,“你不可能写出关于 USB 的教程”,“收益太小了”。在很多方面,他们是对的,我不可能写出一个关于 USB 标准的教程,那得花费几周时间。我同样不能教授如何为全部所有的设备编写外设驱动,所以使用自己写的驱动是没什么用的。然而,即便不能做到最好,我仍然可以获取一个正常工作的 USB 驱动,拿一个键盘驱动,然后教授如何在操作系统中使用它们。我开始寻找可以运行在一个甚至不知道文件是什么的操作系统的自由驱动,但是我一个都找不到,它们都太高层了,所以我尝试写一个。大家说的都对,这耗费了我几周时间。然而我可以高兴的说我做的这些工作没有获取操作系统以外的帮助,并且可以和鼠标和键盘通信。这绝不是完整的、高效的,或者正确的,但是它能工作。驱动是以 C 编写的,而且有兴趣的可以在下载页找到全部源代码。
+
+所以,这一个教程不会是 USB 标准的课程(一点也没有)。实际上我们将会看到如何使用其他人的代码。
+
+### 3、链接
+
+既然我们要引进外部代码到操作系统,我们就需要谈一谈链接。链接是一种过程,可以在程序或者操作系统中链接函数。这意味着当一个程序生成之后,我们不必要编写每一个函数(几乎可以肯定,实际上并非如此)。链接就是我们做的用来把我们程序和别人代码中的函数连结在一起。这个实际上已经在我们的操作系统进行了,因为链接器把所有不同的文件链接在一起,每个都是分开编译的。
+
+> 链接允许我们制作可重用的代码库,所有人都可以在他们的程序中使用。
+
+有两种链接方式:静态和动态。静态链接就像我们在制作自己的操作系统时进行的。链接器找到全部函数的地址,然后在链接结束前,将这些地址都写入代码中。动态链接是在程序“完成”之后。当程序加载后,动态链接器检查程序,然后在操作系统的库找到所有不在程序里的函数。这就是我们的操作系统最终应该能够完成的一项工作,但是现在所有东西都将是静态链接的。
+
+> 程序经常调用调用库,这些库会调用其它的库,直到最终调用了我们写的操作系统的库。
+
+我编写的 USB 驱动程序适合静态编译。这意味着我给你的是每个文件的编译后的代码,然后链接器找到你的代码中的那些没有实现的函数,就将这些函数链接到我的代码。在本课的 [下载页][1] 是一个 makefile 和我的 USB 驱动,这是接下来需要的。下载并使用这个 makefile 替换你的代码中的 makefile, 同事将驱动放在和这个 makefile 相同的文件夹。
+
+### 4、键盘
+
+为了将输入传给我们的操作系统,我们需要在某种程度上理解键盘是如何实际工作的。键盘有两种按键:普通键和修饰键。普通按键是字母、数字、功能键,等等。它们构成了键盘上几乎全部按键。修饰键是多达 8 个的特殊键。它们是左 shift、右 shift、左 ctrl、右 ctrl、左 alt、右 alt、左 GUI 和右 GUI。键盘可以检测出所有的组合中那个修饰键被按下了,以及最多 6 个普通键。每次一个按钮变化了(例如,是按下了还是释放了),键盘就会报告给电脑。通常,键盘也会有 3 个 LED 灯,分别指示大写锁定,数字键锁定,和滚动锁定,这些都是由电脑控制的,而不是键盘自己。键盘也可能有更多的灯,比如电源、静音,等等。
+
+对于标准 USB 键盘,有一个按键值的表,每个键盘按键都一个唯一的数字,每个可能的 LED 也类似。下面的表格列出了前 126 个值。
+
+表 4.1 USB 键盘值
+
+| 序号 | 描述 | 序号 | 描述 | 序号 | 描述 | 序号 | 描述 |
+| ------ | ---------------------- | ------ | -------------------- | ----------- | ----------------------- | -------- | ---------------------- |
+| 4 | `a` 和 `A` | 5 | `b` 和 `B` | 6 | `c` 和 `C` | 7 | `d` 和 `D` |
+| 8 | `e` 和 `E` | 9 | `f` 和 `F` | 10 | `g` 和 `G` | 11 | `h` 和 `H` |
+| 12 | `i` 和 `I` | 13 | `j` 和 `J` | 14 | `k` 和 `K` | 15 | `l` 和 `L` |
+| 16 | `m` 和 `M` | 17 | `n` 和 `N` | 18 | `o` 和 `O` | 19 | `p` 和 `P` |
+| 20 | `q` 和 `Q` | 21 | `r` 和 `R` | 22 | `s` 和 `S` | 23 | `t` 和 `T` |
+| 24 | `u` 和 `U` | 25 | `v` 和 `V` | 26 | `w` 和 `W` | 27 | `x` 和 `X` |
+| 28 | `y` 和 `Y` | 29 | `z` 和 `Z` | 30 | `1` 和 `!` | 31 | `2` 和 `@` |
+| 32 | `3` 和 `#` | 33 | `4` 和 `$` | 34 | `5` 和 `%` | 35 | `6` 和 `^` |
+| 36 | `7` 和 `&` | 37 | `8` 和 `*` | 38 | `9` 和 `(` | 39 | `0` 和 `)` |
+| 40 | `Return`(`Enter`) | 41 | `Escape` | 42 | `Delete`(`Backspace`) | 43 | `Tab` |
+| 44 | `Spacebar` | 45 | `-` 和 `_` | 46 | `=` 和 `+` | 47 | `[` 和 `{` |
+| 48 | `]` 和 `}` | 49 | `\` 和 `|` | 50 | `#` 和 `~` | 51 | `;` 和 `:` |
+| 52 | `'` 和 `"` | 53 | \` 和 `~` | 54 | `,` 和 `<` | 55 | `.` 和 `>` |
+| 56 | `/` 和 `?` | 57 | `Caps Lock` | 58 | `F1` | 59 | `F2` |
+| 60 | `F3` | 61 | `F4` | 62 | `F5` | 63 | `F6` |
+| 64 | `F7` | 65 | `F8` | 66 | `F9` | 67 | `F10` |
+| 68 | `F11` | 69 | `F12` | 70 | `Print Screen` | 71 | `Scroll Lock` |
+| 72 | `Pause` | 73 | `Insert` | 74 | `Home` | 75 | `Page Up` |
+| 76 | `Delete forward` | 77 | `End` | 78 | `Page Down` | 79 | `Right Arrow` |
+| 80 | `Left Arrow` | 81 | `Down Arrow` | 82 | `Up Arrow` | 83 | `Num Lock` |
+| 84 | 小键盘 `/` | 85 | 小键盘 `*` | 86 | 小键盘 `-` | 87 | 小键盘 `+` |
+| 88 | 小键盘 `Enter` | 89 | 小键盘 `1` 和 `End` | 90 | 小键盘 `2` 和 `Down Arrow` | 91 | 小键盘 `3` 和 `Page Down` |
+| 92 | 小键盘 `4` 和 `Left Arrow` | 93 | 小键盘 `5` | 94 | 小键盘 `6` 和 `Right Arrow` | 95 | 小键盘 `7` 和 `Home` |
+| 96 | 小键盘 `8` 和 `Up Arrow` | 97 | 小键盘 `9` 和 `Page Up` | 98 | 小键盘 `0` 和 `Insert` | 99 | 小键盘 `.` 和 `Delete` |
+| 100 | `\` 和 `|` | 101 | `Application` | 102 | `Power` | 103 | 小键盘 `=` |
+| 104 | `F13` | 105 | `F14` | 106 | `F15` | 107 | `F16` |
+| 108 | `F17` | 109 | `F18` | 110 | `F19` | 111 | `F20` |
+| 112 | `F21` | 113 | `F22` | 114 | `F23` | 115 | `F24` |
+| 116 | `Execute` | 117 | `Help` | 118 | `Menu` | 119 | `Select` |
+| 120 | `Stop` | 121 | `Again` | 122 | `Undo` | 123 | `Cut` |
+| 124 | `Copy` | 125 | `Paste` | 126 | `Find` | 127 | `Mute` |
+| 128 | `Volume Up` | 129 | `Volume Down` | | | | |
+
+完全列表可以在[HID 页表 1.12][2]的 53 页,第 10 节找到。
+
+### 5、车轮后的螺母
+
+通常,当你使用其他人的代码,他们会提供一份自己代码的总结,描述代码都做了什么,粗略介绍了是如何工作的,以及什么情况下会出错。下面是一个使用我的 USB 驱动的相关步骤要求。
+
+> 这些总结和代码的描述组成了一个 API - 应用程序产品接口。
+
+表 5.1 CSUD 中和键盘相关的函数
+
+| 函数 | 参数 | 返回值 | 描述 |
+| ----------------------- | ----------------------- | ----------------------- | -----------------------|
+| `UsbInitialise` | 无 | `r0` 是结果码 | 这个方法是一个集多种功能于一身的方法,它加载 USB 驱动程序,枚举所有设备并尝试与它们通信。这种方法通常需要大约一秒钟的时间来执行,但是如果插入几个 USB 集线器,执行时间会明显更长。在此方法完成之后,键盘驱动程序中的方法就可用了,不管是否确实插入了键盘。返回代码如下解释。|
+| `UsbCheckForChange` | 无 | 无 | 本质上提供与 `UsbInitialise` 相同的效果,但不提供相同的一次初始化。该方法递归地检查每个连接的集线器上的每个端口,如果已经添加了新设备,则添加它们。如果没有更改,这应该是非常快的,但是如果连接了多个设备的集线器,则可能需要几秒钟的时间。|
+| `KeyboardCount` | 无 | `r0` 是计数 | 返回当前连接并检测到的键盘数量。`UsbCheckForChange` 可能会对此进行更新。默认情况下最多支持 4 个键盘。可以通过这个驱动程序访问多达这么多的键盘。|
+| `KeyboardGetAddress` | `r0` 是索引 | `r0` 是地址 | 检索给定键盘的地址。所有其他函数都需要一个键盘地址,以便知道要访问哪个键盘。因此,要与键盘通信,首先要检查计数,然后检索地址,然后使用其他方法。注意,在调用 `UsbCheckForChange` 之后,此方法返回的键盘顺序可能会改变。|
+| `KeyboardPoll` | `r0` 是地址 | `r0` 是结果码 | 从键盘读取当前键状态。这是通过直接轮询设备来操作的,与最佳实践相反。这意味着,如果没有频繁地调用此方法,可能会错过一个按键。所有读取方法只返回上次轮询时的值。|
+| `KeyboardGetModifiers` | `r0` 是地址 | `r0` 是修饰键状态 | 检索上次轮询时修饰键的状态。这是两边的 `shift` 键、`alt` 键和 `GUI` 键。这回作为一个位字段返回,这样,位 0 中的 1 表示左控件被保留,位 1 表示左 `shift`,位 2 表示左 `alt` ,位 3 表示左 `GUI`,位 4 到 7 表示前面几个键的右版本。如果有问题,`r0` 包含 0。|
+| `KeyboardGetKeyDownCount` | `r0` 是地址 | `r0` 是计数 | 检索当前按下键盘的键数。这排除了修饰键。这通常不能超过 6。如果有错误,这个方法返回 0。|
+| `KeyboardGetKeyDown` | `r0` 是地址,`r1` 键号 | `r0` 是扫描码 | 检索特定按下键的扫描码(见表 4.1)。通常,要计算出哪些键是按下的,可以调用 `KeyboardGetKeyDownCount`,然后多次调用 `KeyboardGetKeyDown` ,将 `r1` 的值递增,以确定哪些键是按下的。如果有问题,返回 0。可以(但不建议这样做)在不调用 `KeyboardGetKeyDownCount` 的情况下调用此方法将 0 解释为没有按下的键。注意,顺序或扫描代码可以随机更改(有些键盘按数字排序,有些键盘按时间排序,没有任何保证)。|
+| `KeyboardGetKeyIsDown` | `r0` 是地址,`r1` 扫描码 | `r0` 是状态 | 除了 `KeyboardGetKeyDown` 之外,还可以检查按下的键中是否有特定的扫描码。如果没有,返回 0;如果有,返回一个非零值。当检测特定的扫描码(例如寻找 `ctrl+c`)时更快。出错时,返回 0。|
+| `KeyboardGetLedSupport` | `r0` 是地址 | `r0` 是 LED | 检查特定键盘支持哪些 LED。第 0 位代表数字锁定,第 1 位代表大写锁定,第 2 位代表滚动锁定,第 3 位代表合成,第 4 位代表假名,第 5 位代表电源,第 6 位代表 Shift ,第 7 位代表静音。根据 USB 标准,这些 LED 都不是自动更新的(例如,当检测到大写锁定扫描代码时,必须手动设置大写锁定 LED)。|
+| `KeyboardSetLeds` | `r0` 是地址, `r1` 是 LED | `r0` 是结果码 | 试图打开/关闭键盘上指定的 LED 灯。查看下面的结果代码值。参见 `KeyboardGetLedSupport` 获取 LED 的值。|
+
+有几种方法返回“返回值”。这些都是 C 代码的老生常谈了,就是用数字代表函数调用发生了什么。通常情况, 0 总是代表操作成功。下面的是驱动用到的返回值。
+
+> 返回值是一种处理错误的简单方法,但是通常更优雅的解决途径会出现于更高层次的代码。
+
+表 5.2 - CSUD 返回值
+
+| 代码 | 描述 |
+| ---- | ----------------------------------------------------------------------- |
+| 0 | 方法成功完成。 |
+| -2 | 参数:函数调用了无效参数。 |
+| -4 | 设备:设备没有正确响应请求。 |
+| -5 | 不匹配:驱动不适用于这个请求或者设备。 |
+| -6 | 编译器:驱动没有正确编译,或者被破坏了。 |
+| -7 | 内存:驱动用尽了内存。 |
+| -8 | 超时:设备没有在预期的时间内响应请求。 |
+| -9 | 断开连接:被请求的设备断开连接,或者不能使用。 |
+
+驱动的通常用法如下:
+
+ 1. 调用 `UsbInitialise`
+ 2. 调用 `UsbCheckForChange`
+ 3. 调用 `KeyboardCount`
+ 4. 如果返回 0,重复步骤 2。
+ 5. 针对你支持的每个键盘:
+ 1. 调用 `KeyboardGetAddress`
+ 2. 调用 `KeybordGetKeyDownCount`
+ 3. 针对每个按下的按键:
+ 1. 检查它是否已经被按下了
+ 2. 保存按下的按键
+ 4. 针对每个保存的按键:
+ 3. 检查按键是否被释放了
+ 4. 如果释放了就删除
+ 6. 根据按下/释放的案件执行操作
+ 7. 重复步骤 2
+
+最后,你可以对键盘做所有你想做的任何事了,而这些方法应该允许你访问键盘的全部功能。在接下来的两节课,我们将会着眼于完成文本终端的输入部分,类似于大部分的命令行电脑,以及命令的解释。为了做这些,我们将需要在更有用的形式下得到一个键盘输入。你可能注意到我的驱动是(故意的)没有太大帮助,因为它并没有方法来判断是否一个按键刚刚按下或释放了,它只有方法来判断当前那个按键是按下的。这就意味着我们需要自己编写这些方法。
+
+### 6、可用更新
+
+首先,让我们实现一个 `KeyboardUpdate` 方法,检查第一个键盘,并使用轮询方法来获取当前的输入,以及保存最后一个输入来对比。然后我们可以使用这个数据和其它方法来将扫描码转换成按键。这个方法应该按照下面的说明准确操作:
+
+> 重复检查更新被称为“轮询”。这是针对驱动 IO 中断而言的,这种情况下设备在准备好后会发一个信号。
+
+ 1. 提取一个保存好的键盘地址(初始值为 0)。
+ 2. 如果不是 0 ,进入步骤 9.
+ 3. 调用 `UsbCheckForChange` 检测新键盘。
+ 4. 调用 `KeyboardCount` 检测有几个键盘在线。
+ 5. 如果返回 0,意味着没有键盘可以让我们操作,只能退出了。
+ 6. 调用 `KeyboardGetAddress` 参数是 0,获取第一个键盘的地址。
+ 7. 保存这个地址。
+ 8. 如果这个值是 0,那么退出,这里应该有些问题。
+ 9. 调用 `KeyboardGetKeyDown` 6 次,获取每次按键按下的值并保存。
+ 10. 调用 `KeyboardPoll`
+ 11. 如果返回值非 0,进入步骤 3。这里应该有些问题(比如键盘断开连接)。
+
+要保存上面提到的值,我们将需要下面 `.data` 段的值。
+
+```
+.section .data
+.align 2
+KeyboardAddress:
+.int 0
+KeyboardOldDown:
+.rept 6
+.hword 0
+.endr
+```
+
+```
+.hword num 直接将半字的常数插入文件。
+```
+
+```
+.rept num [commands] .endr 复制 `commands` 命令到输出 num 次。
+```
+
+试着自己实现这个方法。对此,我的实现如下:
+
+1、我们加载键盘的地址。
+
+```
+.section .text
+.globl KeyboardUpdate
+KeyboardUpdate:
+push {r4,r5,lr}
+
+kbd .req r4
+ldr r0,=KeyboardAddress
+ldr kbd,[r0]
+```
+
+2、如果地址非 0,就说明我们有一个键盘。调用 `UsbCheckForChanges` 慢,所以如果一切正常,我们要避免调用这个函数。
+
+```
+teq kbd,#0
+bne haveKeyboard$
+```
+
+3、如果我们一个键盘都没有,我们就必须检查新设备。
+
+```
+getKeyboard$:
+bl UsbCheckForChange
+```
+
+4、如果有新键盘添加,我们就会看到这个。
+
+```
+bl KeyboardCount
+```
+
+5、如果没有键盘,我们就没有键盘地址。
+
+```
+teq r0,#0
+ldreq r1,=KeyboardAddress
+streq r0,[r1]
+beq return$
+```
+
+6、让我们获取第一个键盘的地址。你可能想要支持更多键盘。
+
+```
+mov r0,#0
+bl KeyboardGetAddress
+```
+
+7、保存键盘地址。
+
+```
+ldr r1,=KeyboardAddress
+str r0,[r1]
+```
+
+8、如果我们没有键盘地址,这里就没有其它活要做了。
+
+```
+teq r0,#0
+beq return$
+mov kbd,r0
+```
+
+9、循环查询全部按键,在 `KeyboardOldDown` 保存下来。如果我们询问的太多了,返回 0 也是正确的。
+
+```
+saveKeys$:
+ mov r0,kbd
+ mov r1,r5
+ bl KeyboardGetKeyDown
+
+ ldr r1,=KeyboardOldDown
+ add r1,r5,lsl #1
+ strh r0,[r1]
+ add r5,#1
+ cmp r5,#6
+ blt saveKeys$
+```
+
+10、现在我们得到了新的按键。
+
+```
+mov r0,kbd
+bl KeyboardPoll
+```
+
+11、最后我们要检查 `KeyboardOldDown` 是否工作了。如果没工作,那么我们可能是断开连接了。
+
+```
+teq r0,#0
+bne getKeyboard$
+
+return$:
+pop {r4,r5,pc}
+.unreq kbd
+```
+
+有了我们新的 `KeyboardUpdate` 方法,检查输入变得简单,固定周期调用这个方法就行,而它甚至可以检查键盘是否断开连接,等等。这是一个有用的方法,因为我们实际的按键处理会根据条件不同而有所差别,所以能够用一个函数调以它的原始方式获取当前的输入是可行的。下一个方法我们希望它是 `KeyboardGetChar`,简单的返回下一个按下的按钮的 ASCII 字符,或者如果没有按键按下就返回 0。这可以扩展到支持如果它按下一个特定时间当做多次按下按键,也支持锁定键和修饰键。
+
+如果我们有一个 `KeyWasDown` 方法可以使这个方法有用起来,如果给定的扫描代码不在 `KeyboardOldDown` 值中,它只返回 0,否则返回一个非零值。你可以自己尝试一下。与往常一样,可以在下载页面找到解决方案。
+
+### 7、查找表
+
+`KeyboardGetChar` 方法如果写得不好,可能会非常复杂。有 100 多种扫描码,每种代码都有不同的效果,这取决于 shift 键或其他修饰符的存在与否。并不是所有的键都可以转换成一个字符。对于一些字符,多个键可以生成相同的字符。在有如此多可能性的情况下,一个有用的技巧是查找表。查找表与物理意义上的查找表非常相似,它是一个值及其结果的表。对于一些有限的函数,推导出答案的最简单方法就是预先计算每个答案,然后通过检索返回正确的答案。在这种情况下,我们可以在内存中建立一个序列的值,序列中第 n 个值就是扫描代码 n 的 ASCII 字符代码。这意味着如果一个键被按下,我们的方法只需要检测到,然后从表中检索它的值。此外,我们可以为当按住 shift 键时的值单独创建一个表,这样按下 shift 键就可以简单地换个我们用的表。
+
+> 在编程的许多领域,程序越大,速度越快。查找表很大,但是速度很快。有些问题可以通过查找表和普通函数的组合来解决。
+
+在 `.section .data` 命令之后,复制下面的表:
+
+```
+.align 3
+KeysNormal:
+ .byte 0x0, 0x0, 0x0, 0x0, 'a', 'b', 'c', 'd'
+ .byte 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'
+ .byte 'm', 'n', 'o', 'p', 'q', 'r', 's', 't'
+ .byte 'u', 'v', 'w', 'x', 'y', 'z', '1', '2'
+ .byte '3', '4', '5', '6', '7', '8', '9', '0'
+ .byte '\n', 0x0, '\b', '\t', ' ', '-', '=', '['
+ .byte ']', '\\\', '#', ';', '\'', '`', ',', '.'
+ .byte '/', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+ .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+ .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+ .byte 0x0, 0x0, 0x0, 0x0, '/', '*', '-', '+'
+ .byte '\n', '1', '2', '3', '4', '5', '6', '7'
+ .byte '8', '9', '0', '.', '\\\', 0x0, 0x0, '='
+
+.align 3
+KeysShift:
+ .byte 0x0, 0x0, 0x0, 0x0, 'A', 'B', 'C', 'D'
+ .byte 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L'
+ .byte 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'
+ .byte 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '"'
+ .byte '£', '$', '%', '^', '&', '*', '(', ')'
+ .byte '\n', 0x0, '\b', '\t', ' ', '_', '+', '{'
+ .byte '}', '|', '~', ':', '@', '¬', '<', '>'
+ .byte '?', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+ .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+ .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+ .byte 0x0, 0x0, 0x0, 0x0, '/', '*', '-', '+'
+ .byte '\n', '1', '2', '3', '4', '5', '6', '7'
+ .byte '8', '9', '0', '.', '|', 0x0, 0x0, '='
+```
+
+这些表直接将前 104 个扫描码映射到 ASCII 字符作为一个字节表。我们还有一个单独的表来描述 `shift` 键对这些扫描码的影响。我使用 ASCII `null` 字符(`0`)表示所有没有直接映射的 ASCII 键(例如功能键)。退格映射到 ASCII 退格字符(8 表示 `\b`),`enter` 映射到 ASCII 新行字符(10 表示 `\n`), `tab` 映射到 ASCII 水平制表符(9 表示 `\t`)。
+
+> `.byte num` 直接插入字节常量 num 到文件。
+
+.
+
+> 大部分的汇编器和编译器识别转义序列;如 `\t` 这样的字符序列会插入该特殊字符。
+
+`KeyboardGetChar` 方法需要做以下工作:
+
+ 1. 检查 `KeyboardAddress` 是否返回 `0`。如果是,则返回 0。
+ 2. 调用 `KeyboardGetKeyDown` 最多 6 次。每次:
+ 1. 如果按键是 0,跳出循环。
+ 2. 调用 `KeyWasDown`。 如果返回是,处理下一个按键。
+ 3. 如果扫描码超过 103,进入下一个按键。
+ 4. 调用 `KeyboardGetModifiers`
+ 5. 如果 `shift` 是被按着的,就加载 `KeysShift` 的地址,否则加载 `KeysNormal` 的地址。
+ 6. 从表中读出 ASCII 码值。
+ 7. 如果是 0,进行下一个按键,否则返回 ASCII 码值并退出。
+ 3. 返回 0。
+
+
+试着自己实现。我的实现展示在下面:
+
+1、简单的检查我们是否有键盘。
+
+```
+.globl KeyboardGetChar
+KeyboardGetChar:
+ldr r0,=KeyboardAddress
+ldr r1,[r0]
+teq r1,#0
+moveq r0,#0
+moveq pc,lr
+```
+
+2、`r5` 将会保存按键的索引,`r4` 保存键盘的地址。
+
+```
+push {r4,r5,r6,lr}
+kbd .req r4
+key .req r6
+mov r4,r1
+mov r5,#0
+keyLoop$:
+ mov r0,kbd
+ mov r1,r5
+ bl KeyboardGetKeyDown
+```
+
+2.1、 如果扫描码是 0,它要么意味着有错,要么说明没有更多按键了。
+
+```
+teq r0,#0
+beq keyLoopBreak$
+```
+
+2.2、如果按键已经按下了,那么他就没意义了,我们只想知道按下的按键。
+
+```
+mov key,r0
+bl KeyWasDown
+teq r0,#0
+bne keyLoopContinue$
+```
+
+
+2.3、如果一个按键有个超过 104 的扫描码,它将会超出我们的表,所以它是无关的按键。
+
+```
+cmp key,#104
+bge keyLoopContinue$
+```
+
+2.4、我们需要知道修饰键来推断字符。
+
+```
+mov r0,kbd
+bl KeyboardGetModifiers
+```
+
+5. 当将字符更改为其 shift 变体时,我们要同时检测左 `shift` 键和右 `shift` 键。记住,`tst` 指令计算的是逻辑和,然后将其与 0 进行比较,所以当且仅当移位位都为 0 时,它才等于 0。
+
+```
+tst r0,#0b00100010
+ldreq r0,=KeysNormal
+ldrne r0,=KeysShift
+```
+
+2.6、现在我们可以从查找表加载按键了。
+
+```
+ldrb r0,[r0,key]
+```
+
+2.7、如果查找码包含一个 0,我们必须继续。为了继续,我们要增加索引,并检查是否到 6 次了。
+
+```
+teq r0,#0
+bne keyboardGetCharReturn$
+keyLoopContinue$:
+add r5,#1
+cmp r5,#6
+blt keyLoop$
+```
+
+
+3、在这里我们返回我们的按键,如果我们到达 `keyLoopBreak$` ,然后我们就知道这里没有按键被握住,所以返回 0。
+
+```
+keyLoopBreak$:
+mov r0,#0
+keyboardGetCharReturn$:
+pop {r4,r5,r6,pc}
+.unreq kbd
+.unreq key
+```
+
+### 8、记事本操作系统
+
+现在我们有了 `KeyboardGetChar` 方法,可以创建一个操作系统,只打印出用户对着屏幕所写的内容。为了简单起见,我们将忽略所有非常规的键。在 `main.s`,删除 `bl SetGraphicsAddress` 之后的所有代码。调用 `UsbInitialise`,将 `r4` 和 `r5` 设置为 0,然后循环执行以下命令:
+
+ 1. 调用 `KeyboardUpdate`
+ 2. 调用 `KeyboardGetChar`
+ 3. 如果返回 0,跳转到步骤 1
+ 4. 复制 `r4` 和 `r5` 到 `r1` 和 `r2` ,然后调用 `DrawCharacter`
+ 5. 把 `r0` 加到 `r4`
+ 6. 如果 `r4` 是 1024,将 `r1` 加到 `r5`,然后设置 `r4` 为 0。
+ 7. 如果 `r5` 是 768,设置 `r5` 为0
+ 8. 跳转到步骤 1
+
+现在编译,然后在树莓派上测试。你几乎可以立即开始在屏幕上输入文本。如果没有工作,请参阅我们的故障排除页面。
+
+当它工作时,祝贺你,你已经实现了与计算机的接口。现在你应该开始意识到,你几乎已经拥有了一个原始的操作系统。现在,你可以与计算机交互、发出命令,并在屏幕上接收反馈。在下一篇教程[输入02][3]中,我们将研究如何生成一个全文本终端,用户在其中输入命令,然后计算机执行这些命令。
+
+--------------------------------------------------------------------------------
+
+via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/input01.html
+
+作者:[Alex Chadwick][a]
+选题:[lujun9972][b]
+译者:[ezio](https://github.com/oska874)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]: https://www.cl.cam.ac.uk
+[b]: https://github.com/lujun9972
+[1]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/downloads.html
+[2]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/downloads/hut1_12v2.pdf
+[3]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/input02.html
diff --git a/published/20150616 Computer Laboratory - Raspberry Pi- Lesson 11 Input02.md b/published/20150616 Computer Laboratory - Raspberry Pi- Lesson 11 Input02.md
new file mode 100644
index 0000000000..5c39f24424
--- /dev/null
+++ b/published/20150616 Computer Laboratory - Raspberry Pi- Lesson 11 Input02.md
@@ -0,0 +1,901 @@
+[#]: collector: (lujun9972)
+[#]: translator: (guevaraya)
+[#]: reviewer: (wxy)
+[#]: publisher: (wxy)
+[#]: url: (https://linux.cn/article-10700-1.html)
+[#]: subject: (Computer Laboratory – Raspberry Pi: Lesson 11 Input02)
+[#]: via: (https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/input02.html)
+[#]: author: (Alex Chadwick https://www.cl.cam.ac.uk)
+
+计算机实验室之树莓派:课程 11 输入02
+======
+
+课程输入 02 是以课程输入 01 为基础讲解的,通过一个简单的命令行实现用户的命令输入和计算机的处理和显示。本文假设你已经具备 [课程11:输入01][1] 的操作系统代码基础。
+
+### 1、终端
+
+几乎所有的操作系统都是以字符终端显示启动的。经典的黑底白字,通过键盘输入计算机要执行的命令,然后会提示你拼写错误,或者恰好得到你想要的执行结果。这种方法有两个主要优点:键盘和显示器可以提供简易、健壮的计算机交互机制,几乎所有的计算机系统都采用这个机制,这个也广泛被系统管理员应用。
+
+> 早期的计算一般是在一栋楼里的一个巨型计算机系统,它有很多可以输命令的'终端'。计算机依次执行不同来源的命令。
+
+让我们分析下真正想要哪些信息:
+
+1. 计算机打开后,显示欢迎信息
+2. 计算机启动后可以接受输入标志
+3. 用户从键盘输入带参数的命令
+4. 用户输入回车键或提交按钮
+5. 计算机解析命令后执行可用的命令
+6. 计算机显示命令的执行结果,过程信息
+7. 循环跳转到步骤 2
+
+这样的终端被定义为标准的输入输出设备。用于(显示)输入的屏幕和打印输出内容的屏幕是同一个(LCTT 译注:最早期的输出打印真是“打印”到打印机/电传机的,而用于输入的终端只是键盘,除非做了回显,否则输出终端是不会显示输入的字符的)。也就是说终端是对字符显示的一个抽象。字符显示中,单个字符是最小的单元,而不是像素。屏幕被划分成固定数量不同颜色的字符。我们可以在现有的屏幕代码基础上,先存储字符和对应的颜色,然后再用方法 `DrawCharacter` 把其推送到屏幕上。一旦我们需要字符显示,就只需要在屏幕上画出一行字符串。
+
+新建文件名为 `terminal.s`,如下:
+
+```
+.section .data
+.align 4
+terminalStart:
+.int terminalBuffer
+terminalStop:
+.int terminalBuffer
+terminalView:
+.int terminalBuffer
+terminalColour:
+.byte 0xf
+.align 8
+terminalBuffer:
+.rept 128*128
+.byte 0x7f
+.byte 0x0
+.endr
+terminalScreen:
+.rept 1024/8 core.md Dict.md lctt2014.md lctt2016.md lctt2018.md LICENSE published README.md scripts sources translated 768/16
+.byte 0x7f
+.byte 0x0
+.endr
+```
+
+这是文件终端的配置数据文件。我们有两个主要的存储变量:`terminalBuffer` 和 `terminalScreen`。`terminalBuffer` 保存所有显示过的字符。它保存 128 行字符文本(1 行包含 128 个字符)。每个字符有一个 ASCII 字符和颜色单元组成,初始值为 0x7f(ASCII 的删除字符)和 0(前景色和背景色为黑)。`terminalScreen` 保存当前屏幕显示的字符。它保存 128x48 个字符,与 `terminalBuffer` 初始化值一样。你可能会觉得我仅需要 `terminalScreen` 就够了,为什么还要`terminalBuffer`,其实有两个好处:
+
+ 1. 我们可以很容易看到字符串的变化,只需画出有变化的字符。
+ 2. 我们可以回滚终端显示的历史字符,也就是缓冲的字符(有限制)
+
+这种独特的技巧在低功耗系统里很常见。画屏是很耗时的操作,因此我们仅在不得已的时候才去执行这个操作。在这个系统里,我们可以任意改变 `terminalBuffer`,然后调用一个仅拷贝屏幕上字节变化的方法。也就是说我们不需要持续画出每个字符,这样可以节省一大段跨行文本的操作时间。
+
+> 你总是需要尝试去设计一个高效的系统,如果在很少变化的情况下这个系统会运行的更快。
+
+其他在 `.data` 段的值得含义如下:
+
+ * `terminalStart`
+ 写入到 `terminalBuffer` 的第一个字符
+ * `terminalStop`
+ 写入到 `terminalBuffer` 的最后一个字符
+ * `terminalView`
+ 表示当前屏幕的第一个字符,这样我们可以控制滚动屏幕
+ * `temrinalColour`
+ 即将被描画的字符颜色
+
+`terminalStart` 需要保存起来的原因是 `termainlBuffer` 是一个环状缓冲区。意思是当缓冲区变满时,末尾地方会回滚覆盖开始位置,这样最后一个字符变成了第一个字符。因此我们需要将 `terminalStart` 往前推进,这样我们知道我们已经占满它了。如何实现缓冲区检测:如果索引越界到缓冲区的末尾,就将索引指向缓冲区的开始位置。环状缓冲区是一个比较常见的存储大量数据的高明方法,往往这些数据的最近部分比较重要。它允许无限制的写入,只保证最近一些特定数据有效。这个常常用于信号处理和数据压缩算法。这样的情况,可以允许我们存储 128 行终端记录,超过128行也不会有问题。如果不是这样,当超过第 128 行时,我们需要把 127 行分别向前拷贝一次,这样很浪费时间。
+
+![显示 Hellow world 插入到大小为5的循环缓冲区的示意图。][2]
+
+> 环状缓冲区是**数据结构**一个例子。这是一个组织数据的思路,有时我们通过软件实现这种思路。
+
+之前已经提到过 `terminalColour` 几次了。你可以根据你的想法实现终端颜色,但这个文本终端有 16 个前景色和 16 个背景色(这里相当于有 16^2 = 256 种组合)。[CGA][3]终端的颜色定义如下:
+
+
+表格 1.1 - CGA 颜色编码
+
+| 序号 | 颜色 (R, G, B) |
+| ------ | ------------------------|
+| 0 | 黑 (0, 0, 0) |
+| 1 | 蓝 (0, 0, ⅔) |
+| 2 | 绿 (0, ⅔, 0) |
+| 3 | 青色 (0, ⅔, ⅔) |
+| 4 | 红色 (⅔, 0, 0) |
+| 5 | 品红 (⅔, 0, ⅔) |
+| 6 | 棕色 (⅔, ⅓, 0) |
+| 7 | 浅灰色 (⅔, ⅔, ⅔) |
+| 8 | 灰色 (⅓, ⅓, ⅓) |
+| 9 | 淡蓝色 (⅓, ⅓, 1) |
+| 10 | 淡绿色 (⅓, 1, ⅓) |
+| 11 | 淡青色 (⅓, 1, 1) |
+| 12 | 淡红色 (1, ⅓, ⅓) |
+| 13 | 浅品红 (1, ⅓, 1) |
+| 14 | 黄色 (1, 1, ⅓) |
+| 15 | 白色 (1, 1, 1) |
+
+我们将前景色保存到颜色的低字节,背景色保存到颜色高字节。除了棕色,其他这些颜色遵循一种模式如二进制的高位比特代表增加 ⅓ 到每个组件,其他比特代表增加 ⅔ 到各自组件。这样很容易进行 RGB 颜色转换。
+
+> 棕色作为替代色(黑黄色)既不吸引人也没有什么用处。
+
+我们需要一个方法从 `TerminalColour` 读取颜色编码的四个比特,然后用 16 比特等效参数调用 `SetForeColour`。尝试你自己实现。如果你感觉麻烦或者还没有完成屏幕系列课程,我们的实现如下:
+
+```
+.section .text
+TerminalColour:
+teq r0,#6
+ldreq r0,=0x02B5
+beq SetForeColour
+
+tst r0,#0b1000
+ldrne r1,=0x52AA
+moveq r1,#0
+tst r0,#0b0100
+addne r1,#0x15
+tst r0,#0b0010
+addne r1,#0x540
+tst r0,#0b0001
+addne r1,#0xA800
+mov r0,r1
+b SetForeColour
+```
+
+### 2、文本显示
+
+我们的终端第一个真正需要的方法是 `TerminalDisplay`,它用来把当前的数据从 `terminalBuffer`拷贝到 `terminalScreen` 和实际的屏幕。如上所述,这个方法必须是最小开销的操作,因为我们需要频繁调用它。它主要比较 `terminalBuffer` 与 `terminalDisplay` 的文本,然后只拷贝有差异的字节。请记住 `terminalBuffer` 是以环状缓冲区运行的,这种情况,就是从 `terminalView` 到 `terminalStop`,或者 128*48 个字符,要看哪个来的最快。如果我们遇到 `terminalStop`,我们将会假定在这之后的所有字符是 7f16 (ASCII 删除字符),颜色为 0(黑色前景色和背景色)。
+
+让我们看看必须要做的事情:
+
+ 1. 加载 `terminalView`、`terminalStop` 和 `terminalDisplay` 的地址。
+ 2. 对于每一行:
+ 1. 对于每一列:
+ 1. 如果 `terminalView` 不等于 `terminalStop`,根据 `terminalView` 加载当前字符和颜色
+ 2. 否则加载 0x7f 和颜色 0
+ 3. 从 `terminalDisplay` 加载当前的字符
+ 4. 如果字符和颜色相同,直接跳转到第 10 步
+ 5. 存储字符和颜色到 `terminalDisplay`
+ 6. 用 `r0` 作为背景色参数调用 `TerminalColour`
+ 7. 用 `r0 = 0x7f`(ASCII 删除字符,一个块)、 `r1 = x`、`r2 = y` 调用 `DrawCharacter`
+ 8. 用 `r0` 作为前景色参数调用 `TerminalColour`
+ 9. 用 `r0 = 字符`、`r1 = x`、`r2 = y` 调用 `DrawCharacter`
+ 10. 对位置参数 `terminalDisplay` 累加 2
+ 11. 如果 `terminalView` 不等于 `terminalStop`,`terminalView` 位置参数累加 2
+ 12. 如果 `terminalView` 位置已经是文件缓冲器的末尾,将它设置为缓冲区的开始位置
+ 13. x 坐标增加 8
+ 2. y 坐标增加 16
+
+尝试去自己实现吧。如果你遇到问题,我们的方案下面给出来了:
+
+1、我这里的变量有点乱。为了方便起见,我用 `taddr` 存储 `textBuffer` 的末尾位置。
+
+```
+.globl TerminalDisplay
+TerminalDisplay:
+push {r4,r5,r6,r7,r8,r9,r10,r11,lr}
+x .req r4
+y .req r5
+char .req r6
+col .req r7
+screen .req r8
+taddr .req r9
+view .req r10
+stop .req r11
+
+ldr taddr,=terminalStart
+ldr view,[taddr,#terminalView - terminalStart]
+ldr stop,[taddr,#terminalStop - terminalStart]
+add taddr,#terminalBuffer - terminalStart
+add taddr,#128*128*2
+mov screen,taddr
+```
+
+2、从 `yLoop` 开始运行。
+
+```
+mov y,#0
+yLoop$:
+```
+
+2.1、
+
+```
+mov x,#0
+xLoop$:
+```
+从 `xLoop` 开始运行。
+
+
+2.1.1、为了方便起见,我把字符和颜色同时加载到 `char` 变量了
+
+```
+teq view,stop
+ldrneh char,[view]
+```
+
+2.1.2、这行是对上面一行的补充说明:读取黑色的删除字符
+
+
+```
+moveq char,#0x7f
+```
+
+2.1.3、为了简便我把字符和颜色同时加载到 `col` 里。
+
+```
+ldrh col,[screen]
+```
+
+2.1.4、 现在我用 `teq` 指令检查是否有数据变化
+
+```
+teq col,char
+beq xLoopContinue$
+```
+
+2.1.5、我可以容易的保存当前值
+
+
+```
+strh char,[screen]
+```
+
+2.1.6、我用比特偏移指令 `lsr` 和 `and` 指令从切分 `char` 变量,将颜色放到 `col` 变量,字符放到 `char` 变量,然后再用比特偏移指令 `lsr` 获取背景色后调用 `TerminalColour` 。
+
+```
+lsr col,char,#8
+and char,#0x7f
+lsr r0,col,#4
+bl TerminalColour
+```
+
+2.1.7、写入一个彩色的删除字符
+
+```
+mov r0,#0x7f
+mov r1,x
+mov r2,y
+bl DrawCharacter
+```
+
+2.1.8、用 `and` 指令获取 `col` 变量的低半字节,然后调用 `TerminalColour`
+
+```
+and r0,col,#0xf
+bl TerminalColour
+```
+
+2.1.9、写入我们需要的字符
+
+```
+mov r0,char
+mov r1,x
+mov r2,y
+bl DrawCharacter
+```
+
+2.1.10、自增屏幕指针
+
+```
+xLoopContinue$:
+add screen,#2
+```
+
+2.1.11、如果可能自增 `view` 指针
+
+```
+teq view,stop
+addne view,#2
+```
+
+2.1.12、很容易检测 `view` 指针是否越界到缓冲区的末尾,因为缓冲区的地址保存在 `taddr` 变量里
+
+```
+teq view,taddr
+subeq view,#128*128*2
+```
+
+2.1.13、 如果还有字符需要显示,我们就需要自增 `x` 变量然后到 `xLoop` 循环执行
+
+```
+add x,#8
+teq x,#1024
+bne xLoop$
+```
+
+2.2、 如果还有更多的字符显示我们就需要自增 `y` 变量,然后到 `yLoop` 循环执行
+
+```
+add y,#16
+teq y,#768
+bne yLoop$
+```
+
+3、不要忘记最后清除变量
+
+```
+pop {r4,r5,r6,r7,r8,r9,r10,r11,pc}
+.unreq x
+.unreq y
+.unreq char
+.unreq col
+.unreq screen
+.unreq taddr
+.unreq view
+.unreq stop
+```
+
+### 3、行打印
+
+现在我有了自己 `TerminalDisplay` 方法,它可以自动显示 `terminalBuffer` 内容到 `terminalScreen`,因此理论上我们可以画出文本。但是实际上我们没有任何基于字符显示的例程。 首先快速容易上手的方法便是 `TerminalClear`, 它可以彻底清除终端。这个方法不用循环也很容易实现。可以尝试分析下面的方法应该不难:
+
+```
+.globl TerminalClear
+TerminalClear:
+ldr r0,=terminalStart
+add r1,r0,#terminalBuffer-terminalStart
+str r1,[r0]
+str r1,[r0,#terminalStop-terminalStart]
+str r1,[r0,#terminalView-terminalStart]
+mov pc,lr
+```
+
+现在我们需要构造一个字符显示的基础方法:`Print` 函数。它将保存在 `r0` 的字符串和保存在 `r1` 的字符串长度简单的写到屏幕上。有一些特定字符需要特别的注意,这些特定的操作是确保 `terminalView` 是最新的。我们来分析一下需要做什么:
+
+ 1. 检查字符串的长度是否为 0,如果是就直接返回
+ 2. 加载 `terminalStop` 和 `terminalView`
+ 3. 计算出 `terminalStop` 的 x 坐标
+ 4. 对每一个字符的操作:
+ 1. 检查字符是否为新起一行
+ 2. 如果是的话,自增 `bufferStop` 到行末,同时写入黑色删除字符
+ 3. 否则拷贝当前 `terminalColour` 的字符
+ 4. 检查是否在行末
+ 5. 如果是,检查从 `terminalView` 到 `terminalStop` 之间的字符数是否大于一屏
+ 6. 如果是,`terminalView` 自增一行
+ 7. 检查 `terminalView` 是否为缓冲区的末尾,如果是的话将其替换为缓冲区的起始位置
+ 8. 检查 `terminalStop` 是否为缓冲区的末尾,如果是的话将其替换为缓冲区的起始位置
+ 9. 检查 `terminalStop` 是否等于 `terminalStart`, 如果是的话 `terminalStart` 自增一行。
+ 10. 检查 `terminalStart` 是否为缓冲区的末尾,如果是的话将其替换为缓冲区的起始位置
+ 5. 存取 `terminalStop` 和 `terminalView`
+
+试一下自己去实现。我们的方案提供如下:
+
+1、这个是 `Print` 函数开始快速检查字符串为0的代码
+
+```
+.globl Print
+Print:
+teq r1,#0
+moveq pc,lr
+```
+
+2、这里我做了很多配置。 `bufferStart` 代表 `terminalStart`, `bufferStop` 代表`terminalStop`, `view` 代表 `terminalView`,`taddr` 代表 `terminalBuffer` 的末尾地址。
+
+```
+push {r4,r5,r6,r7,r8,r9,r10,r11,lr}
+bufferStart .req r4
+taddr .req r5
+x .req r6
+string .req r7
+length .req r8
+char .req r9
+bufferStop .req r10
+view .req r11
+
+mov string,r0
+mov length,r1
+
+ldr taddr,=terminalStart
+ldr bufferStop,[taddr,#terminalStop-terminalStart]
+ldr view,[taddr,#terminalView-terminalStart]
+ldr bufferStart,[taddr]
+add taddr,#terminalBuffer-terminalStart
+add taddr,#128*128*2
+```
+
+3、和通常一样,巧妙的对齐技巧让许多事情更容易。由于需要对齐 `terminalBuffer`,每个字符的 x 坐标需要 8 位要除以 2。
+
+
+```
+and x,bufferStop,#0xfe
+lsr x,#1
+```
+
+4.1、我们需要检查新行
+
+```
+charLoop$:
+ldrb char,[string]
+and char,#0x7f
+teq char,#'\n'
+bne charNormal$
+```
+
+4.2、循环执行值到行末写入 0x7f;黑色删除字符
+
+```
+mov r0,#0x7f
+clearLine$:
+strh r0,[bufferStop]
+add bufferStop,#2
+add x,#1
+teq x,#128 blt clearLine$
+
+b charLoopContinue$
+```
+
+4.3、存储字符串的当前字符和 `terminalBuffer` 末尾的 `terminalColour` 然后将它和 x 变量自增
+
+```
+charNormal$:
+strb char,[bufferStop]
+ldr r0,=terminalColour
+ldrb r0,[r0]
+strb r0,[bufferStop,#1]
+add bufferStop,#2
+add x,#1
+```
+
+4.4、检查 x 是否为行末;128
+
+
+```
+charLoopContinue$:
+cmp x,#128
+blt noScroll$
+```
+
+4.5、设置 x 为 0 然后检查我们是否已经显示超过 1 屏。请记住,我们是用的循环缓冲区,因此如果 `bufferStop` 和 `view` 之前的差是负值,我们实际上是环绕了缓冲区。
+
+```
+mov x,#0
+subs r0,bufferStop,view
+addlt r0,#128*128*2
+cmp r0,#128*(768/16)*2
+```
+
+4.6、增加一行字节到 `view` 的地址
+
+```
+addge view,#128*2
+```
+
+4.7、 如果 `view` 地址是缓冲区的末尾,我们就从它上面减去缓冲区的长度,让其指向开始位置。我会在开始的时候设置 `taddr` 为缓冲区的末尾地址。
+
+```
+teq view,taddr
+subeq view,taddr,#128*128*2
+```
+
+4.8、如果 `stop` 的地址在缓冲区末尾,我们就从它上面减去缓冲区的长度,让其指向开始位置。我会在开始的时候设置 `taddr` 为缓冲区的末尾地址。
+
+```
+noScroll$:
+teq bufferStop,taddr
+subeq bufferStop,taddr,#128*128*2
+```
+
+4.9、检查 `bufferStop` 是否等于 `bufferStart`。 如果等于增加一行到 `bufferStart`。
+
+```
+teq bufferStop,bufferStart
+addeq bufferStart,#128*2
+```
+
+4.10、如果 `start` 的地址在缓冲区的末尾,我们就从它上面减去缓冲区的长度,让其指向开始位置。我会在开始的时候设置 `taddr` 为缓冲区的末尾地址。
+
+```
+teq bufferStart,taddr
+subeq bufferStart,taddr,#128*128*2
+```
+循环执行知道字符串结束
+
+```
+subs length,#1
+add string,#1
+bgt charLoop$
+```
+
+5、保存变量然后返回
+
+```
+charLoopBreak$:
+sub taddr,#128*128*2
+sub taddr,#terminalBuffer-terminalStart
+str bufferStop,[taddr,#terminalStop-terminalStart]
+str view,[taddr,#terminalView-terminalStart]
+str bufferStart,[taddr]
+
+pop {r4,r5,r6,r7,r8,r9,r10,r11,pc}
+.unreq bufferStart
+.unreq taddr
+.unreq x
+.unreq string
+.unreq length
+.unreq char
+.unreq bufferStop
+.unreq view
+```
+
+这个方法允许我们打印任意字符到屏幕。然而我们用了颜色变量,但实际上没有设置它。一般终端用特性的组合字符去行修改颜色。如 ASCII 转义(1b16)后面跟着一个 0 - f 的 16 进制的数,就可以设置前景色为 CGA 颜色号。如果你自己想尝试实现;在下载页面有一个我的详细的例子。
+
+### 4、标志输入
+
+现在我们有一个可以打印和显示文本的输出终端。这仅仅是说对了一半,我们需要输入。我们想实现一个方法:`ReadLine`,可以保存文件的一行文本,文本位置由 `r0` 给出,最大的长度由 `r1` 给出,返回 `r0` 里面的字符串长度。棘手的是用户输出字符的时候要回显功能,同时想要退格键的删除功能和命令回车执行功能。它们还需要一个闪烁的下划线代表计算机需要输入。这些完全合理的要求让构造这个方法更具有挑战性。有一个方法完成这些需求就是存储用户输入的文本和文件大小到内存的某个地方。然后当调用 `ReadLine` 的时候,移动 `terminalStop` 的地址到它开始的地方然后调用 `Print`。也就是说我们只需要确保在内存维护一个字符串,然后构造一个我们自己的打印函数。
+
+> 按照惯例,许多编程语言中,任意程序可以访问 stdin 和 stdin,它们可以连接到终端的输入和输出流。在图形程序其实也可以进行同样操作,但实际几乎不用。
+
+让我们看看 `ReadLine` 做了哪些事情:
+
+ 1. 如果字符串可保存的最大长度为 0,直接返回
+ 2. 检索 `terminalStop` 和 `terminalStop` 的当前值
+ 3. 如果字符串的最大长度大约缓冲区的一半,就设置大小为缓冲区的一半
+ 4. 从最大长度里面减去 1 来确保输入的闪烁字符或结束符
+ 5. 向字符串写入一个下划线
+ 6. 写入一个 `terminalView` 和 `terminalStop` 的地址到内存
+ 7. 调用 `Print` 打印当前字符串
+ 8. 调用 `TerminalDisplay`
+ 9. 调用 `KeyboardUpdate`
+ 10. 调用 `KeyboardGetChar`
+ 11. 如果是一个新行直接跳转到第 16 步
+ 12. 如果是一个退格键,将字符串长度减 1(如果其大于 0)
+ 13. 如果是一个普通字符,将它写入字符串(字符串大小确保小于最大值)
+ 14. 如果字符串是以下划线结束,写入一个空格,否则写入下划线
+ 15. 跳转到第 6 步
+ 16. 字符串的末尾写入一个新行字符
+ 17. 调用 `Print` 和 `TerminalDisplay`
+ 18. 用结束符替换新行
+ 19. 返回字符串的长度
+
+
+为了方便读者理解,然后然后自己去实现,我们的实现提供如下:
+
+1. 快速处理长度为 0 的情况
+
+```
+.globl ReadLine
+ReadLine:
+teq r1,#0
+moveq r0,#0
+moveq pc,lr
+```
+
+2、考虑到常见的场景,我们初期做了很多初始化动作。`input` 代表 `terminalStop` 的值,`view` 代表 `terminalView`。`Length` 默认为 `0`。
+
+```
+string .req r4
+maxLength .req r5
+input .req r6
+taddr .req r7
+length .req r8
+view .req r9
+
+push {r4,r5,r6,r7,r8,r9,lr}
+
+mov string,r0
+mov maxLength,r1
+ldr taddr,=terminalStart
+ldr input,[taddr,#terminalStop-terminalStart]
+ldr view,[taddr,#terminalView-terminalStart]
+mov length,#0
+```
+
+3、我们必须检查异常大的读操作,我们不能处理超过 `terminalBuffer` 大小的输入(理论上可行,但是 `terminalStart` 移动越过存储的 terminalStop`,会有很多问题)。
+
+```
+cmp maxLength,#128*64
+movhi maxLength,#128*64
+```
+
+4、由于用户需要一个闪烁的光标,我们需要一个备用字符在理想状况在这个字符串后面放一个结束符。
+
+```
+sub maxLength,#1
+```
+
+5、写入一个下划线让用户知道我们可以输入了。
+
+```
+mov r0,#'_'
+strb r0,[string,length]
+```
+
+6、保存 `terminalStop` 和 `terminalView`。这个对重置一个终端很重要,它会修改这些变量。严格讲也可以修改 `terminalStart`,但是不可逆。
+
+```
+readLoop$:
+str input,[taddr,#terminalStop-terminalStart]
+str view,[taddr,#terminalView-terminalStart]
+```
+
+7、写入当前的输入。由于下划线因此字符串长度加 1
+
+```
+mov r0,string
+mov r1,length
+add r1,#1
+bl Print
+```
+
+8、拷贝下一个文本到屏幕
+
+```
+bl TerminalDisplay
+```
+
+
+9、获取最近一次键盘输入
+
+```
+bl KeyboardUpdate
+```
+
+10、检索键盘输入键值
+
+```
+bl KeyboardGetChar
+```
+
+11、如果我们有一个回车键,循环中断。如果有结束符和一个退格键也会同样跳出循环。
+
+```
+teq r0,#'\n'
+beq readLoopBreak$
+teq r0,#0
+beq cursor$
+teq r0,#'\b'
+bne standard$
+```
+
+12、从 `length` 里面删除一个字符
+
+```
+delete$:
+cmp length,#0
+subgt length,#1
+b cursor$
+```
+
+13、写回一个普通字符
+
+```
+standard$:
+cmp length,maxLength
+bge cursor$
+strb r0,[string,length]
+add length,#1
+```
+
+14、加载最近的一个字符,如果不是下划线则修改为下换线,如果是则修改为空格
+
+```
+cursor$:
+ldrb r0,[string,length]
+teq r0,#'_'
+moveq r0,#' '
+movne r0,#'_'
+strb r0,[string,length]
+```
+
+15、循环执行值到用户输入按下
+
+```
+b readLoop$
+readLoopBreak$:
+```
+
+16、在字符串的结尾处存入一个新行字符
+
+```
+mov r0,#'\n'
+strb r0,[string,length]
+```
+
+17、重置 `terminalView` 和 `terminalStop` 然后调用 `Print` 和 `TerminalDisplay` 显示最终的输入
+
+```
+str input,[taddr,#terminalStop-terminalStart]
+str view,[taddr,#terminalView-terminalStart]
+mov r0,string
+mov r1,length
+add r1,#1
+bl Print
+bl TerminalDisplay
+```
+
+18、写入一个结束符
+
+```
+mov r0,#0
+strb r0,[string,length]
+```
+
+19、返回长度
+
+```
+mov r0,length
+pop {r4,r5,r6,r7,r8,r9,pc}
+.unreq string
+.unreq maxLength
+.unreq input
+.unreq taddr
+.unreq length
+.unreq view
+```
+
+### 5、终端:机器进化
+
+现在我们理论用终端和用户可以交互了。最显而易见的事情就是拿去测试了!删除 `main.s` 里 `bl UsbInitialise` 后面的代码后如下:
+
+```
+reset$:
+ mov sp,#0x8000
+ bl TerminalClear
+
+ ldr r0,=welcome
+ mov r1,#welcomeEnd-welcome
+ bl Print
+
+loop$:
+ ldr r0,=prompt
+ mov r1,#promptEnd-prompt
+ bl Print
+
+ ldr r0,=command
+ mov r1,#commandEnd-command
+ bl ReadLine
+
+ teq r0,#0
+ beq loopContinue$
+
+ mov r4,r0
+
+ ldr r5,=command
+ ldr r6,=commandTable
+
+ ldr r7,[r6,#0]
+ ldr r9,[r6,#4]
+ commandLoop$:
+ ldr r8,[r6,#8]
+ sub r1,r8,r7
+
+ cmp r1,r4
+ bgt commandLoopContinue$
+
+ mov r0,#0
+ commandName$:
+ ldrb r2,[r5,r0]
+ ldrb r3,[r7,r0]
+ teq r2,r3
+ bne commandLoopContinue$
+ add r0,#1
+ teq r0,r1
+ bne commandName$
+
+ ldrb r2,[r5,r0]
+ teq r2,#0
+ teqne r2,#' '
+ bne commandLoopContinue$
+
+ mov r0,r5
+ mov r1,r4
+ mov lr,pc
+ mov pc,r9
+ b loopContinue$
+
+ commandLoopContinue$:
+ add r6,#8
+ mov r7,r8
+ ldr r9,[r6,#4]
+ teq r9,#0
+ bne commandLoop$
+
+ ldr r0,=commandUnknown
+ mov r1,#commandUnknownEnd-commandUnknown
+ ldr r2,=formatBuffer
+ ldr r3,=command
+ bl FormatString
+
+ mov r1,r0
+ ldr r0,=formatBuffer
+ bl Print
+
+loopContinue$:
+ bl TerminalDisplay
+ b loop$
+
+echo:
+ cmp r1,#5
+ movle pc,lr
+
+ add r0,#5
+ sub r1,#5
+ b Print
+
+ok:
+ teq r1,#5
+ beq okOn$
+ teq r1,#6
+ beq okOff$
+ mov pc,lr
+
+ okOn$:
+ ldrb r2,[r0,#3]
+ teq r2,#'o'
+ ldreqb r2,[r0,#4]
+ teqeq r2,#'n'
+ movne pc,lr
+ mov r1,#0
+ b okAct$
+
+ okOff$:
+ ldrb r2,[r0,#3]
+ teq r2,#'o'
+ ldreqb r2,[r0,#4]
+ teqeq r2,#'f'
+ ldreqb r2,[r0,#5]
+ teqeq r2,#'f'
+ movne pc,lr
+ mov r1,#1
+
+ okAct$:
+
+ mov r0,#16
+ b SetGpio
+
+.section .data
+.align 2
+welcome: .ascii "Welcome to Alex's OS - Everyone's favourite OS"
+welcomeEnd:
+.align 2
+prompt: .ascii "\n> "
+promptEnd:
+.align 2
+command:
+ .rept 128
+ .byte 0
+ .endr
+commandEnd:
+.byte 0
+.align 2
+commandUnknown: .ascii "Command `%s' was not recognised.\n"
+commandUnknownEnd:
+.align 2
+formatBuffer:
+ .rept 256
+ .byte 0
+ .endr
+formatEnd:
+
+.align 2
+commandStringEcho: .ascii "echo"
+commandStringReset: .ascii "reset"
+commandStringOk: .ascii "ok"
+commandStringCls: .ascii "cls"
+commandStringEnd:
+
+.align 2
+commandTable:
+.int commandStringEcho, echo
+.int commandStringReset, reset$
+.int commandStringOk, ok
+.int commandStringCls, TerminalClear
+.int commandStringEnd, 0
+```
+
+这块代码集成了一个简易的命令行操作系统。支持命令:`echo`、`reset`、`ok` 和 `cls`。`echo` 拷贝任意文本到终端,`reset` 命令会在系统出现问题的是复位操作系统,`ok` 有两个功能:设置 OK 灯亮灭,最后 `cls` 调用 TerminalClear 清空终端。
+
+试试树莓派的代码吧。如果遇到问题,请参照问题集锦页面吧。
+
+如果运行正常,祝贺你完成了一个操作系统基本终端和输入系列的课程。很遗憾这个教程先讲到这里,但是我希望将来能制作更多教程。有问题请反馈至 awc32@cam.ac.uk。
+
+你已经在建立了一个简易的终端操作系统。我们的代码在 commandTable 构造了一个可用的命令表格。每个表格的入口是一个整型数字,用来表示字符串的地址,和一个整型数字表格代码的执行入口。 最后一个入口是 为 0 的 `commandStringEnd`。尝试实现你自己的命令,可以参照已有的函数,建立一个新的。函数的参数 `r0` 是用户输入的命令地址,`r1` 是其长度。你可以用这个传递你输入值到你的命令。也许你有一个计算器程序,或许是一个绘图程序或国际象棋。不管你的什么点子,让它跑起来!
+
+
+--------------------------------------------------------------------------------
+
+via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/input02.html
+
+作者:[Alex Chadwick][a]
+选题:[lujun9972][b]
+译者:[guevaraya](https://github.com/guevaraya)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]: https://www.cl.cam.ac.uk
+[b]: https://github.com/lujun9972
+[1]: https://linux.cn/article-10676-1.html
+[2]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/circular_buffer.png
+[3]: https://en.wikipedia.org/wiki/Color_Graphics_Adapter
diff --git a/published/20160301 How To Set Password Policies In Linux.md b/published/20160301 How To Set Password Policies In Linux.md
new file mode 100644
index 0000000000..3cfedf6341
--- /dev/null
+++ b/published/20160301 How To Set Password Policies In Linux.md
@@ -0,0 +1,351 @@
+[#]: collector: (lujun9972)
+[#]: translator: (liujing97)
+[#]: reviewer: (wxy)
+[#]: publisher: (wxy)
+[#]: url: (https://linux.cn/article-10698-1.html)
+[#]: subject: (How To Set Password Policies In Linux)
+[#]: via: (https://www.ostechnix.com/how-to-set-password-policies-in-linux/)
+[#]: author: (SK https://www.ostechnix.com/author/sk/)
+
+如何设置 Linux 系统的密码策略
+======
+
+
+
+虽然 Linux 的设计是安全的,但还是存在许多安全漏洞的风险,弱密码就是其中之一。作为系统管理员,你必须为用户提供一个强密码。因为大部分的系统漏洞就是由于弱密码而引发的。本教程描述了在基于 DEB 系统的 Linux,比如 Debian、Ubuntu、Linux Mint 等和基于 RPM 系统的 Linux,比如 RHEL、CentOS、Scientific Linux 等的系统下设置像**密码长度**、**密码复杂度**、**密码有效期**等密码策略。
+
+### 在基于 DEB 的系统中设置密码长度
+
+默认情况下,所有的 Linux 操作系统要求用户**密码长度最少 6 个字符**。我强烈建议不要低于这个限制。并且不要使用你的真实名称、父母、配偶、孩子的名字,或者你的生日作为密码。即便是一个黑客新手,也可以很快地破解这类密码。一个好的密码必须是至少 6 个字符,并且包含数字、大写字母和特殊符号。
+
+通常地,在基于 DEB 的操作系统中,密码和身份认证相关的配置文件被存储在 `/etc/pam.d/` 目录中。
+
+设置最小密码长度,编辑 `/etc/pam.d/common-password` 文件;
+
+```
+$ sudo nano /etc/pam.d/common-password
+```
+
+找到下面这行:
+
+```
+password [success=2 default=ignore] pam_unix.so obscure sha512
+```
+
+![][2]
+
+在末尾添加额外的文字:`minlen=8`。在这里我设置的最小密码长度为 `8`。
+
+```
+password [success=2 default=ignore] pam_unix.so obscure sha512 minlen=8
+```
+
+
+
+保存并关闭该文件。这样一来,用户现在不能设置小于 8 个字符的密码。
+
+### 在基于 RPM 的系统中设置密码长度
+
+**在 RHEL、CentOS、Scientific Linux 7.x** 系统中, 以 root 身份执行下面的命令来设置密码长度。
+
+```
+# authconfig --passminlen=8 --update
+```
+
+查看最小密码长度,执行:
+
+```
+# grep "^minlen" /etc/security/pwquality.conf
+```
+
+**输出样例:**
+
+```
+minlen = 8
+```
+
+**在 RHEL、CentOS、Scientific Linux 6.x** 系统中,编辑 `/etc/pam.d/system-auth` 文件:
+
+```
+# nano /etc/pam.d/system-auth
+```
+
+找到下面这行并在该行末尾添加:
+
+```
+password requisite pam_cracklib.so try_first_pass retry=3 type= minlen=8
+```
+
+
+
+如上设置中,最小密码长度是 `8` 个字符。
+
+### 在基于 DEB 的系统中设置密码复杂度
+
+此设置会强制要求密码中应该包含多少类型,比如大写字母、小写字母和其他字符。
+
+首先,用下面命令安装密码质量检测库:
+
+```
+$ sudo apt-get install libpam-pwquality
+```
+
+之后,编辑 `/etc/pam.d/common-password` 文件:
+
+```
+$ sudo nano /etc/pam.d/common-password
+```
+
+为了设置密码中至少有一个**大写字母**,则在下面这行的末尾添加文字 `ucredit=-1`。
+
+```
+password requisite pam_pwquality.so retry=3 ucredit=-1
+```
+
+
+
+设置密码中至少有一个**小写字母**,如下所示。
+
+```
+password requisite pam_pwquality.so retry=3 dcredit=-1
+```
+
+设置密码中至少含有其他字符,如下所示。
+
+```
+password requisite pam_pwquality.so retry=3 ocredit=-1
+```
+
+正如你在上面样例中看到的一样,我们设置了密码中至少含有一个大写字母、一个小写字母和一个特殊字符。你可以设置被最大允许的任意数量的大写字母、小写字母和特殊字符。
+
+你还可以设置密码中被允许的字符类的最大或最小数量。
+
+下面的例子展示了设置一个新密码中被要求的字符类的最小数量:
+
+```
+password requisite pam_pwquality.so retry=3 minclass=2
+```
+
+### 在基于 RPM 的系统中设置密码复杂度
+
+**在 RHEL 7.x / CentOS 7.x / Scientific Linux 7.x 中:**
+
+设置密码中至少有一个小写字母,执行:
+
+```
+# authconfig --enablereqlower --update
+```
+
+查看该设置,执行:
+
+```
+# grep "^lcredit" /etc/security/pwquality.conf
+```
+
+**输出样例:**
+
+```
+lcredit = -1
+```
+
+类似地,使用以下命令去设置密码中至少有一个大写字母:
+
+```
+# authconfig --enablerequpper --update
+```
+
+查看该设置:
+
+```
+# grep "^ucredit" /etc/security/pwquality.conf
+```
+
+**输出样例:**
+
+```
+ucredit = -1
+```
+
+设置密码中至少有一个数字,执行:
+
+```
+# authconfig --enablereqdigit --update
+```
+
+查看该设置,执行:
+
+```
+# grep "^dcredit" /etc/security/pwquality.conf
+```
+
+**输出样例:**
+
+```
+dcredit = -1
+```
+
+设置密码中至少含有一个其他字符,执行:
+
+```
+# authconfig --enablereqother --update
+```
+
+查看该设置,执行:
+
+```
+# grep "^ocredit" /etc/security/pwquality.conf
+```
+
+**输出样例:**
+
+```
+ocredit = -1
+```
+
+在 **RHEL 6.x / CentOS 6.x / Scientific Linux 6.x systems** 中,以 root 身份编辑 `/etc/pam.d/system-auth` 文件:
+
+```
+# nano /etc/pam.d/system-auth
+```
+
+找到下面这行并且在该行末尾添加:
+
+```
+password requisite pam_cracklib.so try_first_pass retry=3 type= minlen=8 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1
+```
+
+如上设置中,密码必须要至少包含 `8` 个字符。另外,密码必须至少包含一个大写字母、一个小写字母、一个数字和一个其他字符。
+
+### 在基于 DEB 的系统中设置密码有效期
+
+现在,我们将要设置下面的策略。
+
+ 1. 密码被使用的最长天数。
+ 2. 密码更改允许的最小间隔天数。
+ 3. 密码到期之前发出警告的天数。
+
+设置这些策略,编辑:
+
+```
+$ sudo nano /etc/login.defs
+```
+
+在你的每个需求后设置值。
+
+```
+PASS_MAX_DAYS 100
+PASS_MIN_DAYS 0
+PASS_WARN_AGE 7
+```
+
+
+
+正如你在上面样例中看到的一样,用户应该每 `100` 天修改一次密码,并且密码到期之前的 `7` 天开始出现警告信息。
+
+请注意,这些设置将会在新创建的用户中有效。
+
+为已存在的用户设置修改密码的最大间隔天数,你必须要运行下面的命令:
+
+```
+$ sudo chage -M
+```
+
+设置修改密码的最小间隔天数,执行:
+
+```
+$ sudo chage -m
+```
+
+设置密码到期之前的警告,执行:
+
+```
+$ sudo chage -W
+```
+
+显示已存在用户的密码,执行:
+
+```
+$ sudo chage -l sk
+```
+
+这里,**sk** 是我的用户名。
+
+**输出样例:**
+
+```
+Last password change : Feb 24, 2017
+Password expires : never
+Password inactive : never
+Account expires : never
+Minimum number of days between password change : 0
+Maximum number of days between password change : 99999
+Number of days of warning before password expires : 7
+```
+
+正如你在上面看到的输出一样,该密码是无限期的。
+
+修改已存在用户的密码有效期,
+
+```
+$ sudo chage -E 24/06/2018 -m 5 -M 90 -I 10 -W 10 sk
+```
+
+上面的命令将会设置用户 `sk` 的密码期限是 `24/06/2018`。并且修改密码的最小间隔时间为 `5` 天,最大间隔时间为 `90` 天。用户账号将会在 `10` 天后被自动锁定,而且在到期之前的 `10` 天前显示警告信息。
+
+### 在基于 RPM 的系统中设置密码效期
+
+这点和基于 DEB 的系统是相同的。
+
+### 在基于 DEB 的系统中禁止使用近期使用过的密码
+
+你可以限制用户去设置一个已经使用过的密码。通俗的讲,就是说用户不能再次使用相同的密码。
+
+为设置这一点,编辑 `/etc/pam.d/common-password` 文件:
+
+```
+$ sudo nano /etc/pam.d/common-password
+```
+
+找到下面这行并且在末尾添加文字 `remember=5`:
+
+```
+password [success=2 default=ignore] pam_unix.so obscure use_authtok try_first_pass sha512 remember=5
+```
+
+上面的策略将会阻止用户去使用最近使用过的 5 个密码。
+
+### 在基于 RPM 的系统中禁止使用近期使用过的密码
+
+这点对于 RHEL 6.x 和 RHEL 7.x 和它们的衍生系统 CentOS、Scientific Linux 是相同的。
+
+以 root 身份编辑 `/etc/pam.d/system-auth` 文件,
+
+```
+# vi /etc/pam.d/system-auth
+```
+
+找到下面这行,并且在末尾添加文字 `remember=5`。
+
+```
+password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok remember=5
+```
+
+现在你了解了 Linux 中的密码策略,以及如何在基于 DEB 和 RPM 的系统中设置不同的密码策略。
+
+就这样,我很快会在这里发表另外一天有趣而且有用的文章。在此之前请保持关注。如果您觉得本教程对你有帮助,请在您的社交,专业网络上分享并支持我们。
+
+--------------------------------------------------------------------------------
+
+via: https://www.ostechnix.com/how-to-set-password-policies-in-linux/
+
+作者:[SK][a]
+选题:[lujun9972][b]
+译者:[liujing97](https://github.com/liujing97)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]: https://www.ostechnix.com/author/sk/
+[b]: https://github.com/lujun9972
+[1]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
+[2]: http://www.ostechnix.com/wp-content/uploads/2016/03/sk@sk-_003-2-1.jpg
diff --git a/published/20170710 iWant - The Decentralized Peer To Peer File Sharing Commandline Application.md b/published/20170710 iWant - The Decentralized Peer To Peer File Sharing Commandline Application.md
new file mode 100644
index 0000000000..2da3ae9a1a
--- /dev/null
+++ b/published/20170710 iWant - The Decentralized Peer To Peer File Sharing Commandline Application.md
@@ -0,0 +1,197 @@
+iWant:一个去中心化的点对点共享文件的命令行工具
+======
+
+
+
+不久之前,我们编写了一个指南,内容是一个文件共享实用程序,名为 [transfer.sh][1],它是一个免费的 Web 服务,允许你在 Internet 上轻松快速地共享文件,还有 [PSiTransfer][2],一个简单的开源自托管文件共享解决方案。今天,我们将看到另一个名为 “iWant” 的文件共享实用程序。它是一个基于命令行的自由开源的去中心化点对点文件共享应用程序。
+
+你可能想知道,它与其它文件共享应用程序有什么不同?以下是 iWant 的一些突出特点。
+
+ * 它是一个命令行应用程序。这意味着你不需要消耗内存来加载 GUI 实用程序。你只需要一个终端。
+ * 它是去中心化的。这意味着你的数据不会在任何中心位置存储。因此,不会因为中心点失败而失败。
+ * iWant 允许中断下载,你可以在以后随时恢复。你不需要从头开始下载,它会从你停止的位置恢复下载。
+ * 共享目录中文件所作的任何更改(如删除、添加、修改)都会立即反映在网络中。
+ * 就像种子一样,iWant 从多个节点下载文件。如果任何节点离开群组或未能响应,它将继续从另一个节点下载。
+ * 它是跨平台的,因此你可以在 GNU/Linux、MS Windows 或者 Mac OS X 中使用它。
+
+### 安装 iWant
+
+iWant 可以使用 PIP 包管理器轻松安装。确保你在 Linux 发行版中安装了 pip。如果尚未安装,参考以下指南。
+
+[如何使用 Pip 管理 Python 包](https://www.ostechnix.com/manage-python-packages-using-pip/)
+
+安装 pip 后,确保你有以下依赖项:
+
+ * libffi-dev
+ * libssl-dev
+
+比如说,在 Ubuntu 上,你可以使用以下命令安装这些依赖项:
+
+```
+$ sudo apt-get install libffi-dev libssl-dev
+```
+
+安装完所有依赖项后,使用以下命令安装 iWant:
+
+```
+$ sudo pip install iwant
+```
+
+现在我们的系统中已经有了 iWant,让我们来看看如何使用它来通过网络传输文件。
+
+### 用法
+
+首先,使用以下命令启动 iWant 服务器:
+
+(LCTT 译注:虽然这个软件是叫 iWant,但是其命令名为 `iwanto`,另外这个软件至少一年没有更新了。)
+
+```
+$ iwanto start
+```
+
+第一次启动时,iWant 会询问想要分享和下载文件夹的位置,所以需要输入两个文件夹的位置。然后,选择要使用的网卡。
+
+示例输出:
+
+```
+Shared/Download folder details looks empty..
+Note: Shared and Download folder cannot be the same
+SHARED FOLDER(absolute path):/home/sk/myshare
+DOWNLOAD FOLDER(absolute path):/home/sk/mydownloads
+Network interface available
+1. lo => 127.0.0.1
+2. enp0s3 => 192.168.43.2
+Enter index of the interface:2
+now scanning /home/sk/myshare
+[Adding] /home/sk/myshare 0.0
+Updating Leader 56f6d5e8-654e-11e7-93c8-08002712f8c1
+[Adding] /home/sk/myshare 0.0
+connecting to 192.168.43.2:1235 for hashdump
+```
+
+如果你看到类似上面的输出,你可以立即开始使用 iWant 了。
+
+同样,在网络中的所有系统上启动 iWant 服务,指定有效的分享和下载文件夹的位置,并选择合适的网卡。
+
+iWant 服务将继续在当前终端窗口中运行,直到你按下 `CTRL+C` 退出为止。你需要打开一个新选项卡或新的终端窗口来使用 iWant。
+
+iWant 的用法非常简单,它的命令很少,如下所示。
+
+ * `iwanto start` – 启动 iWant 服务。
+ * `iwanto search ` – 查找文件。
+ * `iwanto download ` – 下载一个文件。
+ * `iwanto share ` – 更改共享文件夹的位置。
+ * `iwanto download to ` – 更改下载文件夹位置。
+ * `iwanto view config` – 查看共享和下载文件夹。
+ * `iwanto –version` – 显示 iWant 版本。
+ * `iwanto -h` – 显示帮助信息。
+
+让我向你展示一些例子。
+
+#### 查找文件
+
+要查找一个文件,运行:
+
+```
+$ iwanto search
+
+```
+
+请注意,你无需指定确切的名称。
+
+示例:
+
+```
+$ iwanto search command
+```
+
+上面的命令将搜索包含 “command” 字符串的所有文件。
+
+我的 Ubuntu 系统会输出:
+
+```
+Filename Size Checksum
+------------------------------------------- ------- --------------------------------
+/home/sk/myshare/THE LINUX COMMAND LINE.pdf 3.85757 efded6cc6f34a3d107c67c2300459911
+```
+
+#### 下载文件
+
+你可以在你的网络上的任何系统下载文件。要下载文件,只需提供文件的哈希(校验和),如下所示。你可以使用 `iwanto search` 命令获取共享的哈希值。
+
+```
+$ iwanto download efded6cc6f34a3d107c67c2300459911
+```
+
+文件将保存在你的下载位置,在本文中是 `/home/sk/mydownloads/` 位置。
+
+```
+Filename: /home/sk/mydownloads/THE LINUX COMMAND LINE.pdf
+Size: 3.857569 MB
+```
+
+#### 查看配置
+
+要查看配置,例如共享和下载文件夹的位置,运行:
+
+```
+$ iwanto view config
+```
+
+示例输出:
+
+```
+Shared folder:/home/sk/myshare
+Download folder:/home/sk/mydownloads
+```
+
+#### 更改共享和下载文件夹的位置
+
+你可以更改共享文件夹和下载文件夹。
+
+```
+$ iwanto share /home/sk/ostechnix
+```
+
+现在,共享位置已更改为 `/home/sk/ostechnix`。
+
+同样,你可以使用以下命令更改下载位置:
+
+```
+$ iwanto download to /home/sk/Downloads
+```
+
+要查看所做的更改,运行命令:
+
+```
+$ iwanto view config
+```
+
+#### 停止 iWant
+
+一旦你不想用 iWant 了,可以按下 `CTRL+C` 退出。
+
+如果它不起作用,那可能是由于防火墙或你的路由器不支持多播。你可以在 `~/.iwant/.iwant.log` 文件中查看所有日志。有关更多详细信息,参阅最后提供的项目的 GitHub 页面。
+
+差不多就是全部了。希望这个工具有所帮助。下次我会带着另一个有趣的指南再次来到这里。
+
+干杯!
+
+### 资源
+
+-[iWant GitHub](https://github.com/nirvik/iWant)
+
+--------------------------------------------------------------------------------
+
+via: https://www.ostechnix.com/iwant-decentralized-peer-peer-file-sharing-commandline-application/
+
+作者:[SK][a]
+选题:[lujun9972](https://github.com/lujun9972)
+译者:[MjSeven](https://github.com/MjSeven)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://www.ostechnix.com/author/sk/
+[1]:https://www.ostechnix.com/easy-fast-way-share-files-internet-command-line/
+[2]:https://www.ostechnix.com/psitransfer-simple-open-source-self-hosted-file-sharing-solution/
diff --git a/published/20180118 Rediscovering make- the power behind rules.md b/published/20180118 Rediscovering make- the power behind rules.md
new file mode 100644
index 0000000000..4c770d0577
--- /dev/null
+++ b/published/20180118 Rediscovering make- the power behind rules.md
@@ -0,0 +1,101 @@
+重新发现 make: 规则背后的力量
+======
+
+
+
+我过去认为 makefile 只是一种将一组组的 shell 命令列出来的简便方法;过了一段时间我了解到它们是有多么的强大、灵活以及功能齐全。这篇文章带你领略其中一些有关规则的特性。
+
+> 备注:这些全是针对 GNU Makefile 的,如果你希望支持 BSD Makefile ,你会发现有些新的功能缺失。感谢 [zge][5] 指出这点。
+
+### 规则
+
+规则是指示 `make` 应该如何并且何时构建一个被称作为目标的文件的指令。目标可以依赖于其它被称作为前提的文件。
+
+你会指示 `make` 如何按步骤构建目标,那就是一套按照出现顺序一次执行一个的 shell 命令。语法像这样:
+
+```
+target_name : prerequisites
+ recipe
+```
+
+一但你定义好了规则,你就可以通过从命令行执行以下命令构建目标:
+
+```
+$ make target_name
+```
+
+目标一经构建,除非前提改变,否则 `make` 会足够聪明地不再去运行该步骤。
+
+### 关于前提的更多信息
+
+前提表明了两件事情:
+
+* 当目标应当被构建时:如果其中一个前提比目标更新,`make` 假定目的应当被构建。
+* 执行的顺序:鉴于前提可以反过来在 makefile 中由另一套规则所构建,它们同样暗示了一个执行规则的顺序。
+
+如果你想要定义一个顺序但是你不想在前提改变的时候重新构建目标,你可以使用一种特别的叫做“唯顺序”的前提。这种前提可以被放在普通的前提之后,用管道符(`|`)进行分隔。
+
+### 样式
+
+为了便利,`make` 接受目标和前提的样式。通过包含 `%` 符号可以定义一种样式。这个符号是一个可以匹配任何长度的文字符号或者空隔的通配符。以下有一些示例:
+
+* `%`:匹配任何文件
+* `%.md`:匹配所有 `.md` 结尾的文件
+* `prefix%.go`:匹配所有以 `prefix` 开头以 `.go` 结尾的文件
+
+### 特殊目标
+
+有一系列目标名字,它们对于 `make` 来说有特殊的意义,被称作特殊目标。
+
+你可以在这个[文档][1]发现全套特殊目标。作为一种经验法则,特殊目标以点开始后面跟着大写字母。
+
+以下是几个有用的特殊目标:
+
+- `.PHONY`:向 `make` 表明此目标的前提可以被当成伪目标。这意味着 `make` 将总是运行,无论有那个名字的文件是否存在或者上次被修改的时间是什么。
+- `.DEFAULT`:被用于任何没有指定规则的目标。
+- `.IGNORE`:如果你指定 `.IGNORE` 为前提,`make` 将忽略执行步骤中的错误。
+
+### 替代
+
+当你需要以你指定的改动方式改变一个变量的值,替代就十分有用了。
+
+替代的格式是 `$(var:a=b)`,它的意思是获取变量 `var` 的值,用值里面的 `b` 替代词末尾的每个 `a` 以代替最终的字符串。例如:
+
+```
+foo := a.o
+bar : = $(foo:.o=.c) # sets bar to a.c
+```
+
+注意:特别感谢 [Luis Lavena][2] 让我们知道替代的存在。
+
+### 档案文件
+
+档案文件是用来一起将多个数据文档(类似于压缩文件的概念)收集成一个文件。它们由 `ar` Unix 工具所构建。`ar` 可以用于为任何目的创建档案,但除了[静态库][3],它已经被 `tar` 大量替代。
+
+在 `make` 中,你可以使用一个档案文件中的单独一个成员作为目标或者前提,就像这样:
+
+```
+archive(member) : prerequisite
+ recipe
+```
+
+### 最后的想法
+
+关于 `make` 还有更多可探索的,但是至少这是一个起点,我强烈鼓励你去查看[文档][4],创建一个笨拙的 makefile 然后就可以探索它了。
+
+--------------------------------------------------------------------------------
+
+via: https://monades.roperzh.com/rediscovering-make-power-behind-rules/
+
+作者:[Roberto Dip][a]
+译者:[tomjlw](https://github.com/tomjlw)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://monades.roperzh.com
+[1]:https://www.gnu.org/software/make/manual/make.html#Special-Targets
+[2]:https://twitter.com/luislavena/
+[3]:http://tldp.org/HOWTO/Program-Library-HOWTO/static-libraries.html
+[4]:https://www.gnu.org/software/make/manual/make.html
+[5]:https://lobste.rs/u/zge
diff --git a/published/20180205 Rancher - Container Management Application.md b/published/20180205 Rancher - Container Management Application.md
new file mode 100644
index 0000000000..82f5a9ef6f
--- /dev/null
+++ b/published/20180205 Rancher - Container Management Application.md
@@ -0,0 +1,229 @@
+Rancher:一个全面的可用于产品环境的容器管理平台
+======
+
+Docker 作为一款容器化应用的新兴软件,被大多数 IT 公司使用来减少基础设施平台的成本。
+
+通常,没有 GUI 的 Docker 软件对于 Linux 管理员来说很容易,但是对于开发者来就有点困难。当把它搬到生产环境上来,那么它对 Linux 管理员来说也相当不友好。那么,轻松管理 Docker 的最佳解决方案是什么呢?
+
+唯一的办法就是提供 GUI。Docker API 允许第三方应用接入 Docker。在市场上有许多 Docker GUI 应用。我们已经写过一篇关于 Portainer 应用的文章。今天我们来讨论另一个应用,Rancher。
+
+容器让软件开发更容易,让开发者更快的写代码、更好的运行它们。但是,在生产环境上运行容器却很困难。
+
+**推荐阅读:** [Portainer:一个简单的 Docker 管理图形工具][1]
+
+### Rancher 简介
+
+[Rancher][2] 是一个全面的容器管理平台,它可以让容器在各种基础设施平台的生产环境上部署和运行更容易。它提供了诸如多主机网络、全局/本地负载均衡和卷快照等基础设施服务。它整合了原生 Docker 的管理能力,如 Docker Machine 和 Docker Swarm。它提供了丰富的用户体验,让 DevOps 管理员在更大规模的生产环境上运行 Docker。
+
+访问以下文章可以了解 Linux 系统上安装 Docker。
+
+**推荐阅读:**
+
+- [如何在 Linux 上安装 Docker][3]
+- [如何在 Linux 上使用 Docker 镜像][4]
+- [如何在 Linux 上使用 Docker 容器][5]
+- [如何在 Docker 容器内安装和运行应用][6]
+
+### Rancher 特性
+
+ * 可以在两分钟内安装 Kubernetes。
+ * 一键启动应用(90 个流行的 Docker 应用)。
+ * 部署和管理 Docker 更容易。
+ * 全面的生产级容器管理平台。
+ * 可以在生产环境上快速部署容器。
+ * 强大的自动部署和运营容器技术。
+ * 模块化基础设施服务。
+ * 丰富的编排工具。
+ * Rancher 支持多种认证机制。
+
+### 怎样安装 Rancher
+
+由于 Rancher 是以轻量级的 Docker 容器方式运行,所以它的安装非常简单。Rancher 是由一组 Docker 容器部署的。只需要简单的启动两个容器就能运行 Rancher。一个容器用作管理服务器,另一个容器在各个节点上作为代理。在 Linux 系统下简单的运行下列命令就能部署 Rancher。
+
+Rancher 服务器提供了两个不同的安装包标签如 `stable` 和 `latest`。下列命令将会拉取适合的 Rancher 镜像并安装到你的操作系统上。Rancher 服务器仅需要两分钟就可以启动。
+
+ * `latest`:这个标签是他们的最新开发构建。这些构建将通过 Rancher CI 的自动化框架进行验证,不建议在生产环境使用。
+ * `stable`:这是最新的稳定发行版本,推荐在生产环境使用。
+
+Rancher 的安装方法有多种。在这篇教程中我们仅讨论两种方法。
+
+ * 以单一容器的方式安装 Rancher(内嵌 Rancher 数据库)
+ * 以单一容器的方式安装 Rancher(外部数据库)
+
+### 方法 - 1
+
+运行下列命令以单一容器的方式安装 Rancher 服务器(内嵌数据库)
+
+```
+$ sudo docker run -d --restart=unless-stopped -p 8080:8080 rancher/server:stable
+$ sudo docker run -d --restart=unless-stopped -p 8080:8080 rancher/server:latest
+```
+
+### 方法 - 2
+
+你可以在启动 Rancher 服务器时指向外部数据库,而不是使用自带的内部数据库。首先创建所需的数据库,数据库用户为同一个。
+
+```
+> CREATE DATABASE IF NOT EXISTS cattle COLLATE = 'utf8_general_ci' CHARACTER SET = 'utf8';
+> GRANT ALL ON cattle.* TO 'cattle'@'%' IDENTIFIED BY 'cattle';
+> GRANT ALL ON cattle.* TO 'cattle'@'localhost' IDENTIFIED BY 'cattle';
+```
+
+运行下列命令启动 Rancher 去连接外部数据库。
+
+```
+$ sudo docker run -d --restart=unless-stopped -p 8080:8080 rancher/server \
+ --db-host myhost.example.com --db-port 3306 --db-user username --db-pass password --db-name cattle
+```
+
+如果你想测试 Rancher 2.0,使用下列的命令去启动。
+
+```
+$ sudo docker run -d --restart=unless-stopped -p 80:80 -p 443:443 rancher/server:preview
+```
+
+### 通过 GUI 访问 & 安装 Rancher
+
+浏览器输入 `http://hostname:8080` 或 `http://server_ip:8080` 去访问 rancher GUI.
+
+![][8]
+
+### 怎样注册主机
+
+注册你的主机 URL 允许它连接到 Rancher API。这是一次性设置。
+
+接下来,点击主菜单下面的 “Add a Host” 链接或者点击主菜单上的 “INFRASTRUCTURE >> Add Hosts”,点击 “Save” 按钮。
+
+![][9]
+
+默认情况下,Rancher 里的访问控制认证禁止了访问,因此我们首先需要通过一些方法打开访问控制认证,否则任何人都不能访问 GUI。
+
+点击 “>> Admin >> Access Control”,输入下列的值最后点击 “Enable Authentication” 按钮去打开它。在我这里,是通过 “local authentication” 的方式打开的。
+
+ * “Login UserName”: 输入你期望的登录名
+ * “Full Name”: 输入你的全名
+ * “Password”: 输入你期望的密码
+ * “Confirm Password”: 再一次确认密码
+
+![][10]
+
+注销然后使用新的登录凭证重新登录:
+
+![][11]
+
+现在,我能看到本地认证已经被打开。
+
+![][12]
+
+### 怎样添加主机
+
+注册你的主机后,它将带你进入下一个页面,在那里你能选择不同云服务提供商的 Linux 主机。我们将添加一个主机运行 Rancher 服务,因此选择“custom”选项然后输入必要的信息。
+
+在第 4 步输入你服务器的公有 IP,运行第 5 步列出的命令,最后点击 “close” 按钮。
+
+```
+$ sudo docker run -e CATTLE_AGENT_IP="192.168.56.2" --rm --privileged -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/rancher:/var/lib/rancher rancher/agent:v1.2.11 http://192.168.56.2:8080/v1/scripts/16A52B9BE2BAB87BB0F5:1546214400000:ODACe3sfis5V6U8E3JASL8jQ
+
+INFO: Running Agent Registration Process, CATTLE_URL=http://192.168.56.2:8080/v1
+INFO: Attempting to connect to: http://192.168.56.2:8080/v1
+INFO: http://192.168.56.2:8080/v1 is accessible
+INFO: Configured Host Registration URL info: CATTLE_URL=http://192.168.56.2:8080/v1 ENV_URL=http://192.168.56.2:8080/v1
+INFO: Inspecting host capabilities
+INFO: Boot2Docker: false
+INFO: Host writable: true
+INFO: Token: xxxxxxxx
+INFO: Running registration
+INFO: Printing Environment
+INFO: ENV: CATTLE_ACCESS_KEY=9946BD1DCBCFEF3439F8
+INFO: ENV: CATTLE_AGENT_IP=192.168.56.2
+INFO: ENV: CATTLE_HOME=/var/lib/cattle
+INFO: ENV: CATTLE_REGISTRATION_ACCESS_KEY=registrationToken
+INFO: ENV: CATTLE_REGISTRATION_SECRET_KEY=xxxxxxx
+INFO: ENV: CATTLE_SECRET_KEY=xxxxxxx
+INFO: ENV: CATTLE_URL=http://192.168.56.2:8080/v1
+INFO: ENV: DETECTED_CATTLE_AGENT_IP=172.17.0.1
+INFO: ENV: RANCHER_AGENT_IMAGE=rancher/agent:v1.2.11
+INFO: Launched Rancher Agent: e83b22afd0c023dabc62404f3e74abb1fa99b9a178b05b1728186c9bfca71e8d
+```
+
+![][13]
+
+等待几秒钟后新添加的主机将会出现。点击 “Infrastructure >> Hosts” 页面。
+
+![][14]
+
+### 怎样查看容器
+
+只需要点击下列位置就能列出所有容器。点击 “Infrastructure >> Containers” 页面。
+
+![][15]
+
+### 怎样创建容器
+
+非常简单,只需点击下列位置就能创建容器。
+
+点击 “Infrastructure >> Containers >> Add Container” 然后输入每个你需要的信息。为了测试,我将创建一个 `latest` 标签的 CentOS 容器。
+
+![][16]
+
+在同样的列表位置,点击 “ Infrastructure >> Containers”。
+
+![][17]
+
+点击容器名展示容器的性能信息,如 CPU、内存、网络和存储。
+
+![][18]
+
+选择特定容器,然后点击最右边的“三点”按钮或者点击“Actions”按钮对容器进行管理,如停止、启动、克隆、重启等。
+
+![][19]
+
+如果你想控制台访问容器,只需要点击 “Actions” 按钮中的 “Execute Shell” 选项即可。
+
+![][20]
+
+### 怎样从应用目录部署容器
+
+Rancher 提供了一个应用模版目录,让部署变的很容易,只需要单击一下就可以。
+它维护了多数流行应用,这些应用由 Rancher 社区贡献。
+
+![][21]
+
+点击 “Catalog >> All >> Choose the required application”,最后点击 “Launch” 去部署。
+
+![][22]
+
+
+--------------------------------------------------------------------------------
+
+via: https://www.2daygeek.com/rancher-a-complete-container-management-platform-for-production-environment/
+
+作者:[Magesh Maruthamuthu][a]
+译者:[arrowfeng](https://github.com/arrowfeng)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://www.2daygeek.com/author/magesh/
+[1]:https://www.2daygeek.com/portainer-a-simple-docker-management-gui/
+[2]:http://rancher.com/
+[3]:https://www.2daygeek.com/install-docker-on-centos-rhel-fedora-ubuntu-debian-oracle-archi-scentific-linux-mint-opensuse/
+[4]:https://www.2daygeek.com/list-search-pull-download-remove-docker-images-on-linux/
+[5]:https://www.2daygeek.com/create-run-list-start-stop-attach-delete-interactive-daemonized-docker-containers-on-linux/
+[6]:https://www.2daygeek.com/install-run-applications-inside-docker-containers/
+[7]:data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
+[8]:https://www.2daygeek.com/wp-content/uploads/2018/02/Install-rancher-container-management-application-in-linux-1.png
+[9]:https://www.2daygeek.com/wp-content/uploads/2018/02/Install-rancher-container-management-application-in-linux-2.png
+[10]:https://www.2daygeek.com/wp-content/uploads/2018/02/Install-rancher-container-management-application-in-linux-3.png
+[11]:https://www.2daygeek.com/wp-content/uploads/2018/02/Install-rancher-container-management-application-in-linux-3a.png
+[12]:https://www.2daygeek.com/wp-content/uploads/2018/02/Install-rancher-container-management-application-in-linux-4.png
+[13]:https://www.2daygeek.com/wp-content/uploads/2018/02/Install-rancher-container-management-application-in-linux-5.png
+[14]:https://www.2daygeek.com/wp-content/uploads/2018/02/Install-rancher-container-management-application-in-linux-6.png
+[15]:https://www.2daygeek.com/wp-content/uploads/2018/02/Install-rancher-container-management-application-in-linux-7.png
+[16]:https://www.2daygeek.com/wp-content/uploads/2018/02/Install-rancher-container-management-application-in-linux-8.png
+[17]:https://www.2daygeek.com/wp-content/uploads/2018/02/Install-rancher-container-management-application-in-linux-9.png
+[18]:https://www.2daygeek.com/wp-content/uploads/2018/02/Install-rancher-container-management-application-in-linux-10.png
+[19]:https://www.2daygeek.com/wp-content/uploads/2018/02/Install-rancher-container-management-application-in-linux-11.png
+[20]:https://www.2daygeek.com/wp-content/uploads/2018/02/Install-rancher-container-management-application-in-linux-12.png
+[21]:https://www.2daygeek.com/wp-content/uploads/2018/02/Install-rancher-container-management-application-in-linux-13.png
+[22]:https://www.2daygeek.com/wp-content/uploads/2018/02/Install-rancher-container-management-application-in-linux-14.png
diff --git a/published/20181003 Oomox - Customize And Create Your Own GTK2, GTK3 Themes.md b/published/20181003 Oomox - Customize And Create Your Own GTK2, GTK3 Themes.md
new file mode 100644
index 0000000000..80bca6cdb4
--- /dev/null
+++ b/published/20181003 Oomox - Customize And Create Your Own GTK2, GTK3 Themes.md
@@ -0,0 +1,132 @@
+[#]: collector: (lujun9972)
+[#]: translator: (geekpi)
+[#]: reviewer: (wxy)
+[#]: publisher: (wxy)
+[#]: url: (https://linux.cn/article-10683-1.html)
+[#]: subject: (Oomox – Customize And Create Your Own GTK2, GTK3 Themes)
+[#]: via: (https://www.ostechnix.com/oomox-customize-and-create-your-own-gtk2-gtk3-themes/)
+[#]: author: (EDITOR https://www.ostechnix.com/author/editor/)
+
+Oomox:定制和创建你自己的 GTK2、GTK3 主题
+======
+
+
+
+主题和可视化定制是 Linux 的主要优势之一。由于所有代码都是开源的,因此你可以比 Windows/Mac OS 更大程度上地改变 Linux 系统的外观和行为方式。GTK 主题可能是人们定制 Linux 桌面的最流行方式。GTK 工具包被各种桌面环境使用,如 Gnome、Cinnamon、Unity、XFC E和 budgie。这意味着为 GTK 制作的单个主题只需很少的修改就能应用于任何这些桌面环境。
+
+有很多非常高品质的流行 GTK 主题,例如 **Arc**、**Numix** 和 **Adapta**。但是如果你想自定义这些主题并创建自己的视觉设计,你可以使用 **Oomox**。
+
+Oomox 是一个图形应用,可以完全使用自己的颜色、图标和终端风格自定义和创建自己的 GTK 主题。它自带几个预设,你可以在 Numix、Arc 或 Materia 主题样式上创建自己的 GTK 主题。
+
+### 安装 Oomox
+
+在 Arch Linux 及其衍生版中:
+
+Oomox 可以在 [AUR][1] 中找到,所以你可以使用任何 AUR 助手程序安装它,如 [yay][2]。
+
+```
+$ yay -S oomox
+```
+
+在 Debian/Ubuntu/Linux Mint 中,在[这里][3]下载 `oomox.deb` 包并按如下所示进行安装。在写本指南时,最新版本为 `oomox_1.7.0.5.deb`。
+
+```
+$ sudo dpkg -i oomox_1.7.0.5.deb
+$ sudo apt install -f
+```
+
+在 Fedora 上,Oomox 可以在第三方 **COPR** 仓库中找到。
+
+```
+$ sudo dnf copr enable tcg/themes
+$ sudo dnf install oomox
+```
+
+Oomox 也有 [Flatpak 应用][4]。确保已按照[本指南][5]中的说明安装了 Flatpak。然后,使用以下命令安装并运行 Oomox:
+
+```
+$ flatpak install flathub com.github.themix_project.Oomox
+$ flatpak run com.github.themix_project.Oomox
+```
+
+对于其他 Linux 发行版,请进入 Github 上的 Oomox 项目页面(本指南末尾给出链接),并从源代码手动编译和安装。
+
+### 自定义并创建自己的 GTK2、GTK3 主题
+
+#### 主题定制
+
+
+
+你可以更改几乎每个 UI 元素的颜色,例如:
+
+1. 标题
+2. 按钮
+3. 标题内的按钮
+4. 菜单
+5. 选定的文字
+
+在左边,有许多预设主题,如汽车主题、现代主题,如 Materia 和 Numix,以及复古主题。在窗口的顶部,有一个名为**主题样式**的选项,可让你设置主题的整体视觉样式。你可以在 Numix、Arc 和 Materia 之间进行选择。
+
+使用某些像 Numix 这样的样式,你甚至可以更改标题渐变,边框宽度和面板透明度等内容。你还可以为主题添加黑暗模式,该模式将从默认主题自动创建。
+
+
+
+#### 图标集定制
+
+你可以自定义用于主题图标的图标集。有两个选项:Gnome Colors 和 Archdroid。你可以更改图标集的基础和笔触颜色。
+
+#### 终端定制
+
+你还可以自定义终端颜色。该应用有几个预设,但你可以为每个颜色,如红色,绿色,黑色等自定义确切的颜色代码。你还可以自动交换前景色和背景色。
+
+#### Spotify 主题
+
+这个应用的一个独特功能是你可以根据喜好定义 spotify 主题。你可以更改 spotify 的前景色、背景色和强调色来匹配整体的 GTK 主题。
+
+然后,只需按下“应用 Spotify 主题”按钮,你就会看到这个窗口:
+
+
+
+点击应用即可。
+
+#### 导出主题
+
+根据自己的喜好自定义主题后,可以通过单击左上角的重命名按钮重命名主题:
+
+
+
+然后,只需点击“导出主题”将主题导出到你的系统。
+
+
+
+你也可以只导出图标集或终端主题。
+
+之后你可以打开桌面环境中的任何可视化自定义应用,例如基于 Gnome 桌面的 Tweaks,或者 “XFCE 外观设置”。选择你导出的 GTK 或者 shell 主题。
+
+### 总结
+
+如果你是一个 Linux 主题迷,并且你确切知道系统中的每个按钮、每个标题应该怎样,Oomox 值得一试。 对于极致的定制者,它可以让你几乎更改系统外观的所有内容。对于那些只想稍微调整现有主题的人来说,它有很多很多预设,所以你可以毫不费力地得到你想要的东西。
+
+你试过吗? 你对 Oomox 有什么看法? 请在下面留言!
+
+### 资源
+
+- [Oomox GitHub 仓库](https://github.com/themix-project/oomox)
+
+--------------------------------------------------------------------------------
+
+via: https://www.ostechnix.com/oomox-customize-and-create-your-own-gtk2-gtk3-themes/
+
+作者:[EDITOR][a]
+选题:[lujun9972](https://github.com/lujun9972)
+译者:[geekpi](https://github.com/geekpi)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]: https://www.ostechnix.com/author/editor/
+[1]: https://aur.archlinux.org/packages/oomox/
+[2]: https://www.ostechnix.com/yay-found-yet-another-reliable-aur-helper/
+[3]: https://github.com/themix-project/oomox/releases
+[4]: https://flathub.org/apps/details/com.github.themix_project.Oomox
+[5]: https://www.ostechnix.com/flatpak-new-framework-desktop-applications-linux/
diff --git a/published/20181108 My Google-free Android life.md b/published/20181108 My Google-free Android life.md
new file mode 100644
index 0000000000..782f03f454
--- /dev/null
+++ b/published/20181108 My Google-free Android life.md
@@ -0,0 +1,212 @@
+[#]: collector: (lujun9972)
+[#]: translator: (LuuMing)
+[#]: reviewer: (wxy)
+[#]: publisher: (wxy)
+[#]: url: (https://linux.cn/article-10677-1.html)
+[#]: subject: (My Google-free Android life)
+[#]: via: (https://lushka.al/my-android-setup/)
+[#]: author: (Anxhelo Lushka https://lushka.al/)
+
+我的去 Google 化的安卓之旅
+======
+> 一篇介绍如何在你的生活中和设备里去 Google 化的文章。
+
+最近人们经常问我有关我手机的事情,比如安卓怎么安装,怎样绕过 Google Service 使用手机。好吧,这篇文章就来详细的解决那些问题。我尽可能让这篇文章适合初学者,因此我会慢慢介绍,一个一个来讲并且附上截图,你就能更好地看到它是怎样运作的。
+
+首先我会告诉你为什么 Google Services(在我看来)对你的设备不好。我可以一言以概之,并让你看 [Richard Stallman][2] 写的这篇[文章][1],但我决定抓住几个要点附在这。
+
+ * 要用非自由软件
+ * 大体上,大多数 Google Services 需要运行在非自由的 Javascript 代码之上。现如今,如果禁用掉 Javascript,什么都没有了,甚至 Google 帐号都需要运行非自由软件(由站点发送的 JavaScript),对于登录也是。
+ * 被监视
+ * Google 悄悄地把它的广告跟踪方式与浏览方式结合在一起,并存储了每个用户的大量数据。
+ * 服务条款
+ * Google 会终止转卖了 Pixel 手机的用户账户。他们无法访问帐户下保存在 Google Services 中的所有邮件和文档。
+ * 审查
+ * Amazon 和 Google 切断了域前置,该技术能使身处某些国家的人们访问到在那里禁止的通信系统。
+ * Google 已经同意为巴基斯坦政府执行特殊的 Youtube 审查,删除对立观点。这将有助于压制异议。
+ * Youtube 的“content ID”会自动删除已发布的视频,这并不包含在版权法中。
+
+这只是几个原因,你可以阅读上面我提到的 RMS 的文章,他详细解释了这几点。尽管听起来骇人听闻,但这些行为在现实生活中已经每天在发生。
+
+### 下一步,我的搭建教程
+
+我有一款[小米红米 Note 5 Pro][3] 智能手机(代号 whyred),生产于中国的[小米][4]。它是 4 个月之前(距写这篇文章的时候)我花了大约 185 欧元买的。
+
+现在你也许会想,“但你为什么买中国品牌,他们不可靠”。是的,它不是通常你所期望的(品牌)所生产的,例如三星(人们通常会将它和安卓联系在一起,这显然是错的)、一加、诺基亚等。但你应当知道几乎所有的手机都生产于中国。
+
+我选择这款手机有几个原因,首先当然是价格。它是一款性价比相当高的产品,大多数人都能买得起。下一个原因是说明书上的规格(不仅仅是),在这个价位上相当合适。拥有 6 英尺屏幕(全高清分辨率),4000 毫安电池(一流的电池寿命),4GB RAM,64GB 存储,双后摄像头(12 MP + 5 MP),一个带闪光灯的前摄像头(13 MP)和一个高性能的骁龙 636,它可能是那时候最好的选择。
+
+随之而来的问题是 [MIUI][5],大多数小米设备所附带的安卓外壳(除了 Android One 项目设备)。是的,它没有那么可怕,它有一些额外的功能,但问题在更深的地方。小米设备如此便宜(据我所知销售利润仅有 5-10%)的一个原因是**他们在系统里伴随 MIUI 添加了数据挖掘和广告**。这样的话,系统应用需要额外不必要的权限来获取你的数据并且进行广告轰炸,从中获取利润。
+
+更有趣的是,所包含的“天气”应用想要访问我的联系人并且拨打电话,如果它仅是显示天气的话为什么需要访问联系人呢。另一个例子是“录音机”应用,它也需要联系人和网络权限,可能想把录音发送回小米。
+
+为了解决它,我不得不格式化手机并且摆脱 MIUI。在市场上近来的手机上这就变得极为艰难。
+
+格式化手机的想法很简单,删除掉现有的系统然后安装一个新的喜欢的系统(这次是原生安卓)。为了实现它,你先得解锁 [bootloader][6]。
+
+> bootloader 是一个在计算机完成自检后为其加载操作系统或者运行环境的计算机程序。—[维基百科][7]
+
+问题是小米关于解锁 bootloader 有明确的政策。几个月之前,流程就像这样:你需向小米[申请][8]解锁代码,并提供真实的原因,但不是每次都成功,因为他们可以拒绝你的请求并且不提供理由。
+
+现在,流程变了。你要从小米那下载一个软件,叫做 [Mi Unlock][9],在 Windows 电脑上安装它,在手机的[开发者模式中打开调试选项][10],重启到 bootloader 模式(关机状态下长按向下音量键 + 电源键)并将手机连接到电脑上,开始一个叫做“许可”的流程。这个过程会在小米的服务器上启动一个定时器,允许你**在 15 天之后解锁手机**(在一些少数情况下或者一个月,完全随机)。
+
+![Mi Unlock app][11]
+
+15 天过去后,重新连接手机并重复之前的步骤,这时候按下解锁键,你的 bootloader 就会解锁,并且能够安装其他 ROM(系统)。**注意,确保你已经备份好了数据,因为解锁 bootloader 会清空手机。**
+
+下一步就是找一个兼容的系统([ROM][12])。我在 [XDA 开发者论坛上][13]找了个遍,它是 Android 开发者和用户们交流想法、应用等东西的地方。幸运的是,我的手机相当流行,因此论坛上有它[专门的版块][14]。在那儿,我略过一些流行的 ROM 并决定使用 [AOSiP ROM][15]。(AOSiP 代表安卓开源 illusion 项目)
+
+> **校订**:有人发邮件告诉我说文章里写的就是[/e/][16]的目的与所做的事情。我想说谢谢你的帮助,但完全不是这样。我关于 /e/ 的看法背后的原因可以见此[网站][17],但我仍会在此列出一些原因。
+
+> eelo 是一个从 Kickstarter 和 IndieGoGo 上集资并超过 200K € 的“基金会”,承诺创造一个开放、安全且保护隐私的移动 OS 和网页服务器。
+
+> 1. 他们的 OS 基于 LineageOS 14.1 (Android 7.1) 且搭载 microG 和其他开源应用,此系统已经存在很长一段时间了并且现在叫做 [Lineage for microG][18]。
+> 2. 所有的应用程序并非从源代码构建,而是从 [APKPure][19] 上下载安装包并推送进 ROM,不知道那些安装包中是否包含专有代码或恶意软件。
+> 3. 有一段时间,它们就那样随意地从代码中删除 Lineage 的版权标头并加入自己的。
+> 4. 他们喜欢删除负面反馈并且监视用户 Telegram 群聊中的舆论。
+
+> 总而言之,我**不建议使用 /e/** ROM。(至少现在)
+
+另一件你有可能要做的事情是获取手机的 [root 权限][20],让它真正的成为你的手机,并且修改系统中的文件,例如使用系统范围的 adblocker 等。为了实现它,我决定使用 [Magisk][21],一个天赐的应用,它由一个学生开发,可以帮你获取设备的 root 权限并安装一种叫做[模块][22]的东西,基本上是软件。
+
+下载 ROM 和 Magisk 之后,我得在手机上安装它们。为了完成安装,我将文件移动到了 SD 卡上。现在,若要安装系统,我需要使用 [恢复系统][23]。我用的是较为普遍的 [TWRP][24](代表 TeamWin Recovery Project)。
+
+要安装恢复系统(听起来有点难,我知道),我需要将文件[烧录][20]进手机。为了完成烧录,我将手机用一个叫做 [ADB 的工具][25]连接上电脑(Fedora Linux 系统)。使用命令让自己定制的恢复系统覆盖掉原先的。
+
+```
+fastboot flash recovery twrp.img
+```
+
+完成之后,我关掉手机并按住音量上和电源键,直到 TWRP 界面显示。这意味着我进行顺利,并且它已经准备好接收我的指令。
+
+![TWRP screen][26]
+
+下一步是**发送擦除命令**,在你第一次为手机安装自定义 ROM 时是必要的。如上图所示,擦除命令会清除掉数据,缓存和 Dalvik 。(这里也有高级选项让我们可以勾选以删除掉系统,如果我们不再需要旧系统的话)
+
+这需要几分钟去完成,之后,你的手机基本上就干净了。现在是时候**安装系统了**。通过按下主屏幕上的安装按钮,我们选择之前添加进的 zip 文件(ROM 文件)并滑动屏幕安装它。下一步,我们需要安装 Magisk,它可以给我们访问设备的 root 权限。
+
+> **校订**:一些有经验的安卓用户或发烧友也许注意到了,手机上不包含 [GApps](谷歌应用)。这在安卓世界里称之为 GApps-less,一个 GAps 应用也不安装。
+
+> 注意有一个不好之处在于若不安装 Google Services 有的应用无法正常工作,例如它们的通知也许会花更长的时间到达或者根本不起作用。(对我来说这一点是最影响应用程序使用的)原因是这些应用使用了 [Google Cloud Messaging][28](现在叫做 [Firebase][29])唤醒手机并推送通知。
+
+> 你可以通过安装使用 [microG][30](部分地)解决它,microG 提供一些 Google Services 的特性且允许你拥有更多的控制。我不建议使用它,因为它仍然有助于 Google Services 并且你不一定信任它。但是,如果你没法立刻放弃使用,只想慢慢地退出谷歌,这便是一个好的开始。
+
+都成功地安装之后,现在我们重启手机,就进入了主屏幕。
+
+### 下一个部分,安装应用并配置一切
+
+事情开始变得简单了。为了安装应用,我使用了 [F-Droid][31],一个可替代的应用商店,里面**只包含自由及开源应用**。如果这里没有你要的应用,你可以使用 [Aurora Store][32],一个从应用商店里下载应用且不需要使用谷歌帐号或被追踪的客户端。
+
+F-Droid 里面有名为 repos 的东西,它是一个包含你可以安装应用的“仓库”。我使用默认的仓库,并从 [IzzyOnDroid][33] 添加了另一个,它有更多默认仓库中没有的应用,并且它更新地更频繁。
+
+![My repos][34]
+
+从下面你可以发现我所安装的应用清单,它们替代的应用与用途。
+
+- [AdAway](https://f-droid.org/en/packages/org.adaway) > 系统广告拦截器,使用 hosts 文件拦截所有的广告
+- [AfWall+](https://f-droid.org/en/packages/dev.ukanth.ufirewall) > 一个防火墙,可以阻止不想要的连接
+- [Amaze](https://f-droid.org/en/packages/com.amaze.filemanager) > 替代系统的文件管理器,允许文件的 root 访问权限,并且拥有 zip/unzip 功能
+- [Ameixa](https://f-droid.org/en/packages/org.xphnx.ameixa) > 大多数应用的图标包
+- [andOTP](https://f-droid.org/en/packages/org.shadowice.flocke.andotp) > 替代谷歌验证器/Authy,一个可以用来登录启用了双因子验证的网站账户的 TOTP 应用,可以使用 PIN 码备份和锁定
+- [AnySoftKeyboard/AOSP Keyboard](https://f-droid.org/packages/com.menny.android.anysoftkeyboard/) > 开源键盘,它有许多主题和语言包,我也是该[项目](https://anysoftkeyboard.github.io/)的一员
+- [Audio Recorder](https://f-droid.org/en/packages/com.github.axet.audiorecorder) > 如其名字,允许你从麦克风录制不同格式的音频文件
+- [Battery Charge Limit](https://f-droid.org/en/packages/com.slash.batterychargelimit) > 当到 80% 时自动停止充电,降低电池磨损并增加寿命
+- [DAVx5](https://f-droid.org/en/packages/at.bitfire.davdroid) > 这是我最常用的应用之一,对我来说它基本上替代了谷歌联系人、谷歌日历和谷歌 Tasks,它连接着我的 Nextcloud 环境可以让我完全控制自己的数据
+- [Document Viewer](https://f-droid.org/en/packages/org.sufficientlysecure.viewer) > 一个可以打开数百种文件格式的查看器应用,快速、轻量
+- [Deezloader Remix](https://gitlab.com/Nick80835/DeezLoader-Android/) > 让我可以在 Deezer 上下载高质量 MP3 的应用
+- [Easy xkcd](https://f-droid.org/en/packages/de.tap.easy_xkcd) > xkcd 漫画阅读器,我喜欢这些 xkcd 漫画
+- [Etar](https://f-droid.org/en/packages/ws.xsoh.etar) > 日历应用,替代谷歌日历,与 DAVx5 一同工作
+- [FastHub-Libre](https://f-droid.org/en/packages/com.fastaccess.github.libre) > 一个 GitHub 客户端,完全 FOSS(自由及开源软件),非常实用如果你像我一样喜欢使用 Github 的话
+- [Fennec F-Droid](https://f-droid.org/en/packages/org.mozilla.fennec_fdroid) > 替代谷歌 Chrome 和其他类似的应用,一个为 F-Droid 打造的火狐浏览器,不含专有二进制代码并允许安装扩展提升浏览体验
+- [Gadgetbridge](https://f-droid.org/en/packages/nodomain.freeyourgadget.gadgetbridge) > 替代小米运动,可以用来配对小米硬件的应用,追踪你的健康、步数、睡眠等。
+- [K-9 Mail](https://f-droid.org/en/packages/com.fsck.k9) > 邮件客户端,替代 GMail 应用,可定制并可以添加多个账户
+- [Lawnchair](https://f-droid.org/en/packages/ch.deletescape.lawnchair.plah) > 启动器,可以替代 Nova Launcher 或 Pixel Launcher,允许自定义和各种改变,也支持图标包
+- [Mattermost](https://f-droid.org/en/packages/com.mattermost.mattermost) > 可以连接 Mattermost 服务器的应用。Mattermost 是一个 Slack 替代品
+- [NewPipe](https://f-droid.org/en/packages/org.schabi.newpipe) > 最好的 YouTube 客户端(我认为),可以替代 YoubTube,它完全是 FOSS,免除 YouTube 广告,占用更少空间,允许背景播放,允许下载视频/音频等。试一试吧
+- [Nextcloud SMS](https://f-droid.org/en/packages/fr.unix_experience.owncloud_sms) > 允许备份/同步 SMS 到我的 Nextcloud 环境
+- [Nextcloud Notes](https://f-droid.org/en/packages/it.niedermann.owncloud.notes) > 允许我创建,修改,删除,分享笔记并同步/备份到 Nextcloud 环境
+- [OpenTasks](https://f-droid.org/en/packages/org.dmfs.tasks) > 允许我创建、修改、删除任务并同步到我的 Nextcloud 环境
+- [OsmAnd~](https://f-droid.org/en/packages/net.osmand.plus) > 一个地图应用,使用 [OpenStreetMap](https://openstreetmap.org/),允许下载离线地图和导航
+- [QKSMS](https://f-droid.org/en/packages/com.moez.QKSMS) > 我最喜欢的短信应用,可以替代原来的 Messaging 应用,拥有漂亮的界面,拥有备份、个性化、延迟发送等特性。
+- [Resplash/Mysplash](https://f-droid.org/en/packages/com.wangdaye.mysplash) > 允许你无限地从 [Unsplash](https://unsplash.com/) 下载无数的漂亮壁纸,全都可以免费使用和修改。
+- [ScreenCam](https://f-droid.org/en/packages/com.orpheusdroid.screenrecorder) > 一个录屏工具,允许各样的自定义和录制模式,没有广告并且免费
+- [SecScanQR](https://f-droid.org/en/packages/de.t_dankworth.secscanqr) > 二维码识别应用,快速轻量
+- [Send Reduced Free](https://f-droid.org/en/packages/mobi.omegacentauri.SendReduced) > 这个应用可以在发送之前通过移除 PII(个人识别信息)和减小尺寸,让你立即分享大图
+- [Slide](https://f-droid.org/en/packages/me.ccrama.redditslide/) > 开源 Reddit 客户端
+- [Telegram FOSS](https://f-droid.org/en/packages/org.telegram.messenger) > 没有追踪和 Google Services 的纯净版 Telegram 安卓客户端
+- [TrebleShot](https://f-droid.org/en/packages/com.genonbeta.TrebleShot) > 这个天才般的应用可以让你通过 WIFI 分享文件给其它设备,真的超快,甚至无需连接网络
+- [Tusky](https://f-droid.org/en/packages/com.keylesspalace.tusky) > Tusky 是 [Mastodon](https://joinmastodon.org/) 平台的客户端(替代 Twitter)
+- [Unit Converter Ultimate](https://f-droid.org/en/packages/com.physphil.android.unitconverterultimate) > 这款应用可以一键在 200 种单位之间来回转换,非常快并且完全离线
+- [Vinyl Music Player](https://f-droid.org/en/packages/com.poupa.vinylmusicplayer) > 我首选的音乐播放器,可以替代谷歌音乐播放器或其他你已经安装的音乐播放器,它有漂亮的界面和许多特性
+- [VPN Hotspot](https://f-droid.org/en/packages/be.mygod.vpnhotspot) > 这款应用可以让我打开热点的时候分享 VPN,因此我可以在笔记本上什么都不用做就可以安全地浏览网页
+
+这些差不多就是我列出的一张**最实用的 F-Droid 应用**清单,但不巧,这些并不是所有应用。我使用的专有应用如下(我知道,我也许听起来是一个伪君子,但并不是所有的应用都可以替代,至少现在不是):
+
+ * Google Camera(与 Camera API 2 结合起来,需要 F-Droid 的基本的 microG 才能工作)
+ * Instagram
+ * MyVodafoneAL (运营商应用)
+ * ProtonMail (email 应用)
+ * Titanium Backup(备份应用数据,wifi 密码,通话记录等)
+ * WhatsApp (专有的端到端聊天应用,几乎我认识的所有人都有它)
+
+差不多就是这样,这就是我用的手机上所有的应用。**配置非常简单明了,我可以给几点提示**。
+
+ 1. 仔细阅读和检查应用的权限,不要无脑地点“安装”。
+ 2. 尽可能多地使用开源应用,它们即尊重你的隐私又是免费的(且自由)。
+ 3. 尽可能地使用 VPN,找一个有名气的,别用免费的,否则你将被收割数据然后成为产品。
+ 4. 不要一直打开 WIFI/移动数据/定位,有可能引起安全隐患。
+ 5. 不要只依赖指纹解锁,或者尽可能只用 PIN/密码/模式解锁,因为生物数据可以被克隆后针对你,例如解锁你的手机盗取你的数据。
+
+作为坚持读到这儿的奖励,**一张主屏幕的截图奉上**
+
+![Screenshot][35]
+
+--------------------------------------------------------------------------------
+
+via: https://lushka.al/my-android-setup/
+
+作者:[Anxhelo Lushka][a]
+选题:[lujun9972][b]
+译者:[LuuMing](https://github.com/luuming)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]: https://lushka.al/
+[b]: https://github.com/lujun9972
+[1]: https://stallman.org/google.html
+[2]: https://en.wikipedia.org/wiki/Richard_Stallman
+[3]: https://www.gsmarena.com/xiaomi_redmi_note_5_pro-8893.php
+[4]: https://en.wikipedia.org/wiki/Xiaomi
+[5]: https://en.wikipedia.org/wiki/MIUI
+[6]: https://forum.xda-developers.com/wiki/Bootloader
+[7]: https://en.wikipedia.org/wiki/Booting
+[8]: https://en.miui.com/unlock/
+[9]: http://www.miui.com/unlock/apply.php
+[10]: https://www.youtube.com/watch?v=7zhEsJlivFA
+[11]: https://lushka.al//assets/img/posts/mi-unlock.png
+[12]: https://www.xda-developers.com/what-is-custom-rom-android/
+[13]: https://forum.xda-developers.com/
+[14]: https://forum.xda-developers.com/redmi-note-5-pro
+[15]: https://forum.xda-developers.com/redmi-note-5-pro/development/rom-aosip-8-1-t3804473
+[16]: https://e.foundation
+[17]: https://ewwlo.xyz/evil
+[18]: https://lineage.microg.org/
+[19]: https://apkpure.com/
+[20]: https://lifehacker.com/5789397/the-always-up-to-date-guide-to-rooting-any-android-phone
+[21]: https://forum.xda-developers.com/apps/magisk/official-magisk-v7-universal-systemless-t3473445
+[22]: https://forum.xda-developers.com/apps/magisk
+[23]: http://www.smartmobilephonesolutions.com/content/android-system-recovery
+[24]: https://dl.twrp.me/whyred/
+[25]: https://developer.android.com/studio/command-line/adb
+[26]: https://lushka.al//assets/img/posts/android-twrp.png
+[27]: https://opengapps.org/
+[28]: https://developers.google.com/cloud-messaging/
+[29]: https://firebase.google.com/docs/cloud-messaging/
+[30]: https://microg.org/
+[31]: https://f-droid.org/
+[32]: https://f-droid.org/en/packages/com.dragons.aurora/
+[33]: https://android.izzysoft.de/repo
+[34]: https://lushka.al//assets/img/posts/android-fdroid-repos.jpg
+[35]: https://lushka.al//assets/img/posts/android-screenshot.jpg
+[36]: https://creativecommons.org/licenses/by-nc-sa/4.0/
diff --git a/published/20181119 Arch-Wiki-Man - A Tool to Browse The Arch Wiki Pages As Linux Man Page from Offline.md b/published/20181119 Arch-Wiki-Man - A Tool to Browse The Arch Wiki Pages As Linux Man Page from Offline.md
new file mode 100644
index 0000000000..0771c64582
--- /dev/null
+++ b/published/20181119 Arch-Wiki-Man - A Tool to Browse The Arch Wiki Pages As Linux Man Page from Offline.md
@@ -0,0 +1,223 @@
+[#]: collector: "lujun9972"
+[#]: translator: "Auk7F7"
+[#]: reviewer: "wxy"
+[#]: publisher: "wxy"
+[#]: subject: "Arch-Wiki-Man – A Tool to Browse The Arch Wiki Pages As Linux Man Page from Offline"
+[#]: via: "https://www.2daygeek.com/arch-wiki-man-a-tool-to-browse-the-arch-wiki-pages-as-linux-man-page-from-offline/"
+[#]: author: "Prakash Subramanian https://www.2daygeek.com/author/prakash/"
+[#]: url: "https://linux.cn/article-10694-1.html"
+
+Arch-Wiki-Man:一个以 Linux Man 手册样式离线浏览 Arch Wiki 的工具
+======
+
+现在上网已经很方便了,但技术上会有限制。看到技术的发展,我很惊讶,但与此同时,各种地方也都会出现衰退。
+
+当你搜索有关其他 Linux 发行版的某些东西时,大多数时候你会得到的是一个第三方的链接,但是对于 Arch Linux 来说,每次你都会得到 Arch Wiki 页面的结果。
+
+因为 Arch Wiki 提供了除第三方网站以外的大多数解决方案。
+
+到目前为止,你也许可以使用 Web 浏览器为你的 Arch Linux 系统找到一个解决方案,但现在你可以不用这么做了。
+
+一个名为 arch-wiki-man 的工具提供了一个在命令行中更快地执行这个操作的方案。如果你是一个 Arch Linux 爱好者,我建议你阅读 [Arch Linux 安装后指南][1],它可以帮助你调整你的系统以供日常使用。
+
+### arch-wiki-man 是什么?
+
+[arch-wiki-man][2] 工具允许用户从命令行(CLI)中离线搜索 Arch Wiki 页面。它允许用户以 Linux Man 手册样式访问和搜索整个 Wiki 页面。
+
+而且,你无需切换到 GUI。更新将每两天自动推送一次,因此,你的 Arch Wiki 本地副本页面将是最新的。这个工具的名字是 `awman`, `awman` 是 “Arch Wiki Man” 的缩写。
+
+我们之前写过一篇类似工具 [Arch Wiki 命令行实用程序][3](arch-wiki-cli)的文章。这个工具允许用户从互联网上搜索 Arch Wiki。但你需要在线使用这个实用程序。
+
+### 如何安装 arch-wiki-man 工具?
+
+arch-wiki-man 工具可以在 AUR 仓库(LCTT 译注:AUR 即Arch 用户软件仓库)中获得,因此,我们需要使用 AUR 工具来安装它。有许多 AUR 工具可用,而且我们曾写了一篇关于流行的 AUR 辅助工具: [Yaourt AUR helper][4] 和 [Packer AUR helper][5] 的文章。
+
+```
+$ yaourt -S arch-wiki-man
+```
+
+或
+
+```
+$ packer -S arch-wiki-man
+```
+
+或者,我们可以使用 npm 包管理器来安装它,确保你已经在你的系统上安装了 [NodeJS][6]。然后运行以下命令来安装它。
+
+```
+$ npm install -g arch-wiki-man
+```
+
+### 如何更新 Arch Wiki 本地副本?
+
+正如前面更新的那样,更新每两天自动推送一次,也可以通过运行以下命令来完成更新。
+
+```
+$ sudo awman-update
+[sudo] password for daygeek:
+[email protected] /usr/lib/node_modules/arch-wiki-man
+└── [email protected]
+
+arch-wiki-md-repo has been successfully updated or reinstalled.
+```
+
+`awman-update` 是一种更快、更方便的更新方法。但是,你也可以通过运行以下命令重新安装 arch-wiki-man 来获取更新。
+
+```
+$ yaourt -S arch-wiki-man
+```
+
+或
+
+```
+$ packer -S arch-wiki-man
+```
+
+### 如何在终端中使用 Arch Wiki ?
+
+它有着简易的接口且易于使用。想要搜索,只需要运行 `awman` 加搜索项目。一般语法如下所示。
+
+```
+$ awman Search-Term
+```
+
+### 如何搜索多个匹配项?
+
+如果希望列出包含 “installation” 字符串的所有结果的标题,运行以下格式的命令,如果输出有多个结果,那么你将会获得一个选择菜单来浏览每个项目。
+
+```
+$ awman installation
+```
+
+![][8]
+
+详细页面的截屏:
+
+![][9]
+
+### 在标题和描述中搜索给定的字符串
+
+`-d` 或 `--desc-search` 选项允许用户在标题和描述中搜索给定的字符串。
+
+```
+$ awman -d mirrors
+```
+
+或
+
+```
+$ awman --desc-search mirrors
+? Select an article: (Use arrow keys)
+❯ [1/3] Mirrors: Related articles
+ [2/3] DeveloperWiki-NewMirrors: Contents
+ [3/3] Powerpill: Powerpill is a pac
+```
+
+### 在内容中搜索给定的字符串
+
+`-k` 或 `--apropos` 选项也允许用户在内容中搜索给定的字符串。但须注意,此选项会显著降低搜索速度,因为此选项会扫描整个 Wiki 页面的内容。
+
+```
+$ awman -k openjdk
+```
+
+或
+
+```
+$ awman --apropos openjdk
+? Select an article: (Use arrow keys)
+❯ [1/26] Hadoop: Related articles
+ [2/26] XDG Base Directory support: Related articles
+ [3/26] Steam-Game-specific troubleshooting: See Steam/Troubleshooting first.
+ [4/26] Android: Related articles
+ [5/26] Elasticsearch: Elasticsearch is a search engine based on Lucene. It provides a distributed, mul..
+ [6/26] LibreOffice: Related articles
+ [7/26] Browser plugins: Related articles
+(Move up and down to reveal more choices)
+```
+
+### 在浏览器中打开搜索结果
+
+`-w` 或 `--web` 选项允许用户在 Web 浏览器中打开搜索结果。
+
+```
+$ awman -w AUR helper
+```
+
+或
+
+```
+$ awman --web AUR helper
+```
+
+![][10]
+
+### 以其他语言搜索
+
+想要查看支持的语言列表,请运行以下命令。
+
+```
+$ awman --list-languages
+arabic
+bulgarian
+catalan
+chinesesim
+chinesetrad
+croatian
+czech
+danish
+dutch
+english
+esperanto
+finnish
+greek
+hebrew
+hungarian
+indonesian
+italian
+korean
+lithuanian
+norwegian
+polish
+portuguese
+russian
+serbian
+slovak
+spanish
+swedish
+thai
+ukrainian
+```
+
+使用你的首选语言运行 `awman` 命令以查看除英语以外的其他语言的结果。
+
+```
+$ awman -l chinesesim deepin
+```
+
+![][11]
+
+--------------------------------------------------------------------------------
+
+via: https://www.2daygeek.com/arch-wiki-man-a-tool-to-browse-the-arch-wiki-pages-as-linux-man-page-from-offline/
+
+作者:[Prakash Subramanian][a]
+选题:[lujun9972][b]
+译者:[Auk7F7](https://github.com/Auk7F7)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]: https://www.2daygeek.com/author/prakash/
+[b]: https://github.com/lujun9972
+[1]: https://www.2daygeek.com/arch-linux-post-installation-30-things-to-do-after-installing-arch-linux/
+[2]: https://github.com/greg-js/arch-wiki-man
+[3]: https://www.2daygeek.com/search-arch-wiki-website-command-line-terminal/
+[4]: https://www.2daygeek.com/install-yaourt-aur-helper-on-arch-linux/
+[5]: https://www.2daygeek.com/install-packer-aur-helper-on-arch-linux/
+[6]: https://www.2daygeek.com/install-nodejs-on-ubuntu-centos-debian-fedora-mint-rhel-opensuse/
+[7]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
+[8]: https://www.2daygeek.com/wp-content/uploads/2018/11/arch-wiki-man-%E2%80%93-A-Tool-to-Browse-The-Arch-Wiki-Pages-As-Linux-Man-page-from-Offline-1.png
+[9]: https://www.2daygeek.com/wp-content/uploads/2018/11/arch-wiki-man-%E2%80%93-A-Tool-to-Browse-The-Arch-Wiki-Pages-As-Linux-Man-page-from-Offline-2.png
+[10]: https://www.2daygeek.com/wp-content/uploads/2018/11/arch-wiki-man-%E2%80%93-A-Tool-to-Browse-The-Arch-Wiki-Pages-As-Linux-Man-page-from-Offline-3.png
+[11]: https://www.2daygeek.com/wp-content/uploads/2018/11/arch-wiki-man-%E2%80%93-A-Tool-to-Browse-The-Arch-Wiki-Pages-As-Linux-Man-page-from-Offline-4.png
diff --git a/published/20111221 30 Best Sources For Linux - -BSD - Unix Documentation On the Web.md b/published/201812/20111221 30 Best Sources For Linux - -BSD - Unix Documentation On the Web.md
similarity index 100%
rename from published/20111221 30 Best Sources For Linux - -BSD - Unix Documentation On the Web.md
rename to published/201812/20111221 30 Best Sources For Linux - -BSD - Unix Documentation On the Web.md
diff --git a/published/201812/20171012 7 Best eBook Readers for Linux.md b/published/201812/20171012 7 Best eBook Readers for Linux.md
new file mode 100644
index 0000000000..346eed6bb6
--- /dev/null
+++ b/published/201812/20171012 7 Best eBook Readers for Linux.md
@@ -0,0 +1,188 @@
+7 个最佳 Linux 电子书阅读器
+======
+
+**摘要:** 本文中我们涉及一些 Linux 最佳电子书阅读器。这些应用提供更佳的阅读体验甚至可以管理你的电子书。
+
+![最佳 Linux 电子书阅读器][1]
+
+最近,随着人们发现在手持设备、Kindle 或者 PC 上阅读更加舒适,对电子图书的需求有所增加。至于 Linux 用户,也有各种电子书应用满足你阅读和整理电子书的需求。
+
+在本文中,我们选出了七个最佳 Linux 电子书阅读器。这些电子书阅读器最适合 pdf、epub 和其他电子书格式。
+
+我提供的是 Ubuntu 安装说明,因为我现在使用它。如果你使用的是[非 Ubuntu 发行版][2],你能在你的发行版软件仓库中找到大多数这些电子书应用。
+
+### 1. Calibre
+
+[Calibre][3] 是 Linux 最受欢迎的电子书应用。老实说,这不仅仅是一个简单的电子书阅读器。它是一个完整的电子书解决方案。你甚至能[通过 Calibre 创建专业的电子书][4]。
+
+通过强大的电子书管理和易用的界面,它提供了创建和编辑电子书的功能。Calibre 支持多种格式和与其它电子书阅读器同步。它也可以让你轻松转换一种电子书格式到另一种。
+
+Calibre 最大的缺点是,资源消耗太多,因此作为一个独立的电子阅读器来说是一个艰难的选择。
+
+![Calibre][5]
+
+#### 特性
+
+ * 管理电子书:Calibre 通过管理元数据来排序和分组电子书。你能从各种来源下载一本电子书的元数据或创建和编辑现有的字段。
+ * 支持所有主流电子书格式:Calibre 支持所有主流电子书格式并兼容多种电子阅读器。
+ * 文件转换:在转换时,你能通过改变电子书风格,创建内容表和调整边距的选项来转换任何一种电子书格式到另一种。你也能转换个人文档为电子书。
+ * 从 web 下载杂志期刊:Calibre 能从各种新闻源或者通过 RSS 订阅源传递故事。
+ * 分享和备份你的电子图书馆:它提供了一个选项,可以托管你电子书集合到它的服务端,从而你能与好友共享或用任何设备从任何地方访问。备份和导入/导出特性可以确保你的收藏安全和方便携带。
+
+#### 安装
+
+你能在主流 Linux 发行版的软件库中找到它。对于 Ubuntu,在软件中心搜索它或者使用下面的命令:
+
+```
+sudo apt-get install calibre
+```
+
+### 2. FBReader
+
+![FBReader: Linux 电子书阅读器][6]
+
+[FBReader][7] 是一个开源的轻量级多平台电子书阅读器,它支持多种格式,比如 ePub、fb2、mobi、rtf、html 等。它包括了一些可以访问的流行网络电子图书馆,那里你能免费或付费下载电子书。
+
+#### 特性
+
+ * 支持多种文件格式和设备比如 Android、iOS、Windows、Mac 和更多。
+ * 同步书集、阅读位置和书签。
+ * 在线管理你图书馆,可以从你的 Linux 桌面添加任何书到所有设备。
+ * 支持 Web 浏览器访问你的书集。
+ * 支持将书籍存储在 Google Drive ,可以通过作者,系列或其他属性整理书籍。
+
+#### 安装
+
+你能从官方库或者在终端中输入以下命令安装 FBReader 电子阅读器。
+
+```
+sudo apt-get install fbreader
+```
+
+或者你能从[这里][8]抓取一个以 .deb 包,并在你的基于 Debian 发行版的系统上安装它。
+
+### 3. Okular
+
+[Okular][9] 是另一个开源的基于 KDE 开发的跨平台文档查看器,它已经作为 KDE 应用发布的一部分了。
+
+![Okular][10]
+
+#### 特性
+
+ * Okular 支持多种文档格式像 PDF、Postscript、DjVu、CHM、XPS、ePub 和其他。
+ * 支持在 PDF 文档中评论、高亮和绘制不同的形状等。
+ * 无需修改原始 PDF 文件,分别保存上述这些更改。
+ * 电子书中的文本能被提取到一个文本文件,并且有个名为 Jovie 的内置文本阅读服务。
+
+备注:查看这个应用的时候,我发现这个应用在 Ubuntu 和它的衍生系统中不支持 ePub 文件格式。其他发行版用户仍然可以发挥它全部的潜力。
+
+#### 安装
+
+Ubuntu 用户可以在终端中键入下面的命令来安装它:
+
+```
+sudo apt-get install okular
+```
+
+### 4. Lucidor
+
+Lucidor 是一个易用的、支持 epub 文件格式和在 OPDS 格式中编目的电子阅读器。它也具有在本地书架里组织电子书集、从互联网搜索和下载,和将 Web 订阅和网页转换成电子书的功能。
+
+Lucidor 是 XULRunner 应用程序,它向您展示了具有类似火狐的选项卡式布局,和存储数据和配置时的行为。它是这个列表中最简单的电子阅读器,包括诸如文本说明和滚动选项之类的配置。
+
+![lucidor][11]
+
+你可以通过选择单词并右击“查找单词”来查找该单词在 Wiktionary.org 的定义。它也包含 web 订阅或 web 页面作为电子书的选项。
+
+你能从[这里][12]下载和安装 deb 或者 RPM 包。
+
+### 5. Bookworm
+
+![Bookworm Linux 电子阅读器][13]
+
+Bookworm 是另一个支持多种文件格式诸如 epub、pdf、mobi、cbr 和 cbz 的自由开源的电子阅读器。我写了一篇关于 Bookworm 应用程序的特性和安装的专题文章,到这里阅读:[Bookworm:一个简单而强大的 Linux 电子阅读器][14]
+
+#### 安装
+
+```
+sudo apt-add-repository ppa:bookworm-team/bookworm
+sudo apt-get update
+sudo apt-get install bookworm
+```
+
+### 6. Easy Ebook Viewer
+
+[Easy Ebook Viewer][15] 是又一个用于读取 ePub 文件的很棒的 GTK Python 应用。具有基本章节导航、从上次阅读位置继续、从其他电子书文件格式导入、章节跳转等功能,Easy Ebook Viewer 是一个简单而简约的 ePub 阅读器.
+
+![Easy-Ebook-Viewer][16]
+
+这个应用仍然处于初始阶段,只支持 ePub 文件。
+
+#### 安装
+
+你可以从 [GitHub][17] 下载源代码,并自己编译它及依赖项来安装 Easy Ebook Viewer。或者,以下终端命令将执行完全相同的工作。
+
+```
+sudo apt install git gir1.2-webkit-3.0 libwebkitgtk-3.0-0 gir1.2-gtk-3.0 python3-gi
+git clone https://github.com/michaldaniel/Ebook-Viewer.git
+cd Ebook-Viewer/
+sudo make install
+```
+
+成功完成上述步骤后,你可以从 Dash 启动它。
+
+### 7. Buka
+
+Buka 主要是一个具有简单而清爽的用户界面的电子书管理器。它目前支持 PDF 格式,旨在帮助用户更加关注内容。拥有 PDF 阅读器的所有基本特性,Buka 允许你通过箭头键导航,具有缩放选项,并且能并排查看两页。
+
+你可以创建单独的 PDF 文件列表并轻松地在它们之间切换。Buka 也提供了一个内置翻译工具,但是你需要有效的互联网连接来使用这个特性。
+
+![Buka][19]
+
+#### 安装
+
+你能从[官方下载页面][20]下载一个 AppImage。如果你不知道如何做,请阅读[如何在 Linux 下使用 AppImage][21]。或者,你可以通过命令行安装它:
+
+```
+sudo snap install buka
+```
+
+### 结束语
+
+就我个人而言,我发现 Calibre 最适合我的需要。当然,Bookworm 看起来很有前途,这几天我经常使用它。不过,电子书应用的选择完全取决于你的喜好。
+
+你使用哪个电子书应用呢?在下面的评论中让我们知道。
+
+
+--------------------------------------------------------------------------------
+
+via: https://itsfoss.com/best-ebook-readers-linux/
+
+作者:[Ambarish Kumar][a]
+译者:[zjon](https://github.com/zjon)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://itsfoss.com/author/ambarish/
+[1]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2017/10/best-ebook-readers-linux.png
+[2]:https://itsfoss.com/non-ubuntu-beginner-linux/
+[3]:https://www.calibre-ebook.com
+[4]:https://itsfoss.com/create-ebook-calibre-linux/
+[5]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2017/09/Calibre-800x603.jpeg
+[6]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2017/10/fbreader-800x624.jpeg
+[7]:https://fbreader.org
+[8]:https://fbreader.org/content/fbreader-beta-linux-desktop
+[9]:https://okular.kde.org/
+[10]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2017/09/Okular-800x435.jpg
+[11]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2017/09/lucidor-2.png
+[12]:http://lucidor.org/lucidor/download.php
+[13]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2017/08/bookworm-ebook-reader-linux-800x450.jpeg
+[14]:https://itsfoss.com/bookworm-ebook-reader-linux/
+[15]:https://github.com/michaldaniel/Ebook-Viewer
+[16]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2017/09/Easy-Ebook-Viewer.jpg
+[17]:https://github.com/michaldaniel/Ebook-Viewer.git
+[18]:https://github.com/oguzhaninan/Buka
+[19]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2017/09/Buka2-800x555.png
+[20]:https://github.com/oguzhaninan/Buka/releases
+[21]:https://itsfoss.com/use-appimage-linux/
diff --git a/published/20171108 Continuous infrastructure- The other CI.md b/published/201812/20171108 Continuous infrastructure- The other CI.md
similarity index 100%
rename from published/20171108 Continuous infrastructure- The other CI.md
rename to published/201812/20171108 Continuous infrastructure- The other CI.md
diff --git a/published/201812/20171111 A CEOs Guide to Emacs.md b/published/201812/20171111 A CEOs Guide to Emacs.md
new file mode 100644
index 0000000000..4a92e5710b
--- /dev/null
+++ b/published/201812/20171111 A CEOs Guide to Emacs.md
@@ -0,0 +1,286 @@
+CEO 的 Emacs 秘籍
+===========
+
+几年前,不,是几十年前,我就在用 Emacs。不论是码代码、编写文档,还是管理邮件和日程,我都用这个编辑器,或者是说操作系统,而且我还乐此不疲。许多年过去了,我也转向了其他更新、更好的工具。结果,就连最基本的文件浏览,我都已经忘了在不用鼠标的情况下该怎么操作。大约三个月前,我意识到我在应用程序和计算机之间切换上耗费了大量的时间,于是我决定再次使用 Emacs。这是个很正确的决定,原因有以下几个。其中包括用 `.emacs` 和 Dropbox 来搭建一个良好的、可移植的环境的一些技巧。
+
+对于那些还没用过 Emacs 的人来说,Emacs 会让你爱恨交加。它有点像一个房子大小的鲁布·戈德堡机械,乍一看,它具备烤面包机的所有功能。这听起来不像是一种认可,但关键词是“乍一看”。一旦你了解了 Emacs,你就会意识到它其实是一台可以当发动机用的热核烤面包机……好吧,只是指文本处理的所有事情。当考虑到你计算机的使用周期在很大程度上都是与文本有关时,这是一个相当大胆的声明。大胆,但却是真的。
+
+也许对我来说更重要的是,Emacs 是我曾经使用过的一个应用,并让我觉得我真正的拥有它,而不是把我塑造成一个匿名的“用户”,就好像位于 [Soma][30](LCTT 译注:旧金山的一个街区)或雷蒙德(LCTT 译注:微软总部所在地)附近某个高档办公室的产品营销部门把钱作为明确的目标一样。现代生产力和创作应用程序(如 Pages 或 IDE)就像碳纤维赛车,它们装备得很好,也很齐全。而 Emacs 就像一盒经典的 [Campagnolo][31] (LCTT 译注:世界上最好的三个公路自行车套件系统品牌之一)零件和一个漂亮的自行车牵引式钢框架,但缺少曲柄臂和刹车杆,你必须在网上某个小众文化中找到它们。前者更快而且很完整,后者是无尽的快乐或烦恼的源泉,当然这取决于你自己,而且这种快乐或烦恼会伴随到你死。我就是那种在找到一堆老古董或用 `Emacs Lisp` 配置编辑器时会感到高兴的人,具体情况因人而异。
+
+
+
+*一辆我还在骑的 1933 年产的钢制自行车。你可以看看框架管差别: [https://www.youtube.com/watch?v=khJQgRLKMU0][6]*
+
+这可能给人一种 Emacs 已经过气或过时的印象。然而并不是,Emacs 是强大和永恒的,只要你耐心地去理解它的一些规则。Emacs 的规则很另类,也很奇怪,但其中的逻辑却引人注目,且魅力十足。对于我来说, Emacs 更像是未来而不是过去。就像牵引式钢框架在未来几十年里将会变得好用和舒适,而神奇的碳纤维自行车将会被扔进垃圾场,在撞击中粉碎一样,Emacs 也将会作为一种在最新的流行应用早已被遗忘的时候的好用的工具继续存在这里。
+
+使用 Lisp 代码来构建个人工作环境,并将这个恰到好处的环境移植到任何计算机,如果这种想法打动了你,那么你将会爱上 Emacs。如果你喜欢很潮、很炫的,又不想投入太多时间和精力的情况下就能直接工作的话,那么 Emacs 可能不适合你。我已经不再写代码了(除了 Ludwig 和 Emacs Lisp),但是 Fugue 公司的很多工程师都使用 Emacs 来提高码代码的效率。我公司有 30% 的工程师用 Emacs,40% 用 IDE 和 30% 的用 vim。但这篇文章是写给 CEO 和其他[精英][32](PHB[^1] )(以及对 Emacs 感兴趣的人)的,所以我将解释或者说辩解我为什么喜欢它以及我如何使用它。同时我也希望我能介绍清楚,从而让你有个良好的体验,而不是花上几个小时去 Google。
+
+### 恒久优势
+
+使用 Emacs 带来的长期优势是让生活更轻松。与最后的收获相比,最开始的付出完全值得。想想这些:
+
+#### 简单高效
+
+Org 模式本身就值得花时间,但如果你像我一样,你通常要处理十几份左右的文件 —— 从博客帖子到会议事务清单,再到员工评估。在现代计算世界中,这通常意味着要使用多个应用程序,所有这些程序都有不同的用户界面、保存方式、排序和搜索方式。结果就是你需要不断转换思维环境,记住各种细节。我讨厌在程序间切换,这是在强人所难,因为这是个不完整界面模型[^2] ,并且我讨厌记住本该由计算机记住的东西。在单个环境下,Emacs 对 PHB 甚至比对于程序员更高效,因为程序员更多时候只需要专注于一个程序。转换思维环境的成本比表面上的要更高。操作系统和应用程序厂商已经构建了各种界面,以分散我们对这一现实的注意力。如果你是技术人员,通过快捷键(`M-:`)来访问功能强大的[语言解释器][33]会方便的多[^3] 。
+
+许多应用程序可以全天全屏地用于编辑文本。但Emacs 是唯一的,因为它既是编辑器也是 Emacs Lisp 解释器。从本质上来说,你工作时只要用电脑上的一两个键就能完成。如果你略懂编程的话,就会发现这代表着你可以在 Emacs 中做 _任何事情_。一旦你在内存中存储了这些指令,你的电脑就可以在工作时几乎实时地为你提供高效的运转。你不会想用 Emacs Lisp 来重建 Excel,因为只要用简单的一两行代码就能实现 Excel 中大多数的功能。比如说我要处理数字,我更有可能转到 scratch 缓冲区,编写一些代码,而不是打开电子表格。即便是要写一封比较大的邮件时,我通常也会先在 Emacs 中写完,然后再复制粘贴到邮件客户端中。当你可以流畅的书写时,为什么要去切换呢?你可以先从一两个简单的算术开始,随着时间的推移,你可以很容易的在 Emacs 中添加你所需要处理的计算。这在应用程序中可能是独一无二的,同时还提供了让为其他的人创造的丰富特性。还记得艾萨克·阿西莫夫书中那些神奇的终端吗? Emacs 是我所遇到的最接近它们的东西[^4] 。我决定不再用什么应用程序来做这个或那个。相反,我只是工作。拥有一个伟大的工具并致力于此,这才是真正的动力和效率。
+
+#### 静中造物
+
+拥有所发现的最好的文本编辑功能的最终结果是什么?有一群人在做各种各样有用的补充吗?发挥了 Lisp 键盘的全部威力了吗?我用 Emacs 来完成所有的创作性工作,音乐和图片除外。
+
+我办公桌上有两个显示器。其中一块竖屏是将 Emacs 全天全屏显示,另一个显示浏览器,用来搜索和阅读,我通常也会打开一个终端。我将日历、邮件等放在 OS X 的另一个桌面上,当我使用 Emacs 时,这个桌面会隐藏起来,同时我也会关掉所有通知。这样就能让我专注于我手头上在做的事了。我发现,越是先进的 UI 应用程序,消除干扰越是不可能,因为这些应用程序致力于提供帮助和易用性。我不需要经常被提醒该如何操作,我已经做了成千上万次了,我真正需要的是一张干净整洁的白纸用来思考。也许因为年龄和自己的“恶习”,我不太喜欢处在嘈杂的环境中,但我认为这值得一试。看看在你电脑环境中有一些真正的宁静是怎样的。当然,现在很多应用程序都有隐藏界面的模式,谢天谢地,苹果和微软现在都有了真正意义上的全屏模式。但是,没有并没有应用程序可以强大到足以“处理”大多数事务。除非你整天写代码,或者像出书一样,处理很长的文档,否则你仍然会面临其他应用程序的干扰。而且,大多数现代应用程序似乎同时显得自视甚高,缺乏功能和可用性[^5] 。比起 office 桌面版,我更讨厌它的在线版。
+
+
+
+*我的桌面布局, Emacs 在左边*
+
+但是沟通呢?创造和沟通之间的差别很大。当我将这两件事在不同时间段处理时,我的效率会更高。我们 Fugue 公司使用 Slack,痛并快乐着。我把 Slack 和我的日历、电子邮件放在一个即时通讯的桌面上,这样,当我正在做事时,我就能够忽略所有的聊天信息了。虽然只要一个 Slackstorm 或一封风投或董事会董事的电子邮件,就能让我立刻丢掉手头工作。但是,大多数事情通常可以等上一两个小时。
+
+#### 普适恒久
+
+第三个原因是,我发现 Emacs 比其它的环境更有优势的是,你可以很容易地用它来处理事务。我的意思是,你所需要的只是通过类似于 Dropbox 的网站同步一两个目录,而不是让大量的应用程序以它们自己的方式进行交互和同步。然后,你可以在任何你已经精心打造了适合你的目的的套件的环境中工作了。我在 OS X、Windows,或有时在 Linux 都是这样做的。它非常简单可靠。这种功能很有用,以至于我害怕处理 Pages、Google Docs、Office 或其他类型的文件和应用程序,这些文件和应用程序会迫使我回到文件系统或云中的某个地方去寻找。
+
+限制在计算机上永久存储的因素是文件格式。假设人类已经解决了存储问题[^6] ,随着时间的推移,我们面临的问题是我们能否够继续访问我们创建的信息。文本文件是保存时间最久的格式。你可以用 Emacs 轻松地打开 1970 年的文本文件。然而对于 Office 应用程序却并非如此。同时文本文件要比 Office 应用程序数据文件小得多,也要好的多。作为一个数码背包迷,作为一个在脑子里一闪而过就会做很多小笔记的人,拥有一个简单、轻便、永久、随时可用的东西对我来说很重要。
+
+如果你准备尝试 Emacs,请继续读下去!下面的部分不是完整的教程,但是在读完后,就可以动手操作了。
+
+### 驾驭之道 —— 专业定制
+
+所有这些强大、精神上的平静和安宁的代价是,Emacs 有一个陡峭的学习曲线,它的一切都与你以前所习惯的不同。一开始,这会让你觉得你是在浪费时间在一个过时和奇怪的应用程序上,就好像穿越到过去。这有点像你只开过车,却要你去学骑自行车[^7] 。
+
+#### 类型抉择
+
+我用的是来自 GNU 的 OS X 和 Windows 的通用版本的 Emacs。你可以在 [http://emacsformacos.com/][35] 获取 OS X 版本,在 [http://www.gnu.org/software/emacs/][37] 获取 Windows 版本。市面上还有很多其他版本,尤其是 Mac 版本,但我发现,要做一些功能强大的东西(涉及到 Lisp 和许多模式),学习曲线要比实际操作低得多。下载,然后我们就可以开始了[^8] !
+
+#### 驾驭之始
+
+在本文中,我将使用 Emacs 的按键和组合键约定。`C` 表示 `Control` 键,`M` 表示 `meta`(通常是 `Alt` 或 `Option` 键),以及用于组合键的连字符。因此,`C-h t` 表示同时按下 `Control` 和 `h` 键,然后释放,再按下 `t`。这个组合快捷键会指向一个教程,这是你首先要做的一件事。
+
+不要使用方向键或鼠标。它们可以工作,但是你应该给自己一周的时间来使用 Emacs 教程中的原生的导航命令。一旦你这些命令变为了肌肉记忆,你可能就会乐在其中,无论到哪里,你都会非常想念它们。这个 Emacs 教程在介绍它们方面做得很好,但是我将进行总结,所以你不需要阅读全部内容。最无聊的是,不用方向键,用 `C-b` 向前移动,用 `C-f` 向后移动,上一行用 `C-p`,下一行用 `C-n`。你可能会想:“我用方向键就很好,为什么还要这样做?” 有几个原因。首先,你不需要从主键盘区将你的手移开。第二,使用 `Alt`(或用 Emacs 的说法 `Meta`)键来向前或向后在单词间移动。显而易见这样更方便。第三,如果想重复某个命令,可以在命令前面加上一个数字。在编辑文档时,我经常使用这种方法,通过估计向后移动多少个单词或向上或向下移动多少行,然后按下 `C-9 C-p` 或 `M-5 M-b` 之类的快捷键。其它真正重要的导航命令基于开头用 `a` 和结尾用 `e`。在行中使用 `C-a|e`,在句中使用 `M-a|e`。为了让句中的命令正常工作,需要在句号后增加两个空格,这同时提供了一个有用的特性,并消除了脑中一个过时的[观点][38]。如果需要将文档导出到单个空间[发布环境][39],可以编写一个宏来执行此操作。
+
+Emacs 所附带的教程很值得去看。对于真正缺乏耐心的人,我将介绍一些重要的命令,但那个教程非常有用。记住:用 `C-h t` 进入教程。
+
+#### 驾驭之复制粘贴
+
+你可以把 Emacs 设为 CUA 模式,这将会以熟悉的方式工作来操作复制粘贴,但是原生的 Emacs 方法更好,而且你一旦学会了它,就很容易。你可以使用 `Shift` 和导航命令来标记区域(如同选择)。所以 `C-F` 是选中光标前的一个字符,等等。亦可以用 `M-w` 来复制,用 `C-w` 剪切,然后用 `C-y` 粘贴。这些实际上叫做删除和召回,但它非常类似于剪切和粘贴。在删除中还有一些小技巧,但是现在,你只需要关注剪切、复制和粘贴。如果你开始尝试了,那么 `C-x u` 是撤销。
+
+#### 驾驭之 Ido 模式
+
+相信我,Ido 会让文件的工作变得很简单。通常,你在 Emacs 中处理文件不需要使用一个单独的访达或文件资源管理器的窗口。相反,你可以用编辑器的命令来创建、打开和保存文件。如果没有 Ido 的话,这将有点麻烦,所以我建议你在学习其他之前安装好它。 Ido 是 Emacs 的 22 版时开始出现的,但是需要对你的 `.emacs` 文件做一些调整,来确保它一直开启着。这是个配置环境的好理由。
+
+Emacs 中的大多数功能都表现在模式上。要安装指定的模式,需要做两件事。嗯,一开始你需要做一些额外的事情,但这些只需要做一次,然后再做这两件事。那么,这件额外的事情是你需要一个单独的位置来放置所有 Emacs Lisp 文件,并且你需要告诉 Emacs 这个位置在哪。我建议你在 Dropbox 上创建一个单独的目录,那是你 Emacs 主目录。在这里,你需要创建一个 `.emacs` 文件和 `.emacs.d` 目录。在 `.emacs.d` 目录下,创建一个 `lisp` 的目录。就像这样:
+
+```
+home
+|
++.emacs
+|
+-.emacs.d
+ |
+ -lisp
+```
+
+你可以将 `.el` 文件,比如说模式文件,放到 `home/.emacs.d/lisp` 目录下,然后在你的 `.emacs` 文件中添加以下代码来指明该路径:
+
+```
+(add-to-list 'load-path "~/.emacs.d/lisp/")
+```
+
+Ido 模式是 Emacs 自带的,所以你不需要在你的 `lisp` 目录中放这个 `.el` 文件,但你仍然需要添加上面代码,因为下面的介绍会使用到它.
+
+#### 驾驭之符号链接
+
+等等,这里写的 `.emacs` 和 `.emacs.d` 都是存放在你的主目录下,但我们把它们放到了 Dropbox 的某些愚蠢的文件夹!对,这就让你的环境在任何地方都很容易使用。把所有东西都保存在 Dropbox 上,并做符号链接到 `~` 下的 `.emacs` 、`.emacs.d` 和你的主要存放文档的目录。在 OS X 上,使用 `ln -s` 命令非常简单,但在 Windows 上却很麻烦。幸运的是,Emacs 提供了一种简单的方法来替代 Windows 上的符号链接,Windows 的 `HOME` 环境变量。转到 Windows 的环境变量(Windows 10,你可以按 Windows 键然后输入 “环境变量” 来搜索,这是 Windows 10 最好的地方了),在你的帐户下创建一个指向你在 Dropbox 中 Emacs 的文件夹的 `HOME` 环境变量。如果你想方便地浏览 Dropbox 之外的本地文件,你可能想在你的实际主目录下建立一个到 Dropbox 下 Emacs 主目录的符号链接。
+
+至此,你已经完成了在任意机器上指向你的 Emacs 配置和文件所需的技巧。如果你买了一台新电脑,或者用别人的电脑一小时或一天,你就可以得到你的整个工作环境。第一次操作起来似乎有点难,但是一旦你知道你在做什么,就(最多)只需要 10 分钟。
+
+但我们现在是在配置 Ido ……
+
+按下 `C-x` `C-f` 然后输入 `~/.emacs` 和两次回车来创建 `.emacs` 文件,将下面几行添加进去:
+
+```
+;; set up ido mode
+(require `ido)
+(setq ido-enable-flex-matching t)
+(setq ido-everywhere t)
+(ido-mode 1)
+```
+
+在 `.emacs` 窗口开着的时候,执行 `M-x evaluate-buffer` 命令。如果某处弄错了的话,将得到一个错误,或者你将得到 Ido。Ido 改变了在 minibuffer 中操作文件操方式。关于这个有一篇比较好的文档,但是我也会指出一些技巧。有效地使用 `~/`;你可以在 minibuffer 的任何地方输入 `~/`,它就会跳转到主目录。这就意味着,你应该让你的大部分东西就近的放在主目录下。我用 `~/org` 目录来保存所有非代码的东西,用 `~/code` 保存代码。一旦你进入到正确的目录,通常会拥有一组具有不同扩展名的文件,特别是当你使用 Org 模式并从中发布的话。你可以输入 `.` 和想要的扩展名,无论你的在文件名的什么位置,Ido 都会将选择限制在具有该扩展名的文件中。例如,我在 Org 模式下写这篇博客,所以该文件是:
+
+```
+~/org/blog/emacs.org
+```
+
+我偶尔也会用 Org 模式发布成 HTML 格式,所以我将在同一目录下得到 `emacs.html` 文件。当我想打开该 Org 文件时,我会输入:
+
+```
+C-x C-f ~/o[RET]/bl[RET].or[RET]
+```
+
+其中 `[RET]` 是我使用 `Ido` 模式的自动补全而按下的回车键。所以,这只需要按 12 个键,如果你习惯了的话, 这将比打开访达或文件资源管理器再用鼠标点要节省 _很_ 多时间。 Ido 模式很有用,而这只是操作 Emacs 的一种实用模式而已。下面让我们去探索一些其它对完成工作很有帮助的模式吧。
+
+#### 驾驭之字体风格
+
+我推荐在 Emacs 中使用漂亮的字体族。它们可以使用不同的括号、0 和其他字符进行自定义。你可以在字体文件本身中构建额外的行间距。我推荐 1.5 倍的行间距,并在代码和数据中使用不等宽字体。写作中我用 `Serif` 字体,它有一种紧凑但时髦的感觉。你可以在 [http://input.fontbureau.com/][40] 上找到它们,在那里你可以根据自己的喜好进行定制。你可以使用 Emacs 中的菜单手动设置字体,但这会将代码保存到你的 `.emacs` 文件中,如果你使用多个设备,你可能需要一些不同的设置。我将我的 `.emacs` 设置为根据使用的机器的名称来相应配置屏幕。代码如下:
+
+```
+;; set up fonts for different OSes. OSX toggles to full screen.
+(setq myfont "InputSerif")
+(cond
+((string-equal system-name "Sampo.local")
+ (set-face-attribute 'default nil :font myfont :height 144)
+ (toggle-frame-fullscreen))
+((string-equal system-name "Morpheus.local")
+ (set-face-attribute 'default nil :font myfont :height 144))
+((string-equal system-name "ILMARINEN")
+ (set-face-attribute 'default nil :font myfont :height 106))
+((string-equal system-name "UKKO")
+ (set-face-attribute 'default nil :font myfont :height 104)))
+```
+
+你应该将 Emacs 中的 `system-name` 的值替换成你通过 `(system-name)` 得到的值。注意,在 Sampo (我的 MacBook)上,我还将 Emacs 设置为全屏。我也想在 Windows 实现这个功能,但是 Windows 和 Emacs 好像互相嫌弃对方,当我尝试配置时,它总是不稳定。相反,我只能在启动后手动全屏。
+
+我还建议去掉 Emacs 中的上世纪 90 年代出现的难看工具栏,当时比较流行在应用程序中使用工具栏。我还去掉了一些其它的“电镀层”,这样我就有了一个简单、高效的界面。把这些加到你的 `.emacs` 的文件中来去掉工具栏和滚动条,但要保留菜单(在 OS X 上,它将被隐藏,除非你将鼠标到屏幕顶部):
+
+```
+(if (fboundp 'scroll-bar-mode) (scroll-bar-mode -1))
+(if (fboundp 'tool-bar-mode) (tool-bar-mode -1))
+(if (fboundp 'menu-bar-mode) (menu-bar-mode 1))
+```
+
+#### 驾驭之 Org 模式
+
+我基本上是在 Org 模式下处理工作的。它是我创作文档、记笔记、列任务清单以及 90% 其他工作的首选环境。Org 模式是笔记和待办事项列表的组合工具,最初是由一个在会议中使用笔记本电脑的人构想出来的。我反对在会议中使用笔记本电脑,自己也不使用,所以我的用法与他的有些不同。对我来说,Org 模式主要是一种处理结构中内容的方式。在 Org 模式中有标题和副标题等,它们的作用就像一个大纲。Org 模式允许你展开或隐藏大纲树,还可以重新排列该树。这正合我意,并且我发现用这种方式使用它是一种乐趣。
+
+Org 模式也有很多让生活愉快的小功能。例如,脚注处理非常好,LaTeX/PDF 输出也很好。Org 模式能够根据所有文档中的待办事项生成议程,并能很好地将它们与日期/时间联系起来。我不把它用在任何形式的外部任务上,这些任务都是在一个共享的日历上处理的,但是在创建事物和跟踪我未来需要创建的东西时,它是无价的。安装它,你只要将 `org-mode.el` 放到你的 `lisp` 目录下。如果你想要它基于文档的结构进行缩进并在打开时全部展开的话,在你的 `.emacs` 文件中添加如下代码:
+
+```
+;; set up org mode
+(setq org-startup-indented t)
+(setq org-startup-folded "showall")
+(setq org-directory "~/org")
+```
+
+最后一行是让 Org 模式知道在哪里查找要包含在议程和其他事情中的文件。我把 Org 模式保存在我的主目录中,也就是说,像前面介绍的一样,它是 Dropbox 目录的一个符号链接。
+
+我有一个总是在缓冲区中打开的 `stuff.org` 文件。我把它当作记事本。Org 模式使得提取待办事项和有期限的事情变得很容易。当你能够内联 Lisp 代码并在需要计算它时,它特别有用。拥有包含内容的代码非常方便。同样,你可以使用 Emacs 访问实际的计算机,这是一种解放。
+
+##### 用 Org 模式进行发布
+
+我关心的是文档的外观及格式。我刚开始工作时是个设计师,而且我认为信息可以,也应该表现得清晰和美丽。Org 模式对将 LaTeX 生成 PDF 支持的很好,LaTeX 虽然也有学习曲线,但是很容易处理一些简单的事务。
+
+如果你想使用字体和样式,而不是典型的 LaTeX 字体和样式,你需要做些事。首先,你要用到 XeLaTeX,这样就可以使用普通的系统字体,而不是 LaTeX 的特殊字体。接下来,你需要将以下代码添加到 `.emacs` 中:
+
+```
+(setq org-latex-pdf-process
+ '("xelatex -interaction nonstopmode %f"
+ "xelatex -interaction nonstopmode %f"))
+```
+
+我把这个放在 `.emacs` 中 Org 模式配置部分的末尾,使文档变得更整洁。这让你在从 Org 模式发布时可以使用更多格式化选项。例如,我经常使用:
+
+```
+#+LaTeX_HEADER: \usepackage{fontspec}
+#+LATEX_HEADER: \setmonofont[Scale=0.9]{Input Mono}
+#+LATEX_HEADER: \setromanfont{Maison Neue}
+#+LATEX_HEADER: \linespread{1.5}
+#+LATEX_HEADER: \usepackage[margin=1.25in]{geometry}
+
+#+TITLE: Document Title Here
+```
+
+这些都可以在 `.org` 文件中找到。我们的公司规定的正文字体是 `Maison Neue`,但你也可以在这写上任何适当的东西。我很是抵制 `Maison Neue`,因为这是一种糟糕的字体,任何人都不应该使用它。
+
+这个文件是一个使用该配置输出为 PDF 的实例。这就是开箱即用的 LaTeX 一样。在我看来这还不错,但是字体很平淡,而且有点奇怪。此外,如果你使用标准格式,人们会觉得他们正在阅读的东西是、或者假装是一篇学术论文。别怪我没提醒你。
+
+#### 驾驭之 Ace Jump 模式
+
+这只是一个辅助模式,而不是一个主模式,但是你也需要它。其工作原理有点像之前提到的 Jef Raskin 的 Leap 功能[^9] 。 按下 `C-c C-SPC`,然后输入要跳转到单词的第一个字母。它会高亮显示所有以该字母开头的单词,并将其替换为字母表中的字母。你只需键入所需位置的字母,光标就会跳转到该位置。我常将它作为导航键或是用来检索。将 `.el` 文件下到你的 `lisp` 目录下,并在 `.emacs` 文件添加如下代码:
+
+```
+;; set up ace-jump-mode
+(add-to-list 'load-path "which-folder-ace-jump-mode-file-in/")
+(require 'ace-jump-mode)
+(define-key global-map (kbd "C-c C-SPC" ) 'ace-jump-mode)
+```
+
+### 待续
+
+本文已经够详细了,你能在其中得到你所想要的。我很想知道除编程之外(或用于编程)Emacs 的使用情况,及其是否高效。在我使用 Emacs 的过程中,可能存在一些自作聪明的老板式想法,如果你能指出来,我将不胜感激。之后,我可能会写一些更新来介绍其它特性或模式。我很确定我将会向你展示如何在 Emacs 和 Ludwig 模式下使用 Fugue,因为我会将它发展成比代码高亮更有用的东西。更多想法,请在 Twitter 上 [@fugueHQ][41] 。
+
+### 脚注
+
+[^1]: 如果你是位精英,但从没涉及过技术方面,那么 Emacs 并不适合你。对于少数的人来说,Emacs 可能会为他们开辟一条通往计算机技术方面的道路,但这只是极少数。如果你知道怎么使用 Unix 或 Windows 的终端,或者曾编辑过 dotfile,或者说你曾写过一点代码的话,这对使用 Emacs 有很大的帮助。
+
+[^2]: 参考链接: http://archive.wired.com/wired/archive/2.08/tufte.html
+
+[^3]: 我主要是在写作时使用这个模式来进行一些运算。比如说,当我在给一个新雇员写一封入职信时,我想要算这封入职信中有多少个选项。由于我在我的 `.emacs` 为 outstanding-shares 定义了一个变量,所以我只要按下 `M-:` 然后输入 `(* .001 outstanding-shares)` 就能再无需打开计算器或电子表格的情况下得到精度为 0.001 的结果。我使用了 _大量_ 的变量来避免程序间切换。
+
+[^4]: 缺少的部分是 web。有个名为 eww 的 Emacs 网页浏览器能够让你在 Emacs 中浏览网页。我用的就是这个,因为它既能拦截广告(LCTT 译注:实质上是无法显示,/laugh),同时也在可读性方面为 web 开发者消除了大多数差劲的选项。这个其实有点类似于 Safari 的阅读模式。不幸的是,大部分网站都有很多令人讨厌的繁琐的东西以及难以转换为文本的导航,
+
+[^5]: 易用性和易学性这两者经常容易被搞混。易学性是指学习使用工具的难易程度。而易用性是指工具高效的程度。通常来说,这是要差别的,就想鼠标和菜单栏的差别一样。菜单栏很容易学会,但是却不怎么高效,以致于早期会存在一些键盘的快捷键。除了在 GUI 方面上,Raskin 在很多方面上的观点都很正确。如今,操作系统正在将一些合适的搜索映射到键盘的快捷键上。比如说在 OS X 和 Windows 上,我默认的导航方式就是搜索。Ubuntu 的搜索做的很差劲,如同它的 GUI 一样差劲。
+
+[^6]: 在有网的情况下,[AWS S3][42] 是解决文件存储问题的有效方案。数万亿个对象存在 S3 中,但是从来没有遗失过。大部分提供云存储的服务都是在 S3 上或是模拟 S3 构建的。没人能够拥有 S3 一样的规模,所以我将重要的文件通过 Dropbox 存储在上面。
+
+[^7]: 目前,你可能会想:“这个人和自行车有什么关系?”……我在各个层面上都喜欢自行车。自行车是迄今为止发明的最具机械效率的交通工具。自行车可以是真正美丽的事物。而且,只要注意点的话,自行车可以用一辈子。早在 2001 年,我曾向 Rivendell Bicycle Works 订购了一辆自行车,现在我每次看到那辆自行车依然很高兴,自行车和 Unix 是我接触过的最好的两个发明。对了,还有 Emacs。
+
+[^8]: 这个网站有一个很棒的 Emacs 教程,但不是这个。当我浏览这个页面时,我确实得到了一些对获取高效的 Emacs 配置很重要的知识,但无论怎么说,这都不是个替代品。
+
+[^9]: 20 世纪 80 年代,Jef Raskin 与 Steve Jobs 在 Macintosh 项目上闹翻后, Jef Raskin 又设计了 [Canon Cat 计算机][43]。这台 Cat 计算机是以文档为中心的界面(所有的计算机都应如此),并以一种全新的方式使用键盘,你现在可以用 Emacs 来模仿这种键盘。如果现在有一台现代的,功能强大的 Cat 计算机并配有一个高分辨的显示器和 Unix 系统的话,我立马会用 Mac 来换。[https://youtu.be/o_TlE_U_X3c?t=19s][28]
+
+--------------------------------------------------------------------------------
+
+via: https://blog.fugue.co/2015-11-11-guide-to-emacs.html
+
+作者:[Josh Stella][a]
+译者:[oneforalone](https://github.com/oneforalone)
+校对:[wxy](https://github.com/wxy), [oneforalone](https://github.com/oneforalone)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://blog.fugue.co/authors/josh.html
+[1]:https://blog.fugue.co/2013-10-16-vpc-on-aws-part3.html
+[2]:https://blog.fugue.co/2013-10-02-vpc-on-aws-part2.html
+[3]:http://ww2.fugue.co/2017-05-25_OS_AR_GartnerCoolVendor2017_01-LP-Registration.html
+[4]:https://blog.fugue.co/authors/josh.html
+[5]:https://twitter.com/joshstella
+[6]:https://www.youtube.com/watch?v=khJQgRLKMU0
+[7]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#phb
+[8]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#tufte
+[9]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#interpreter
+[10]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#eww
+[11]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#usability
+[12]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#s3
+[13]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#bicycles
+[14]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#nottutorial
+[15]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#canoncat
+[16]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#phbOrigin
+[17]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#tufteOrigin
+[18]:http://archive.wired.com/wired/archive/2.08/tufte.html
+[19]:http://archive.wired.com/wired/archive/2.08/tufte.html
+[20]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#interpreterOrigin
+[21]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#ewwOrigin
+[22]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#usabilityOrigin
+[23]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#s3Origin
+[24]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#bicyclesOrigin
+[25]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#nottutorialOrigin
+[26]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#canoncatOrigin
+[27]:https://youtu.be/o_TlE_U_X3c?t=19s
+[28]:https://youtu.be/o_TlE_U_X3c?t=19s
+[29]:https://blog.fugue.co/authors/josh.html
+[30]:http://www.huffingtonpost.com/zachary-ehren/soma-isnt-a-drug-san-fran_b_987841.html
+[31]:http://www.campagnolo.com/US/en
+[32]:http://www.businessinsider.com/best-pointy-haired-boss-moments-from-dilbert-2013-10
+[33]:http://www.webopedia.com/TERM/I/interpreter.html
+[34]:http://emacsformacosx.com/
+[35]:http://emacsformacosx.com/
+[36]:http://www.gnu.org/software/emacs/
+[37]:http://www.gnu.org/software/emacs/
+[38]:http://www.huffingtonpost.com/2015/05/29/two-spaces-after-period-debate_n_7455660.html
+[39]:http://practicaltypography.com/one-space-between-sentences.html
+[40]:http://input.fontbureau.com/
+[41]:https://twitter.com/fugueHQ
+[42]:https://baike.baidu.com/item/amazon%20s3/10809744?fr=aladdin
+[43]:https://en.wikipedia.org/wiki/Canon_Cat
diff --git a/published/201812/20171129 TLDR pages Simplified Alternative To Linux Man Pages.md b/published/201812/20171129 TLDR pages Simplified Alternative To Linux Man Pages.md
new file mode 100644
index 0000000000..bca48001bf
--- /dev/null
+++ b/published/201812/20171129 TLDR pages Simplified Alternative To Linux Man Pages.md
@@ -0,0 +1,106 @@
+TLDR 页:Linux 手册页的简化替代品
+==============
+
+[][22]
+
+在终端上使用各种命令执行重要任务是 Linux 桌面体验中不可或缺的一部分。Linux 这个开源操作系统拥有[丰富的命令][23],任何用户都无法全部记住所有这些命令。而使事情变得更复杂的是,每个命令都有自己的一组带来丰富的功能的选项。
+
+为了解决这个问题,人们创建了[手册页][12],(手册 —— man 是 manual 的缩写)。首先,它是用英文写成的,包含了大量关于不同命令的深入信息。有时候,当你在寻找命令的基本信息时,它就会显得有点庞杂。为了解决这个问题,人们创建了[TLDR 页][13]。
+
+### 什么是 TLDR 页?
+
+TLDR 页的 GitHub 仓库将其描述为简化的、社区驱动的手册页集合。在实际示例的帮助下,努力让使用手册页的体验变得更简单。如果还不知道,TLDR 取自互联网的常见俚语:太长没读。
+
+如果你想比较一下,让我们以 `tar` 命令为例。 通常,手册页的篇幅会超过 1000 行。`tar` 是一个归档实用程序,经常与 `bzip` 或 `gzip` 等压缩方法结合使用。看一下它的手册页:
+
+[][14]
+
+而另一方面,TLDR 页面让你只是浏览一下命令,看看它是如何工作的。 `tar` 的 TLDR 页面看起来像这样,并带有一些方便的例子 —— 你可以使用此实用程序完成的最常见任务:
+
+[][15]
+
+让我们再举一个例子,向你展示 TLDR 页面为 `apt` 提供的内容:
+
+[][16]
+
+如上,它向你展示了 TLDR 如何工作并使你的生活更轻松,下面让我们告诉你如何在基于 Linux 的操作系统上安装它。
+
+### 如何在 Linux 上安装和使用 TLDR 页?
+
+最成熟的 TLDR 客户端是基于 Node.js 的,你可以使用 NPM 包管理器轻松安装它。如果你的系统上没有 Node 和 NPM,请运行以下命令:
+
+```
+sudo apt-get install nodejs
+sudo apt-get install npm
+```
+
+如果你使用的是 Debian、Ubuntu 或 Ubuntu 衍生发行版以外的操作系统,你可以根据自己的情况使用`yum`、`dnf` 或 `pacman`包管理器。
+
+现在,通过在终端中运行以下命令,在 Linux 机器上安装 TLDR 客户端:
+
+```
+sudo npm install -g tldr
+```
+
+一旦安装了此终端实用程序,最好在尝试之前更新其缓存。 为此,请运行以下命令:
+
+```
+tldr --update
+```
+
+执行此操作后,就可以阅读任何 Linux 命令的 TLDR 页面了。 为此,只需键入:
+
+```
+tldr
+```
+
+[][17]
+
+你还可以运行其[帮助命令](https://github.com/tldr-pages/tldr-node-client),以查看可与 TLDR 一起使用的各种参数,以获取所需输出。 像往常一样,这个帮助页面也附有例子。
+
+### TLDR 的 web、Android 和 iOS 版本
+
+你会惊喜地发现 TLDR 页不仅限于你的 Linux 桌面。 相反,它也可以在你的 Web 浏览器中使用,可以从任何计算机访问。
+
+要使用 TLDR Web 版本,请访问 [tldr.ostera.io][18] 并执行所需的搜索操作。
+
+或者,你也可以下载 [iOS][19] 和 [Android][20] 应用程序,并随时随地学习新命令。
+
+[][21]
+
+你觉得这个很酷的 Linux 终端技巧很有意思吗? 请尝试一下,让我们知道您的反馈。
+
+--------------------------------------------------------------------------------
+
+via: https://fossbytes.com/tldr-pages-linux-man-pages-alternative/
+
+作者:[Adarsh Verma][a]
+译者:[wxy](https://github.com/wxy)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://fossbytes.com/author/adarsh/
+[1]:https://fossbytes.com/watch-star-wars-command-prompt-via-telnet/
+[2]:https://fossbytes.com/use-stackoverflow-linux-terminal-mac/
+[3]:https://fossbytes.com/single-command-curl-wttr-terminal-weather-report/
+[4]:https://fossbytes.com/how-to-google-search-in-command-line-using-googler/
+[5]:https://fossbytes.com/check-bitcoin-cryptocurrency-prices-command-line-coinmon/
+[6]:https://fossbytes.com/review-torrench-download-torrents-using-terminal-linux/
+[7]:https://fossbytes.com/use-wikipedia-termnianl-wikit/
+[8]:http://www.facebook.com/sharer.php?u=https%3A%2F%2Ffossbytes.com%2Ftldr-pages-linux-man-pages-alternative%2F
+[9]:https://twitter.com/intent/tweet?text=TLDR+pages%3A+Simplified+Alternative+To+Linux+Man+Pages&url=https%3A%2F%2Ffossbytes.com%2Ftldr-pages-linux-man-pages-alternative%2F&via=%40fossbytes14
+[10]:http://plus.google.com/share?url=https://fossbytes.com/tldr-pages-linux-man-pages-alternative/
+[11]:http://pinterest.com/pin/create/button/?url=https://fossbytes.com/tldr-pages-linux-man-pages-alternative/&media=https://fossbytes.com/wp-content/uploads/2017/11/tldr-page-ubuntu.jpg
+[12]:https://fossbytes.com/linux-lexicon-man-pages-navigation/
+[13]:https://github.com/tldr-pages/tldr
+[14]:https://fossbytes.com/wp-content/uploads/2017/11/tar-man-page.jpg
+[15]:https://fossbytes.com/wp-content/uploads/2017/11/tar-tldr-page.jpg
+[16]:https://fossbytes.com/wp-content/uploads/2017/11/tldr-page-of-apt.jpg
+[17]:https://fossbytes.com/wp-content/uploads/2017/11/tldr-kill-command.jpg
+[18]:https://tldr.ostera.io/
+[19]:https://itunes.apple.com/us/app/tldt-pages/id1071725095?ls=1&mt=8
+[20]:https://play.google.com/store/apps/details?id=io.github.hidroh.tldroid
+[21]:https://fossbytes.com/wp-content/uploads/2017/11/tldr-app-ios.jpg
+[22]:https://fossbytes.com/wp-content/uploads/2017/11/tldr-page-ubuntu.jpg
+[23]:https://fossbytes.com/a-z-list-linux-command-line-reference/
diff --git a/sources/tech/20171223 Celebrate Christmas In Linux Way With These Wallpapers.md b/published/201812/20171223 Celebrate Christmas In Linux Way With These Wallpapers.md
similarity index 62%
rename from sources/tech/20171223 Celebrate Christmas In Linux Way With These Wallpapers.md
rename to published/201812/20171223 Celebrate Christmas In Linux Way With These Wallpapers.md
index e59286ddbc..3aa2e6f3ea 100644
--- a/sources/tech/20171223 Celebrate Christmas In Linux Way With These Wallpapers.md
+++ b/published/201812/20171223 Celebrate Christmas In Linux Way With These Wallpapers.md
@@ -1,145 +1,165 @@
[#]: collector: (lujun9972)
-[#]: translator: ( )
-[#]: reviewer: ( )
-[#]: publisher: ( )
+[#]: translator: (jlztan)
+[#]: reviewer: (wxy)
+[#]: publisher: (wxy)
[#]: subject: (Celebrate Christmas In Linux Way With These Wallpapers)
[#]: via: (https://itsfoss.com/christmas-linux-wallpaper/)
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
-[#]: url: ( )
+[#]: url: (https://linux.cn/article-10381-1.html)
-Celebrate Christmas In Linux Way With These Wallpapers
+以 Linux 的方式庆祝圣诞节
======
-It’s the holiday season and many of you might be celebrating Christmas already. From the team of It’s FOSS, I would like to wish you a Merry Christmas and a happy new year.
+当前正是假日季,很多人可能已经在庆祝圣诞节了。祝你圣诞快乐,新年快乐。
-To continue the festive mood, I’ll show you some really awesome [Linux wallpapers][1] on Christmas theme. But before we see that, how about a Christmas Tree in Linux terminal.
+为了延续节日氛围,我将向你展示一些非常棒的圣诞主题的 [Linux 壁纸][1]。在呈现这些壁纸之前,先来看一棵 Linux 终端下的圣诞树。
-### Display Christmas Tree in Linux Terminal
+### 让你的桌面飘雪(针对 GNOME 用户)
-
+- [Let it Snow on Your Linux Desktop](https://youtu.be/1QI1ludzZuA)
-If you want to display an animated Christmas tree in the terminal, you can use the command below:
+如果您在 Ubuntu 18.04 或任何其他 Linux 发行版中使用 GNOME 桌面,您可以使用一个小的 [GNOME 扩展][55]并在桌面上飘雪。
+
+您可以从软件中心或 GNOME 扩展网站获取此 gsnow 扩展。我建议您阅读一些关于[使用 GNOME 扩展][55]的内容。
+
+安装此扩展程序后,您会在顶部面板上看到一个小雪花图标。 如果您单击一次,您会看到桌面屏幕上的小絮状物掉落。
+
+
+
+你可以再次点击该图标来禁止雪花落下。
+
+### 在 Linux 终端下显示圣诞树
+
+
+
+如果你想要在终端里显示一个动画的圣诞树,你可以使用如下命令:
```
curl https://raw.githubusercontent.com/sergiolepore/ChristBASHTree/master/tree-EN.sh | bash
```
-If you don’t want to get it from the internet all the time, you can get the shell script from its GitHub repository, change the permission and run it like a normal shell script.
+要是不想一直从互联网上获取这棵圣诞树,也可以从它的 [GitHub 仓库][2] 中获取对应的 shell 脚本,更改权限之后按照运行普通 shell 脚本的方式运行它。
-[ChristBASHTree][2]
-
-### Display Christmas Tree in Linux terminal using Perl
+### 使用 Perl 在 Linux 终端下显示圣诞树
[![Christmas Tree in Linux terminal by NixCraft][3]][4]
-This trick was originally shared by [NixCraft][5]. You’ll need to install a Perl module for this.
+这个技巧最初由 [NixCraft][5] 分享,你需要为此安装 Perl 模块。
-To be honest, I don’t like using Perl modules because uninstalling them is a real pain. So **use this Perl module knowing that you’ll have to manually remove it**.
+说实话,我不喜欢使用 Perl 模块,因为卸载它们真的很痛苦。所以使用这个 Perl 模块时需谨记,你必须手动移除它。
```
perl -MCPAN -e 'install Acme::POE::Tree'
```
-You can read the original article [here][5] to know more about it.
+你可以阅读 [原文][5] 来了解更多信息。
-## Download Linux Christmas Wallpapers
+### 下载 Linux 圣诞主题壁纸
-All these Linux Christmas wallpapers are created by Mark Riedesel and you can find plenty of other artwork on [his website][6].
+所有这些 Linux 圣诞主题壁纸都是由 Mark Riedesel 制作的,你可以在 [他的网站][6] 上找到很多其他艺术品。
-He has been making such wallpapers almost every year since 2002. Quite understandably some of the earliest wallpapers don’t have modern aspect ratio. I have put them up in reverse chronological order.
+自 2002 年以来,他几乎每年都在制作这样的壁纸。可以理解的是,最早的一些壁纸不具有现代的宽高比。我把它们按时间倒序排列。
-One tiny note. The images displayed here are highly compressed so download the wallpapers from the provided link only.
+注意一个小地方,这里显示的图片都是高度压缩的,因此你要通过图片下方提供的链接进行下载。
+
+![Christmas Linux Wallpaper][56]
+
+*[下载此壁纸][57]*
![Christmas Linux Wallpaper][7]
-[Download This Wallpaper][8]
+*[下载此壁纸][8]*
[![Christmas Linux Wallpapers][9]][10]
-[Download This Wallpaper][11]
+*[下载此壁纸][11]*
[![Christmas Linux Wallpapers][12]][13]
-[Download This Wallpaper][14]
+*[下载此壁纸][14]*
[![Christmas Linux Wallpapers][15]][16]
-[Download This Wallpaper][17]
+*[下载此壁纸][17]*
[![Christmas Linux Wallpapers][18]][19]
-[Download This Wallpaper][20]
+*[下载此壁纸][20]*
[![Christmas Linux Wallpapers][21]][22]
-[Download This Wallpaper][23]
+*[下载此壁纸][23]*
[![Christmas Linux Wallpapers][24]][25]
-[Download This Wallpaper][26]
+*[下载此壁纸][26]*
[![Christmas Linux Wallpapers][27]][28]
-[Download This Wallpaper][29]
+*[下载此壁纸][29]*
[![Christmas Linux Wallpapers][30]][31]
-[Download This Wallpaper][32]
+*[下载此壁纸][32]*
[![Christmas Linux Wallpapers][33]][34]
-[Download This Wallpaper][35]
+*[下载此壁纸][35]*
[![Christmas Linux Wallpapers][36]][37]
-[Download This Wallpaper][38]
+*[下载此壁纸][38]*
[![Christmas Linux Wallpapers][39]][40]
-[Download This Wallpaper][41]
+*[下载此壁纸][41]*
[![Christmas Linux Wallpapers][42]][43]
-[Download This Wallpaper][44]
+*[下载此壁纸][44]*
[![Christmas Linux Wallpapers][45]][46]
-[Download This Wallpaper][47]
+*[下载此壁纸][47]*
[![Christmas Linux Wallpapers][48]][49]
-[Download This Wallpaper][50]
+*[下载此壁纸][50]*
-### Bonus: Linux Christmas carols
+### 福利:Linux 圣诞颂歌
-Here is a bonus for you. Christmas carols Linuxified for Linux lovers like us.
+这是给你的一份福利,给像我们一样的 Linux 爱好者的关于 Linux 的圣诞颂歌。
-In [an article on Computer World][51], [Sandra Henry-Stocker][52] shared such Christmas carols. An excerpt:
+在 [《计算机世界》的一篇文章][51] 中,[Sandra Henry-Stocker][52] 分享了这些圣诞颂歌。摘录片段如下:
-To the tune of: [Chestnuts Roasting on an Open Fire][53]
+这一段用的 [Chestnuts Roasting on an Open Fire][53] 的曲调:
-> Running merrily on open source
+> Running merrily on open source
+>
> With users happy as can be
+>
> We’re using Linux and getting lots done
+
> And happy everything is free
-To the tune of: [The Twelve Days of Christmas][54]
+这一段用的 [The Twelve Days of Christmas][54] 的曲调:
-> On my first day with Linux, my admin gave to me a password and a login ID
+> On my first day with Linux, my admin gave to me a password and a login ID
+>
> On my second day with Linux my admin gave to me two new commands and a password and a login ID
-You can read full carols [here][51].
+在 [这里][51] 阅读完整的颂歌。
-Merry Linux to you!!
+Linux 快乐!
---------------------------------------------------------------------------------
+------
via: https://itsfoss.com/christmas-linux-wallpaper/
作者:[Abhishek Prakash][a]
选题:[lujun9972][b]
-译者:[译者ID](https://github.com/译者ID)
-校对:[校对者ID](https://github.com/校对者ID)
+译者:[jlztan](https://github.com/jlztan)
+校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
@@ -199,3 +219,6 @@ via: https://itsfoss.com/christmas-linux-wallpaper/
[52]: https://twitter.com/bugfarm
[53]: https://www.youtube.com/watch?v=dhzxQCTCI3E
[54]: https://www.youtube.com/watch?v=oyEyMjdD2uk
+[55]: https://itsfoss.com/gnome-shell-extensions/
+[56]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2016/12/ChristmasTux2018.jpeg?w=800&ssl=1
+[57]: http://www.klowner.com/wallery/christmas_tux_2018/download/ChristmasTux2018_4K_3840x2160.png
diff --git a/published/201812/20171223 My personal Email setup - Notmuch, mbsync, postfix and dovecot.md b/published/201812/20171223 My personal Email setup - Notmuch, mbsync, postfix and dovecot.md
new file mode 100644
index 0000000000..12f45713d4
--- /dev/null
+++ b/published/201812/20171223 My personal Email setup - Notmuch, mbsync, postfix and dovecot.md
@@ -0,0 +1,240 @@
+我的个人电子邮件系统设置:notmuch、mbsync、Postfix 和 dovecot
+======
+
+我使用个人电子邮件系统已经相当长的时间了,但是一直没有记录过文档。最近我换了我的笔记本电脑(职业变更导致的变动),我在试图重新创建本地邮件系统时迷茫了。所以这篇文章是一个给自己看的文档,这样我就不用费劲就能再次搭建出来。
+
+### 服务器端
+
+我运行自己的邮件服务器,并使用 Postfix 作为 SMTP 服务器,用 Dovecot 实现 IMAP。我不打算详细介绍如何配置这些设置,因为我的设置主要是通过使用 Jonas 为 Redpill 基础架构创建的脚本完成的。什么是 Redpill?(用 Jonas 自己的话说):
+
+> \ Redpill 是一个概念:一种设置 Debian hosts 去跨组织协作的方式
+>
+> \ 我发展了这个概念,并将其首次用于 Redpill 网中网:redpill.dk,其中涉及到了我自己的网络(jones.dk),我的主要客户的网络(homebase.dk),一个包括 Skolelinux Germany(free-owl.de)的在德国的网络,和 Vasudev 的网络(copyninja.info)
+
+除此之外, 我还有一个 dovecot sieve 过滤,根据邮件的来源,对邮件进行高级分类,将其放到各种文件夹中。所有的规则都存在于每个有邮件地址的账户下的 `~/dovecot.sieve` 文件中。
+
+再次,我不会详细介绍如何设置这些东西,因为这不是我这个帖子的目标。
+
+### 在我的笔记本电脑上
+
+在我的笔记本电脑上,我已经按照 4 个部分设置
+
+ 1. 邮件同步:使用 `mbsync` 命令完成
+ 2. 分类:使用 notmuch 完成
+ 3. 阅读:使用 notmuch-emacs 完成
+ 4. 邮件发送:使用作为中继服务器和 SMTP 客户端运行的 Postfix 完成。
+
+### 邮件同步
+
+邮件同步是使用 `mbsync` 工具完成的, 我以前是 OfflineIMAP 的用户,最近切换到 `mbsync`,因为我觉得它比 OfflineIMAP 的配置更轻量、更简单。该命令是由 isync 包提供的。
+
+配置文件是 `~/.mbsyncrc`。下面是我的例子与一些个人设置。
+
+```
+IMAPAccount copyninja
+Host imap.copyninja.info
+User vasudev
+PassCmd "gpg -q --for-your-eyes-only --no-tty --exit-on-status-write-error --batch --passphrase-file ~/path/to/passphrase.txt -d ~/path/to/mailpass.gpg"
+SSLType IMAPS
+SSLVersion TLSv1.2
+CertificateFile /etc/ssl/certs/ca-certificates.crt
+
+
+IMAPAccount gmail-kamathvasudev
+Host imap.gmail.com
+User kamathvasudev@gmail.com
+PassCmd "gpg -q --for-your-eyes-only --no-tty --exit-on-status-write-error --batch --passphrase-file ~/path/to/passphrase.txt -d ~/path/to/mailpass.gpg"
+SSLType IMAPS
+SSLVersion TLSv1.2
+CertificateFile /etc/ssl/certs/ca-certificates.crt
+
+IMAPStore copyninja-remote
+Account copyninja
+
+IMAPStore gmail-kamathvasudev-remote
+Account gmail-kamathvasudev
+
+MaildirStore copyninja-local
+Path ~/Mail/vasudev-copyninja.info/
+Inbox ~/Mail/vasudev-copyninja.info/INBOX
+
+MaildirStore gmail-kamathvasudev-local
+Path ~/Mail/Gmail-1/
+Inbox ~/Mail/Gmail-1/INBOX
+
+Channel copyninja
+Master :copyninja-remote:
+Slave :copyninja-local:
+Patterns *
+Create Both
+SyncState *
+Sync All
+
+Channel gmail-kamathvasudev
+Master :gmail-kamathvasudev-remote:
+Slave :gmail-kamathvasudev-local:
+# Exclude everything under the internal [Gmail] folder, except the interesting folders
+Patterns * ![Gmail]*
+Create Both
+SyncState *
+Sync All
+```
+
+对上述配置中的一些有趣部分进行一下说明。一个是 PassCmd,它允许你提供 shell 命令来获取帐户的密码。这样可以避免在配置文件中填写密码。我使用 gpg 的对称加密,并在我的磁盘上存储密码。这当然是由 Unix ACL 保护安全的。
+
+实际上,我想使用我的公钥来加密文件,但当脚本在后台或通过 systemd 运行时,解锁文件看起来很困难 (或者说几乎不可能)。如果你有更好的建议,我洗耳恭听:-)。
+
+下一个指令部分是 Patterns。这使你可以有选择地同步来自邮件服务器的邮件。这对我来说真的很有帮助,可以排除所有的 “[Gmail]/ folders” 垃圾目录。
+
+### 邮件分类
+
+一旦邮件到达你的本地设备,我们需要一种方法来轻松地在邮件读取器中读取邮件。我最初的设置使用本地 dovecot 实例提供同步的 Maildir,并在 Gnus 中阅读。这种设置相比于设置所有的服务器软件是有点大题小作,但 Gnus 无法很好地应付 Maildir 格式,这是最好的方法。这个设置也有一个缺点,那就是在你快速搜索邮件时,要搜索大量邮件。而这就是 notmuch 的用武之地。
+
+notmuch 允许我轻松索引上千兆字节的邮件档案而找到我需要的东西。我已经创建了一个小脚本,它结合了执行 `mbsync` 和 `notmuch`。我使用 dovecot sieve 来基于实际上创建在服务器端的 Maildirs 标记邮件。下面是我的完整 shell 脚本,它执行同步分类和删除垃圾邮件的任务。
+
+```
+#!/bin/sh
+
+MBSYNC=$(pgrep mbsync)
+NOTMUCH=$(pgrep notmuch)
+
+if [ -n "$MBSYNC" -o -n "$NOTMUCH" ]; then
+ echo "Already running one instance of mail-sync. Exiting..."
+ exit 0
+fi
+
+echo "Deleting messages tagged as *deleted*"
+notmuch search --format=text0 --output=files tag:deleted |xargs -0 --no-run-if-empty rm -v
+
+echo "Moving spam to Spam folder"
+notmuch search --format=text0 --output=files tag:Spam and \
+ to:vasudev@copyninja.info | \
+ xargs -0 -I {} --no-run-if-empty mv -v {} ~/Mail/vasudev-copyninja.info/Spam/cur
+notmuch search --format=text0 --output=files tag:Spam and
+ to:vasudev-debian@copyninja.info | \
+ xargs -0 -I {} --no-run-if-empty mv -v {} ~/Mail/vasudev-copyninja.info/Spam/cur
+
+
+MDIR="vasudev-copyninja.info vasudev-debian Gmail-1"
+mbsync -Va
+notmuch new
+
+for mdir in $MDIR; do
+ echo "Processing $mdir"
+ for fdir in $(ls -d /home/vasudev/Mail/$mdir/*); do
+ if [ $(basename $fdir) != "INBOX" ]; then
+ echo "Tagging for $(basename $fdir)"
+ notmuch tag +$(basename $fdir) -inbox -- folder:$mdir/$(basename $fdir)
+ fi
+ done
+done
+```
+
+因此,在运行 `mbsync` 之前,我搜索所有标记为“deleted”的邮件,并将其从系统中删除。接下来,我在我的帐户上查找标记为“Spam”的邮件,并将其移动到“Spam”文件夹。你没看错,这些邮件逃脱了垃圾邮件过滤器进入到我的收件箱,并被我亲自标记为垃圾邮件。
+
+运行 `mbsync` 后,我基于它们的文件夹标记邮件(搜索字符串 `folder:`)。这让我可以很容易地得到一个邮件列表的内容,而不需要记住列表地址。
+
+### 阅读邮件
+
+现在,我们已经实现同步和分类邮件,是时候来设置阅读部分。我使用 notmuch-emacs 界面来阅读邮件。我使用 emacs 的 Spacemacs 风格,所以我花了一些时间写了一个私有层,它将我所有的快捷键和分类集中在一个地方,而不会扰乱我的整个 `.spacemacs` 文件。你可以在 [notmuch-emacs-layer 仓库][1] 找到我的私有层的代码。
+
+### 发送邮件
+
+能阅读邮件这还不够,我们也需要能够回复邮件。而这是最近是我感到迷茫的一个略显棘手的部分,以至于不得不写这篇文章,这样我就不会再忘记了。(当然也不必在网络上参考一些过时的帖子。)
+
+我的系统发送邮件使用 Postfix 作为 SMTP 客户端,使用我自己的 SMTP 服务器作为它的中继主机。中继的问题是,它不能是具有动态 IP 的主机。有两种方法可以允许具有动态 IP 的主机使用中继服务器, 一种是将邮件来源的 IP 地址放入 `my_network` 或第二个使用 SASL 身份验证。
+
+我的首选方法是使用 SASL 身份验证。为此,我首先要为每台机器创建一个单独的账户,它将把邮件中继到我的主服务器上。想法是不使用我的主帐户 SASL 进行身份验证。(最初我使用的是主账户,但 Jonas 给出了可行的按账户的想法)
+
+```
+adduser _relay
+```
+
+这里替换 `` 为你的笔记本电脑的名称或任何你正在使用的设备。现在我们需要调整 Postfix 作为中继服务器。因此,在 Postfix 配置中添加以下行:
+
+```
+# SASL authentication
+smtp_sasl_auth_enable = yes
+smtp_tls_security_level = encrypt
+smtp_sasl_tls_security_options = noanonymous
+relayhost = [smtp.copyninja.info]:submission
+smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
+```
+
+因此, 这里的 `relayhost` 是用于将邮件转发到互联网的 Postfix 实例的服务器名称。`submission` 的部分 Postfix 将邮件转发到端口 587(安全端口)。`smtp_sasl_tls_security_options` 设置为不允许匿名连接。这是必须的,以便中继服务器信任你的移动主机,并同意为你转发邮件。
+
+`/etc/postfix/sasl_passwd` 是你需要存储用于服务器 SASL 身份验证的帐户密码的文件。将以下内容放入其中。
+
+```
+[smtp.example.com]:submission user:password
+```
+
+用你已放入 `relayhost` 配置的 SMTP 服务器名称替换 `smtp.example.com`。用你创建的 `_relay` 用户及其密码替换 `user` 和 `passwd`。
+
+若要保护 `sasl_passwd` 文件,并为 Postfix 创建它的哈希文件,使用以下命令。
+
+```
+chown root:root /etc/postfix/sasl_passwd
+chmod 0600 /etc/postfix/sasl_passwd
+postmap /etc/postfix/sasl_passwd
+```
+
+最后一条命令将创建 `/etc/postfix/sasl_passwd.db` 文件,它是你的文件的 `/etc/postfix/sasl_passwd` 的哈希文件,具有相同的所有者和权限。现在重新加载 Postfix,并使用 `mail` 命令检查邮件是否从你的系统中发出。
+
+### Bonus 的部分
+
+好吧,因为我有一个脚本创建以上结合了邮件的同步和分类。我继续创建了一个 systemd 计时器,以定期同步后台的邮件。就我而言,每 10 分钟一次。下面是 `mailsync.timer` 文件。
+
+```
+[Unit]
+Description=Check Mail Every 10 minutes
+RefuseManualStart=no
+RefuseManualStop=no
+
+[Timer]
+Persistent=false
+OnBootSec=5min
+OnUnitActiveSec=10min
+Unit=mailsync.service
+
+[Install]
+WantedBy=default.target
+```
+
+下面是 mailsync.service 服务,这是 mailsync.timer 执行我们的脚本所需要的。
+
+```
+[Unit]
+Description=Check Mail
+RefuseManualStart=no
+RefuseManualStop=yes
+
+[Service]
+Type=oneshot
+ExecStart=/usr/local/bin/mail-sync
+StandardOutput=syslog
+StandardError=syslog
+```
+
+将这些文件置于 `/etc/systemd/user` 目录下并运行以下代码去开启它们:
+
+```
+systemctl enable --user mailsync.timer
+systemctl enable --user mailsync.service
+systemctl start --user mailsync.timer
+```
+
+这就是我从系统同步和发送邮件的方式。我从 Jonas Smedegaard 那里了解到了 afew,他审阅了这篇帖子。因此, 下一步, 我将尝试使用 afew 改进我的 notmuch 配置,当然还会有一个后续的帖子:-)。
+
+--------------------------------------------------------------------------------
+
+via: https://copyninja.info/blog/email_setup.html
+
+作者:[copyninja][a]
+译者:[lixinyuxx](https://github.com/lixinyuxx)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://copyninja.info
+[1]:https://source.copyninja.info/notmuch-emacs-layer.git/
diff --git a/published/201812/20180101 27 open solutions to everything in education.md b/published/201812/20180101 27 open solutions to everything in education.md
new file mode 100644
index 0000000000..48a4f3fa3c
--- /dev/null
+++ b/published/201812/20180101 27 open solutions to everything in education.md
@@ -0,0 +1,91 @@
+27 个全方位的开放式教育解决方案
+======
+
+> 阅读这些 2017 年 Opensource.com 发布的开放如何改进教育和学习的好文章。
+
+
+
+开放式理念 (从开源软件到开放硬件,再到开放原则) 正在改变教育的范式。因此,为了庆祝今年发生的一切,我收集了 2017 年(译注:本文原发布于 2018 年初)在 Opensource.com 上发表的 27 篇关于这个主题的最好的文章。我把它们分成明确的主题,而不是按人气来分类。而且,如果这 27 个故事不能满足你对教育方面开源信息的胃口,那就看看我们的合作文章吧 “[教育如何借助 Linux 和树莓派][30]”。
+
+### 开放对每个人都有好处
+
+1. [书评:《OPEN》探讨了开放性的广泛文化含义][1]:Scott Nesbitt 评价 David Price 的书 《OPEN》 ,该书探讨了 “开放” 不仅仅是技术转变的观点,而是 “我们未来将如何工作、生活和学习”。
+2. [通过开源技能快速开始您的职业生涯][2]: VM (Vicky) Brasseur 指出了如何借助学习开源在工作群体中脱颖而出。这个建议不仅仅是针对程序员的;设计师、作家、营销人员和其他创意专业人士也对开源的成功至关重要。
+3. [研究生学位可以让你跳槽到开源职位][3]:引用的研究表明会 Linux 技能会带来更高的薪水, Joshua Pearce 说对开源的熟练和研究生学位是无与伦比的职业技能组合。
+4. [彻底改变了宾夕法尼亚的学校文化的三种实践][4]:Charlie Reisinger 向我们展示了开放式实践是如何在宾夕法尼亚州的一个学区创造一种更具包容性、敏捷性和开放性的文化的。Charlie 说,这不仅仅是为了省钱;该区还受益于 “开放式领导原则,促进师生创新,帮助更好地吸引社区,创造一个更有活力和包容性的学习社区”。
+5. [使用开源工具促使学生进步的 15 种方法][5]:我写了开源是如何让学生自由探索、补拙和学习的,不管他们是在学习基本的数字化素养,还是通过有趣的项目来扩展这些技能。
+6. [开发人员有机会编写好的代码][6]:开源往往是对社会有益的项目的支柱。正如 Benetech Labs 副总裁 Ahn Bui 在这次采访中指出的那样:“建立开放数据标准是打破数据孤岛不可或缺的一步。这些开放标准将为互操作性提供基础,进而转化为更多的组织共同建设,往往更具成本效益。最终目标是以同样的成本甚至更低的成本为更多的人服务。”
+
+### 用于再融合和再利用的开放式教育资源
+
+1. [学术教员可以和维基百科一起教学吗?][7]:Wiki Ed 的项目总监 LiAnna Davis 讨论开放式教育资源 (OER) ,如 Wiki Ed,是如何提供高质量且经济实惠的开源学习资源作为课堂教学工具。
+2. [书本内外?开放教育资源的状态][8]:Cable Green 是 Creative Common 开放教育主管,分享了高等教育中教育面貌是如何变化的,以及 Creative Common 正在采取哪些措施来促进教育。
+3. [急需符合标准的课程的学校系统找到了希望][9]:Karen Vaites 是 Open Up Resources 社区布道师和首席营销官,谈论了非营利组织努力为 K-12 学校提供开放的、标准一致的课程。
+4. [夏威夷大学如何解决当今高等教育的问题][10]:夏威夷大学 Manoa 分校的教育技术专家 Billy Meinke 表示,在大学课程中过渡到 ORE 将 “使教师能够控制他们教授的内容,我们预计这将为他们节省学生的费用。”
+5. [开放式课程如何削减高等教育成本][11]:塞勒学院的教育总监 Devon Ritter 报告了塞勒学院是如何建立以公开许可内容为基础的大学学分课程,目的是使更多的人能够负担得起和获得高等教育。
+6. [开放教育资源运动在提速][12]:Alexis Clifton 是纽约州立大学的 OER 服务的执行董事,描述了纽约 800 万美元的投资如何刺激开放教育的增长,并使大学更实惠。
+7. [开放项目合作,从小学到大学教室][13]:来自杜克大学的 Aria F. Chernik 探索 OSPRI (开源教育学的研究与创新), 这是杜克大学和红帽的合作,旨在建立一个 21 世纪的,开放设计的 preK-12 学习生态系统。
+8. [Perma.cc 将阻止学术链接腐烂][14]::弗吉尼亚理工大学的 Phillip Young 写的关于 Perma.cc 的文章,这种一种“链接腐烂”的解决方案,在学术论文中的超链接随着时间的推移而消失或变化的概览很高。
+9. [开放教育:学生如何通过创建开放教科书来节省资金][15]:OER 先驱 Robin DeRosa 谈到 “引入公开许可教科书的自由,以及教育和学习应结合包容性生态系统,以增强公益的总体理念”。
+
+### 课堂上的开源工具
+
+1. [开源棋盘游戏如何拯救地球][16]:Joshua Pearce 写的关于拯救地球的一个棋盘游戏,这是一款让学生在玩乐和为创客社区做出贡献的同时解决环境问题的棋盘游戏。
+2. [一个教孩子们如何阅读的新 Android 应用程序][17]:Michael Hall 谈到了他在儿子被诊断为自闭症后为他开发的儿童识字应用 Phoenicia,以及良好编码的价值,和为什么用户测试比你想象的更重要。
+3. [8 个用于教育的开源 Android 应用程序][18]:Joshua Allen Holm 推荐了 8 个来自 F-Droid 软件库的开源应用,使我们可以将智能手机用作学习工具。
+4. [MATLA B的 3 种开源替代方案][19]:Jason Baker 更新了他 2016 年的开源数学计算软件调查报告,提供了 MATLAB 的替代方案,这是数学、物理科学、工程和经济学中几乎无处不在的昂贵的专用解决方案。
+5. [SVG 与教孩子编码有什么关系?][20]:退休工程师 Jay Nick 谈论他如何使用艺术作为一种创新的方式,向学生介绍编码。他在学校做志愿者,使用 SVG 来教授一种结合数学和艺术原理的编码方法。
+6. [5 个破灭的神话:在高等教育中使用开源][21]: 拥有德克萨斯理工大学美术博士学位的 Kyle Conway 分享他在一个由专有解决方案统治的世界中使用开源工具的经验。 Kyle 说有一种偏见,反对在计算机科学以外的学科中使用开源:“很多人认为非技术专业的学生不能使用 Linux,他们对在高级学位课程中使用 Linux 的人做出了很多假设……嗯,这是有可能的,我就是证明。”
+7. [大学开源工具列表][22]:Aaron Cocker 概述了他在攻读计算机科学本科学位时使用的开源工具 (包括演示、备份和编程软件)。
+8. [5 个可帮助您学习优秀 KDE 应用程序][23]:Zsolt Szakács 提供五个 KDE 应用程序,可以帮助任何想要学习新技能或培养现有技能的人。
+
+### 在教室编码
+
+1. [如何尽早让下一代编码][24]:Bryson Payne 说我们需要在高中前教孩子们学会编码: 到了九年级,80% 的女孩和 60% 的男孩已经从 STEM 职业中自选。但他建议,这不仅仅是就业和缩小 IT 技能差距的问题。“教一个年轻人编写代码可能是你能给他们的最改变生活的技能。而且这不仅仅是一个职业提升者。编码是关于解决问题,它是关于创造力,更重要的是,它是提升能力”。
+2. [孩子们无法在没有计算机的情况下编码][25]:Patrick Masson 推出了 FLOSS 儿童桌面计划, 该计划教授服务不足学校的学生使用开源软件 (如 Linux、LibreOffice 和 GIMP) 重新利用较旧的计算机。该计划不仅为破旧或退役的硬件注入新的生命,还为学生提供了重要的技能,而且还为学生提供了可能转化为未来职业生涯的重要技能。
+3. [如今 Scratch 是否能像 80 年代的 LOGO 语言一样教孩子们编码?][26]:Anderson Silva 提出使用 [Scratch][27] 以激发孩子们对编程的兴趣,就像在 20 世纪 80 年代开始使用 LOGO 语言时一样。
+4. [通过这个拖放框架学习Android开发][28]:Eric Eslinger 介绍了 App Inventor,这是一个编程框架,用于构建 Android 应用程序使用可视块语言(类似 Scratch 或者 [Snap][29])。
+
+在这一年里,我们了解到,教育领域的各个方面都有了开放的解决方案,我预计这一主题将在 2018 年及以后继续下去。在未来的一年里,你是否希望 Opensource.com 涵盖开放式的教育主题?如果是, 请在评论中分享你的想法。
+
+--------------------------------------------------------------------------------
+
+via: https://opensource.com/article/18/1/best-open-education
+
+作者:[Don Watkins][a]
+译者:[lixinyuxx](https://github.com/lixinyuxx)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://opensource.com/users/don-watkins
+[1]:https://opensource.com/article/17/7/book-review-open
+[2]:https://opensource.com/article/17/8/jump-start-your-career
+[3]:https://opensource.com/article/17/1/grad-school-open-source-academic-lab
+[4]:https://opensource.com/article/17/7/open-school-leadership
+[5]:https://opensource.com/article/17/7/empower-students-open-source-tools
+[6]:https://opensource.com/article/17/3/interview-anh-bui-benetech-labs
+[7]:https://opensource.com/article/17/1/Wiki-Education-Foundation
+[8]:https://opensource.com/article/17/2/future-textbooks-cable-green-creative-commons
+[9]:https://opensource.com/article/17/1/open-up-resources
+[10]:https://opensource.com/article/17/2/interview-education-billy-meinke
+[11]:https://opensource.com/article/17/7/college-alternatives
+[12]:https://opensource.com/article/17/10/open-educational-resources-alexis-clifton
+[13]:https://opensource.com/article/17/3/education-should-be-open-design
+[14]:https://opensource.com/article/17/9/stop-link-rot-permacc
+[15]:https://opensource.com/article/17/11/creating-open-textbooks
+[16]:https://opensource.com/article/17/7/save-planet-board-game
+[17]:https://opensource.com/article/17/4/phoenicia-education-software
+[18]:https://opensource.com/article/17/8/8-open-source-android-apps-education
+[19]:https://opensource.com/alternatives/matlab
+[20]:https://opensource.com/article/17/5/coding-scalable-vector-graphics-make-steam
+[21]:https://opensource.com/article/17/5/how-linux-higher-education
+[22]:https://opensource.com/article/17/6/open-source-tools-university-student
+[23]:https://opensource.com/article/17/6/kde-education-software
+[24]:https://opensource.com/article/17/8/teach-kid-code-change-life
+[25]:https://opensource.com/article/17/9/floss-desktops-kids
+[26]:https://opensource.com/article/17/3/logo-scratch-teach-programming-kids
+[27]:https://scratch.mit.edu/
+[28]:https://opensource.com/article/17/8/app-inventor-android-app-development
+[29]:http://snap.berkeley.edu/
+[30]:https://opensource.com/article/17/12/best-opensourcecom-linux-and-raspberry-pi-education
diff --git a/translated/talk/20180104 How Creative Commons benefits artists and big business.md b/published/201812/20180104 How Creative Commons benefits artists and big business.md
similarity index 52%
rename from translated/talk/20180104 How Creative Commons benefits artists and big business.md
rename to published/201812/20180104 How Creative Commons benefits artists and big business.md
index c04ed4c240..aefc804479 100644
--- a/translated/talk/20180104 How Creative Commons benefits artists and big business.md
+++ b/published/201812/20180104 How Creative Commons benefits artists and big business.md
@@ -1,42 +1,49 @@
-知识共享是怎样造福艺术家和大企业的
+你所不知道的知识共享(CC)
======
+
+> 知识共享为艺术家提供访问权限和原始素材。大公司也从中受益。
+

-我毕业于电影学院,毕业后在一所电影学校教书,之后进入一家主流电影工作室,我一直在从事电影相关的工作。创造业的方方面面面临着同一个问题:创造者需要原材料。有趣的是,自由文化运动提出了解决方案,具体来说是在自由文化运动中出现的知识共享组织。
+我毕业于电影学院,毕业后在一所电影学校教书,之后进入一家主流电影工作室,我一直在从事电影相关的工作。创意产业的方方面面面临着同一个问题:创作者需要原材料。有趣的是,自由文化运动提出了解决方案,具体来说是在自由文化运动中出现的知识共享组织。
-###知识共享能够为我们提供展示片段和小样
+### 知识共享能够为我们提供展示片段和小样
-和其他事情一样,创造力也需要反复练习。幸运的是,在我刚开始接触电脑时,就在一本渲染工场的专业杂志中接触到了开源这个存在。当时我并不理解所谓的“开源”是什么,但我知道只有开源工具能帮助我在领域内稳定发展。对我来说,知识共享也是如此。知识共享可以为艺术家们提供充满丰富艺术资源的工作室。
+和其他事情一样,创造力也需要反复练习。幸运的是,在我刚开始接触电脑时,就在一本关于渲染工场的专业杂志中接触到了开源这个存在。当时我并不理解所谓的“开源”是什么,但我知道只有开源工具能帮助我在领域内稳定发展。对我来说,知识共享也是如此。知识共享可以为艺术家们提供充满丰富艺术资源的工作室。
-我在电影学院任教时,经常需要给学生们准备练习编辑、录音、拟音、分级、评分的脚本。在 Jim Munroe 的独立作品 [Infest Wisely][1] 中和 [Vimeo][2] 上的知识共享里我总能找到我想要的。这些写实的脚本覆盖内容十分广泛,从独立影院出品到昂贵的高质的升降镜头(一般都会用无人机代替)都有。
+我在电影学院任教时,经常需要给学生们准备练习编辑、录音、拟音、分级、评分的示例录像。在 Jim Munroe 的独立作品 [Infest Wisely][1] 中和 [Vimeo][2] 上的知识共享内容里我总能找到我想要的。这些逼真的镜头覆盖内容十分广泛,从独立制作到昂贵的高品质的升降镜头(一般都会用无人机代替)都有。
-对实验艺术来说,确有无尽可能。知识共享提供了丰富的底片材料,这些材料可以用来整合,混剪等等,可以满足一位视觉先锋能够想到的任何用途。
+
-在接触知识共享之前,如果我想要使用写实脚本,我只能用之前的学生和老师拍摄的或者直接使用版权库里的脚本,但这些都有很多局限性。
+对实验主义艺术来说,确有无尽可能。知识共享提供了丰富的素材,这些材料可以用来整合、混剪等等,可以满足一位视觉先锋能够想到的任何用途。
-###坚守版权的底线很重要
+在接触知识共享之前,如果我想要使用写实镜头,如果在大学,只能用之前的学生和老师拍摄的或者直接使用版权库里的镜头,或者使用有受限的版权保护的镜头。
-知识共享同样能够创造经济效益。在某大型计算机公司的渲染工场工作时,我负责在某些硬件设施上测试渲染的运行情况,而这个测试时刻面临着被搁置的风险。做这些测试时,我用的都是[大雄兔][3]的资源,因为这个电影和它的组件都是可以免费使用和分享的。如果没有这个小短片,在接触写实资源之前我都没法完成我的实验,因为对于一个计算机公司来说,雇佣一只3D艺术家来应召布景是不太现实的。
+### 坚守版权的底线很重要
-令我震惊的是,与开源类似,知识共享已经用我们难以想象的方式支撑起了大公司。知识共享的使用或有或无地影响着公司的日常程序,但它填补了不足,让工作流程顺利进行。我没见到谁在他们的书中将流畅工作归功于知识共享的应用,但它确实无处不在。
+知识共享同样能够创造经济效益。在某大型计算机公司的渲染工场工作时,我负责在某些硬件设施上测试渲染的运行情况,而这个测试时刻面临着被搁置的风险。做这些测试时,我用的都是[大雄兔][3]的资源,因为这个电影和它的组件都是可以免费使用和分享的。如果没有这个小短片,在接触写实资源之前我都没法完成我的实验,因为对于一个计算机公司来说,雇佣一只 3D 艺术家来按需布景是不太现实的。
-我也见过一些开放版权的电影,比如[辛特尔][4],在最近的电视节目中播放了它的短片,那时的电视比现在的网络媒体要火得多。
+令我震惊的是,与开源类似,知识共享已经用我们难以想象的方式支撑起了大公司。知识共享的使用可能会也可能不会影响公司的日常流程,但它填补了不足,让工作流程顺利进行。我没见到谁在他们的书中将流畅工作归功于知识共享的应用,但它确实无处不在。
-###知识共享可以提供大量原材料
+
-艺术家需要原材料。画家需要颜料,画笔和画布。雕塑家需要陶土和工具。数字内容编辑师需要数字内容,无论它是剪贴画还是音效或者是电子游戏里的成品精灵。
+我也见过一些开放版权的电影,比如[辛特尔][4],在最近的电视节目中播放了它的短片,电视的分辨率已经超过了标准媒体。
+
+### 知识共享可以提供大量原材料
+
+艺术家需要原材料。画家需要颜料、画笔和画布。雕塑家需要陶土和工具。数字内容编辑师需要数字内容,无论它是剪贴画还是音效或者是电子游戏里的现成的精灵。
数字媒介赋予了人们超能力,让一个人就能完成需要一组人员才能完成的工作。事实上,我们大部分都好高骛远。我们想做高大上的项目,想让我们的成果不论是视觉上还是听觉上都无与伦比。我们想塑造的是宏大的世界,紧张的情节,能引起共鸣的作品,但我们所拥有的时间精力和技能与之都不匹配,达不到想要的效果。
-是知识共享再一次拯救了我们,用 [Freesound.org][5], [Openclipart.org][6], [OpenGameArt.org][7] 等等网站上那些细小的开放版权艺术材料。通过知识共享,艺术家可以使用各种他们自己没办法创造的原材料,来完成他们原本完不成的工作。
+是知识共享再一次拯救了我们,在 [Freesound.org][5]、 [Openclipart.org][6]、 [OpenGameArt.org][7] 等等网站上都有大量的开放版权艺术材料。通过知识共享,艺术家可以使用各种他们自己没办法创造的原材料,来完成他们原本完不成的工作。
-最神奇的是,不用自己投资,你放在网上给大家使用的原材料就能变成精美的作品,而这是你从没想过的。我在知识共享上面分享了很多音乐素材,它们现在用于无数的专辑和电子游戏里。有些人用了我的材料会通知我,有些是我自己发现的,所以这些材料的应用可能比我知道的还有多得多。有时我会偶然看到我亲手画的标志出现在我从没听说过的软件里。我见到过我为[开源网站][8]写的文章在别处发表,有的是论文的参考文献,白皮书或者参考资料中。
+最神奇的是,不用自己投资,你放在网上给大家使用的原材料就能变成精美的作品,而这是你从没想过的。我在知识共享上面分享了很多音乐素材,它们现在用于无数的专辑和电子游戏里。有些人用了我的材料会通知我,有些是我自己发现的,所以这些材料的应用可能比我知道的还有多得多。有时我会偶然看到我亲手画的标志出现在我从没听说过的软件里。我见到过我为 [Opensource.com][8] 写的文章在别处发表,有的是论文的参考文献,白皮书或者参考资料中。
-###知识共享所代表的自由文化也是一种文化
+### 知识共享所代表的自由文化也是一种文化
“自由文化”这个说法过于累赘,文化,从概念上来说,是一个有机的整体。在这种文化中社会逐渐成长发展,从一个人到另一个。它是人与人之间的互动和思想交流。自由文化是自由缺失的现代世界里的特殊产物。
-如果你也想对这样的局限进行反抗,想把你的思想、作品,你自己的文化分享给全世界的人,那么就来和我们一起,使用知识共享吧!
+如果你也想对这样的局限进行反抗,想把你的思想、作品、你自己的文化分享给全世界的人,那么就来和我们一起,使用知识共享吧!
--------------------------------------------------------------------------------
@@ -44,7 +51,7 @@ via: https://opensource.com/article/18/1/creative-commons-real-world
作者:[Seth Kenlon][a]
译者:[Valoniakim](https://github.com/Valoniakim)
-校对:[校对者ID](https://github.com/校对者ID)
+校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
diff --git a/published/201812/20180128 Getting Linux Jobs.md b/published/201812/20180128 Getting Linux Jobs.md
new file mode 100644
index 0000000000..9bfaf0e1e5
--- /dev/null
+++ b/published/201812/20180128 Getting Linux Jobs.md
@@ -0,0 +1,95 @@
+Linux 求职建议
+======
+
+通过对招聘网站数据的仔细研究,我们发现,即使是非常有经验的 Linux 程序员,也会在面试中陷入困境。
+
+这就导致了很多优秀并且有经验的人无缘无故地找不到合适的工作,因为如今的就业市场需要我们有一些手段来提高自己的竞争力。
+
+我有两个同事和一个表哥,他们都有 RedHat 认证,管理过比较大的服务器机房,也都收到过前雇主的认真推荐。
+
+可是,在他们应聘的时候,所有的这些证书、本身的能力、工作经验好像都没有起到任何作用,他们所面对的招聘广告是某人从技术词汇中临时挑选的一些“技能片段”所组成的。
+
+现如今,礼貌变得过时了,**不回应**变成了发布招聘广告的公司的新沟通方式。
+
+这同样也意味着大多公司的招聘或者人事可能会**错过**非常优秀的应聘者。
+
+我之所以敢说的如此肯定,是因为现在招聘广告大多数看上去都非常的滑稽。
+
+[Reallylinux.com][3] 另一位特约撰稿人 Walter ,发表过一篇关于 [招聘广告疯掉了][4] 的文章。
+
+他说的也许是对的,可是我认为 Linux 工作应聘者可以通过注意招聘广告的**三个关键点**避免落入陷阱。
+
+**首先**,很少会有 Linux 系统管理员的招聘广告只针对 Linux 有要求。
+
+一定要注意很少有 Linux 系统管理员的职位是实际在服务器上跑 Linux的,反而,很多在搜索 “Linux 管理员” 得到的职位实际上是指大量的 *NX 操作系统的。
+
+举个例子,有一则关于 **Linux 管理员** 的招聘广告:
+
+> 该职位需要为建立系统集成提供支持,尤其是 BSD 应用的系统安装...
+
+或者有一些其他的要求:
+
+> 有 Windows 系统管理经验的。
+
+最为讽刺的是,如果你在应聘面试的时候表现出专注于 Linux 的话,你可能不会被聘用。
+
+另外,如果你直接把 Linux 写在你的特长或者专业上,他们可能都不会仔细看你的简历,因为他们根本区分不了 UNIX、BSD、Linux。
+
+最终的结果就是,如果你太老实,只在简历上写了 Linux,你可能会被直接过掉,但是如果你把 Linux 改成 UNIX/Linux 的话,可能会走得更远。
+
+我有两个同事最后修改了他们的简历,然后获得了更好的面试机会,虽然依旧没有被聘用,因为大多数招聘广告其实已经内定人员了,这些招聘信息被放出来仅仅是为了表现出他们有招聘的想法。
+
+**第二点**,公司里唯一在乎系统管理员职位的只有技术主管,其他人包括人事或管理层根本不关心这个。
+
+我记得有一次开会旁听的时候,听见一个执行副总裁把服务器管理人员说成“一毛钱一打的人”,这种想法是多么的奇怪啊。
+
+讽刺的是,等到邮件系统出故障,电话交换机连接时不时会断开,或者核心商业文件从企业内网中消失的时候,这些总裁又是最先打电话给系统管理员的。
+
+或许如果他们不整天在电话留言中说那么多空话,或者不往邮件里塞满妻子的照片和旅行途中的照片的话,服务器可能就不会崩溃。
+
+请注意,招聘 Linux 运维或者服务器管理员的广告被放出来是因为公司**技术层**认为有迫切的需求。你也不需要和人事或者公司高层聊什么,搞清楚谁是招聘的技术经理然后打电话给他们。
+
+你需要直接联系他们因为“有些技术问题”是人事回答不了的,即使你只有 60 秒的时间可以和他们交流,你也必须抓住这个机会和真正有需求并且懂技术的人沟通。
+
+那如果人事的漂亮 MM 不让你直接联系技术怎么办呢?
+
+开始记得问人事一些技术性问题,比如说他们的 Linux 集群是如何建立的,它们运行在独立的虚拟机上吗?这些技术性的问题会让人事变得不耐烦,最后让你有机会问出“我能不能直接联系你们团队的技术人员”。
+
+如果对方的回答是“应该可以”或者“稍后回复你”,那么他们可能已经在两周前就已经计划好了找一个人来填补这个空缺,比如说人事部员工的未婚夫。**他们只是不希望看起来太像裙带主义,而是带有一点利己主义的不确定主义。**
+
+所以一定要记得花点时间弄清楚到底谁是发布招聘广告的直接**技术**负责人,然后和他们聊一聊,这可能会让你少一番胡扯并且让你更有可能应聘成功。
+
+**第三点**,现在的招聘广告很少有完全真实的内容了。
+
+我以前见过一个招聘具有高级别专家也不会有的专门知识的初级系统管理员的广告,他们的计划是列出公司的发展计划蓝图,然后找到应聘者。
+
+在这种情况下,你应聘 Linux 管理员职位应该提供几个关键性信息,例如工作经验和相关证书。
+
+诀窍在于,用这些关键词尽量装点你的简历,以匹配他们的招聘信息,这样他们几乎不可能发现你缺失了哪个关键词。
+
+这并不一定会让你成功找到一份工作,但它可以让你获得一次面试机会,这也算是一个巨大的进步。
+
+通过理解和应用以上三点,或许可以让那些寻求 Linux 管理员工作的人能够比那些只有一线地狱机会的人领先一步。
+
+即使这些建议不能让你马上得到面试机会,你也可以利用这些经验和意识去参加贸易展或公司主办的技术会议等活动。
+
+我强烈建议你们也经常参加这种活动,尤其是当它们比较近的话,可以给你一个扩展人脉的机会。
+
+请记住,如今的职业人脉已经失去了原来的意义了,现在只是可以用来获取“哪些公司实际上在招聘、哪些公司只是为了给股东带来增长的表象而在职位方面撒谎”的小道消息。
+
+
+--------------------------------------------------------------------------------
+
+via: http://reallylinux.com/docs/gettinglinuxjobs.shtml
+
+作者:[Andrea W.Codingly][a]
+译者:[Ryze-Borgia](https://github.com/Ryze-Borgia)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:http://reallylinux.com
+[1]:http://www.reallylinux.com
+[2]:http://reallylinux.com/docs/linuxrecessionproof.shtml
+[3]:http://reallylinux.com
+[4]:http://reallylinux.com/docs/wantadsmad.shtml
diff --git a/published/201812/20180130 Graphics and music tools for game development.md b/published/201812/20180130 Graphics and music tools for game development.md
new file mode 100644
index 0000000000..7e77e30d67
--- /dev/null
+++ b/published/201812/20180130 Graphics and music tools for game development.md
@@ -0,0 +1,179 @@
+用于游戏开发的图形和音乐工具
+======
+> 要在三天内打造一个可玩的游戏,你需要一些快速而稳定的好工具。
+
+
+
+在十月初,我们的俱乐部马歇尔大学的 [Geeks and Gadgets][1] 参加了首次 [Open Jam][2],这是一个庆祝最佳开源工具的游戏 Jam。游戏 Jam 是一种活动,参与者以团队协作的方式来开发有趣的计算机游戏。Jam 一般都很短,仅有三天,并且非常累。Opensource.com 在八月下旬[发布了][3] Open Jam 活动,足有 [45 支游戏][4] 进入到了竞赛中。
+
+我们的俱乐部希望在我们的项目中创建和使用开放源码软件,所以 Open Jam 自然是我们想要参与的 Jam 了。我们提交的游戏是一个实验性的游戏,名为 [Mark My Words][5]。我们使用了多种自由和开放源码 (FOSS) 工具来开发它;在这篇文章中,我们将讨论一些我们使用的工具和我们注意到可能有潜在阻碍的地方。
+
+### 音频工具
+
+#### MilkyTracker
+
+[MilkyTracker][6] 是一个可用于编曲老式视频游戏中的音乐的软件包。它是一种[音乐声道器][7],是一个强大的 MOD 和 XM 文件创建器,带有基于特征网格的模式编辑器。在我们的游戏中,我们使用它来编曲大多数的音乐片段。这个程序最好的地方是,它比我们其它的大多数工具消耗更少的硬盘空间和内存。虽然如此,MilkyTracker 仍然非常强大。
+
+
+
+其用户界面需要一会来习惯,这里有对一些想试用 MilkyTracker 的音乐家的一些提示:
+
+ * 转到 “Config > Misc.” ,设置编辑模式的控制风格为 “MilkyTracker”,这将给你提供几乎全部现代键盘快捷方式。
+ * 用 `Ctrl+Z` 撤销
+ * 用 `Ctrl+Y` 重做
+ * 用空格键切换模式编辑方式
+ * 用退格键删除先前的音符
+ * 用插入键来插入一行
+ * 默认情况下,一个音符将持续作用,直到它在该频道上被替换。你可以明确地结束一个音符,通过使用一个反引号(`)键来插入一个 KeyOff 音符
+ * 在你开始谱写乐曲前,你需要创建或查找采样。我们建议在诸如 [Freesound][9] 或 [ccMixter][10] 这样的网站上查找采用 [Creative Commons][8] 协议的采样,
+
+另外,把 [MilkyTracker 文档页面][11] 放在手边。它含有数不清的教程和手册的链接。一个好的起点是在该项目 wiki 上的 [MilkyTracker 指南][12]。
+
+#### LMMS
+
+我们的两个音乐家使用多用途的现代音乐创建工具 [LMMS][13]。它带有一个绝妙的采样和效果库,以及多种多样的灵活的插件来生成独特的声音。LMMS 的学习曲线令人吃惊的低,在某种程度上是因为其好用的节拍/低音线编辑器。
+
+
+
+我们对于想试试 LMMS 的音乐家有一个建议:使用插件。对于 [chiptune][14]式音乐,我们推荐 [sfxr][15]、[BitInvader][16] 和 [FreeBoy][17]。对于其它风格,[ZynAddSubFX][18] 是一个好的选择。它配备了各种合成仪器,可以根据您的需要进行更改。
+
+### 图形工具
+
+#### Tiled
+
+在开放源码游戏开发中,[Tiled][19] 是一个流行的贴片地图编辑器。我们使用它为来为我们在游戏场景中组合连续的、复古式的背景。
+
+
+
+Tiled 可以导出地图为 XML、JSON 或普通的图片。它是稳定的、跨平台的。
+
+Tiled 的功能之一允许你在地图上定义和放置随意的游戏对象,例如硬币和提升道具,但在 jam 期间我们没有使用它。你需要做的全部是以贴片集的方式加载对象的图像,然后使用“插入平铺”来放置它们。
+
+一般来说,对于需要一个地图编辑器的项目,Tiled 是我们所推荐的软件中一个不可或缺的部分。
+
+#### Piskel
+
+[Piskel][20] 是一个像素艺术编辑器,它的源文件代码以 [Apache 2.0 协议][21] 发布。在这次 Jam 期间,们的大多数的图像资源都使用 Piskel 来处理,我们当然也将在未来的工程中使用它。
+
+在这个 Jam 期间,Piskel 极大地帮助我们的两个功能是洋葱皮和精灵序列图导出。
+
+##### 洋葱皮
+
+洋葱皮功能将使 Piskel 以虚影显示你编辑的动画的前一帧和后一帧的,像这样:
+
+
+
+洋葱皮是很方便的,因为它适合作为一个绘制指引和帮助你在整个动画进程中保持角色的一致形状和体积。 要启用它,只需单击屏幕右上角预览窗口下方的洋葱形图标即可。
+
+
+
+##### 精灵序列图导出
+
+Piskel 将动画导出为精灵序列图的能力也非常有用。精灵序列图是一个包含动画所有帧的光栅图像。例如,这是我们从 Piskel 导出的精灵序列图:
+
+
+
+该精灵序列图包含两帧。一帧位于图像的上半部分,另一帧位于图像的下半部分。精灵序列图通过从单个文件加载整个动画,大大简化了游戏的代码。这是上面精灵序列图的动画版本:
+
+
+
+##### Unpiskel.py
+
+在 Jam 期间,我们很多次想批量转换 Piskel 文件到 PNG 文件。由于 Piskel 文件格式基于 JSON,我们写一个基于 GPLv3 协议的名为 [unpiskel.py][22] 的 Python 小脚本来做转换。
+
+它像这样被调用的:
+
+```
+python unpiskel.py input.piskel
+```
+
+这个脚本将从一个 Piskel 文件(这里是 `input.piskel`)中提取 PNG 数据帧和图层,并将它们各自存储。这些文件采用模式 `NAME_XX_YY.png` 命名,在这里 `NAME` 是 Piskel 文件的缩减名称,`XX` 是帧的编号,`YY` 是层的编号。
+
+因为脚本可以从一个 shell 中调用,它可以用在整个文件列表中。
+
+```
+for f in *.piskel; do python unpiskel.py "$f"; done
+```
+
+### Python、Pygame 和 cx_Freeze
+
+#### Python 和 Pygame
+
+我们使用 [Python][23] 语言来制作我们的游戏。它是一个脚本语言,通常被用于文本处理和桌面应用程序开发。它也可以用于游戏开发,例如像 [Angry Drunken Dwarves][24] 和 [Ren'Py][25] 这样的项目所展示的。这两个项目都使用一个称为 [Pygame][26] 的 Python 库来显示图形和产生声音,所以我们也决定在 Open Jam 中使用这个库。
+
+Pygame 被证明是既稳定又富有特色,并且它对我们创建的街机式游戏来说是很棒的。在低分辨率时,库的速度足够快的,但是在高分辨率时,它只用 CPU 的渲染开始变慢。这是因为 Pygame 不使用硬件加速渲染。然而,开发者可以充分利用 OpenGL 基础设施的优势。
+
+如果你正在寻找一个好的 2D 游戏编程库,Pygame 是值得密切注意的一个。它的网站有 [一个好的教程][27] 可以作为起步。务必看看它!
+
+#### cx_Freeze
+
+准备发行我们的游戏是有趣的。我们知道,Windows 用户不喜欢装一套 Python,并且要求他们来安装它可能很过分。除此之外,他们也可能必须安装 Pygame,在 Windows 上,这不是一个简单的工作。
+
+很显然:我们必须放置我们的游戏到一个更方便的格式中。很多其他的 Open Jam 参与者使用专有的游戏引擎 Unity,它能够使他们的游戏在网页浏览器中来玩。这使得它们非常方便地来玩。便利性是一个我们的游戏中根本不存在的东西。但是,感谢生机勃勃的 Python 生态系统,我们有选择。已有的工具可以帮助 Python 程序员将他们的游戏做成 Windows 上的发布版本。我们考虑过的两个工具是 [cx_Freeze][28] 和 [Pygame2exe][29](它使用 [py2exe][30])。我们最终决定用 cx_Freeze,因为它是跨平台的。
+
+在 cx_Freeze 中,你可以把一个单脚本游戏打包成发布版本,只要在 shell 中运行一个命令,像这样:
+
+```
+cxfreeze main.py --target-dir dist
+```
+
+`cxfreeze` 的这个调用将把你的脚本(这里是 `main.py`)和在你系统上的 Python 解释器捆绑到到 `dist` 目录。一旦完成,你需要做的是手动复制你的游戏的数据文件到 `dist` 目录。你将看到,`dist` 目录包含一个可以运行来开始你的游戏的可执行文件。
+
+这里有使用 cx_Freeze 的更复杂的方法,允许你自动地复制数据文件,但是我们发现简单的调用 `cxfreeze` 足够满足我们的需要。感谢这个工具,我们使我们的游戏玩起来更便利一些。
+
+### 庆祝开源
+
+Open Jam 是庆祝开源模式的软件开发的重要活动。这是一个分析开源工具的当前状态和我们在未来工作中需求的一个机会。对于游戏开发者探求其工具的使用极限,学习未来游戏开发所必须改进的地方,游戏 Jam 或许是最好的时机。
+
+开源工具使人们能够在不损害自由的情况下探索自己的创造力,而无需预先投入资金。虽然我们可能不会成为专业的游戏开发者,但我们仍然能够通过我们的简短的实验性游戏 [Mark My Words][5] 获得一点点体验。它是一个以语言学为主题的游戏,描绘了虚构的书写系统在其历史中的演变。还有很多其他不错的作品提交给了 Open Jam,它们都值得一试。 真的,[去看看][31]!
+
+在本文结束前,我们想要感谢所有的 [参加俱乐部的成员][32],使得这次经历真正的有价值。我们也想要感谢 [Michael Clayton][33]、[Jared Sprague][34] 和 [Opensource.com][35] 主办 Open Jam。简直酷毙了。
+
+现在,我们对读者提出了一些问题。你是一个 FOSS 游戏开发者吗?你选择的工具是什么?务必在下面留下一个评论!
+
+--------------------------------------------------------------------------------
+
+via: https://opensource.com/article/18/1/graphics-music-tools-game-dev
+
+作者:[Charlie Murphy][a]
+译者:[robsean](https://github.com/robsean)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://opensource.com/users/rsg167
+[1]:http://mugeeks.org/
+[2]:https://itch.io/jam/open-jam-1
+[3]:https://opensource.com/article/17/8/open-jam-announcement
+[4]:https://opensource.com/article/17/11/open-jam
+[5]:https://mugeeksalpha.itch.io/mark-omy-words
+[6]:http://milkytracker.titandemo.org/
+[7]:https://en.wikipedia.org/wiki/Music_tracker
+[8]:https://creativecommons.org/
+[9]:https://freesound.org/
+[10]:http://ccmixter.org/view/media/home
+[11]:http://milkytracker.titandemo.org/documentation/
+[12]:https://github.com/milkytracker/MilkyTracker/wiki/MilkyTracker-Guide
+[13]:https://lmms.io/
+[14]:https://en.wikipedia.org/wiki/Chiptune
+[15]:https://github.com/grimfang4/sfxr
+[16]:https://lmms.io/wiki/index.php?title=BitInvader
+[17]:https://lmms.io/wiki/index.php?title=FreeBoy
+[18]:http://zynaddsubfx.sourceforge.net/
+[19]:http://www.mapeditor.org/
+[20]:https://www.piskelapp.com/
+[21]:https://github.com/piskelapp/piskel/blob/master/LICENSE
+[22]:https://raw.githubusercontent.com/MUGeeksandGadgets/MarkMyWords/master/tools/unpiskel.py
+[23]:https://www.python.org/
+[24]:https://www.sacredchao.net/~piman/angrydd/
+[25]:https://renpy.org/
+[26]:https://www.Pygame.org/
+[27]:http://Pygame.org/docs/tut/PygameIntro.html
+[28]:https://anthony-tuininga.github.io/cx_Freeze/
+[29]:https://Pygame.org/wiki/Pygame2exe
+[30]:http://www.py2exe.org/
+[31]:https://itch.io/jam/open-jam-1/entries
+[32]:https://github.com/MUGeeksandGadgets/MarkMyWords/blob/3e1e8aed12ebe13acccf0d87b06d4f3bd124b9db/README.md#credits
+[33]:https://twitter.com/mwcz
+[34]:https://twitter.com/caramelcode
+[35]:https://opensource.com/
diff --git a/published/20180131 For your first HTML code lets help Batman write a love letter.md b/published/201812/20180131 For your first HTML code lets help Batman write a love letter.md
similarity index 100%
rename from published/20180131 For your first HTML code lets help Batman write a love letter.md
rename to published/201812/20180131 For your first HTML code lets help Batman write a love letter.md
diff --git a/translated/talk/20180208 Gathering project requirements using the Open Decision Framework.md b/published/201812/20180208 Gathering project requirements using the Open Decision Framework.md
similarity index 90%
rename from translated/talk/20180208 Gathering project requirements using the Open Decision Framework.md
rename to published/201812/20180208 Gathering project requirements using the Open Decision Framework.md
index ea4dced8f8..41416d110a 100644
--- a/translated/talk/20180208 Gathering project requirements using the Open Decision Framework.md
+++ b/published/201812/20180208 Gathering project requirements using the Open Decision Framework.md
@@ -1,9 +1,11 @@
-使用开放决策框架收集项目需求
+降低项目失败率的三个原则
======
+> 透明和包容性的项目要求可以降低您的失败率。 以下是如何协作收集它们。
+

-众所周知,明确、简洁和可衡量的需求会带来更多成功的项目。一项关于[麦肯锡与牛津大学][1]的大型项目的研究表明:“平均而言,大型 IT 项目超出预算 45%,时间每推移 7%,价值就比预期低 56% “。该研究还表明,造成这种失败的一些原因是“模糊的业务目标,不同步的利益相关者以及过度的返工”。
+众所周知,明确、简洁和可衡量的需求会带来更多成功的项目。一项[麦肯锡与牛津大学][1]的关于大型项目的研究表明:“平均而言,大型 IT 项目超出预算 45%,时间每推移 7%,价值就比预期低 56% 。”该研究还表明,造成这种失败的一些原因是“模糊的业务目标,不同步的利益相关者以及过度的返工。”
业务分析师经常发现自己通过持续对话来构建这些需求。为此,他们必须吸引多个利益相关方,并确保参与者提供明确的业务目标。这样可以减少返工,提高更多项目的成功率。
@@ -29,7 +31,7 @@ via: https://opensource.com/open-organization/18/2/constructing-project-requirem
作者:[Tracy Buckner][a]
译者:[geekpi](https://github.com/geekpi)
-校对:[校对者ID](https://github.com/校对者ID)
+校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
@@ -37,4 +39,4 @@ via: https://opensource.com/open-organization/18/2/constructing-project-requirem
[1]:http://calleam.com/WTPF/?page_id=1445
[2]:https://opensource.com/open-organization/resources/open-decision-framework
[3]:https://opensource.com/open-organization/resources/open-org-definition
-[4]:https://opensource.com/open-organization/16/6/introducing-open-decision-framework
\ No newline at end of file
+[4]:https://opensource.com/open-organization/16/6/introducing-open-decision-framework
diff --git a/translated/tech/20180221 12 useful zypper command examples.md b/published/201812/20180221 12 useful zypper command examples.md
similarity index 86%
rename from translated/tech/20180221 12 useful zypper command examples.md
rename to published/201812/20180221 12 useful zypper command examples.md
index 018c5da7c3..94397cd964 100644
--- a/translated/tech/20180221 12 useful zypper command examples.md
+++ b/published/201812/20180221 12 useful zypper command examples.md
@@ -1,10 +1,11 @@
12 条实用的 zypper 命令范例
======
-zypper 是 Suse Linux 系统的包和补丁管理器,你可以根据下面的 12 条附带输出示例的实用范例来学习 zypper 命令的使用。
+
+`zypper` 是 Suse Linux 系统的包和补丁管理器,你可以根据下面的 12 条附带输出示例的实用范例来学习 `zypper` 命令的使用。
![zypper 命令示例][1]
-Suse Linux 使用 zypper 进行包管理,其是一个由 [ZYpp 包管理引擎][2]提供技术支持的包管理系统。在此篇文章中我们将分享 12 条附带输出示例的实用 zypper 命令,能帮助你处理日常的系统管理任务。
+Suse Linux 使用 `zypper` 进行包管理,其是一个由 [ZYpp 包管理引擎][2]提供的包管理系统。在此篇文章中我们将分享 12 条附带输出示例的实用 `zypper` 命令,能帮助你处理日常的系统管理任务。
不带参数的 `zypper` 命令将列出所有可用的选项,这比参考详细的 man 手册要容易上手得多。
@@ -18,12 +19,12 @@ root@kerneltalks # zypper
--help, -h 帮助
--version, -V 输出版本号
--promptids 输出 zypper 用户提示符列表
- --config, -c 使用制定的配置文件来替代默认的
+ --config, -c 使用指定的配置文件来替代默认的
--userdata 在历史和插件中使用的用户自定义事务 id
--quiet, -q 忽略正常输出,只打印错误信息
--verbose, -v 增加冗长程度
--color
- --no-color 是否启用彩色模式如果 tty 支持
+ --no-color 是否启用彩色模式,如果 tty 支持的话
--no-abbrev, -A 表格中的文字不使用缩写
--table-style, -s 表格样式(整型)
--non-interactive, -n 不询问任何选项,自动使用默认答案
@@ -43,7 +44,7 @@ root@kerneltalks # zypper
--gpg-auto-import-keys 自动信任并导入新仓库的签名密钥
--plus-repo, -p 使用附加仓库
--plus-content 另外使用禁用的仓库来提供特定的关键词
- 尝试 '--plus-content debug' 选项来启用仓库
+ 尝试使用 '--plus-content debug' 选项来启用仓库
--disable-repositories 不从仓库中读取元数据
--no-refresh 不刷新仓库
--no-cd 忽略 CD/DVD 中的仓库
@@ -55,11 +56,11 @@ root@kerneltalks # zypper
--disable-system-resolvables
不读取已安装包
- 命令:
+ 命令:
help, ? 打印帮助
shell, sh 允许多命令
- 仓库管理:
+ 仓库管理:
repos, lr 列出所有自定义仓库
addrepo, ar 添加一个新仓库
removerepo, rr 移除指定仓库
@@ -68,14 +69,14 @@ root@kerneltalks # zypper
refresh, ref 刷新所有仓库
clean 清除本地缓存
- 服务管理:
+ 服务管理:
services, ls 列出所有自定义服务
addservice, as 添加一个新服务
modifyservice, ms 修改指定服务
removeservice, rs 移除指定服务
refresh-services, refs 刷新所有服务
- 软件管理:
+ 软件管理:
install, in 安装包
remove, rm 移除包
verify, ve 确认包依赖的完整性
@@ -83,7 +84,7 @@ root@kerneltalks # zypper
install-new-recommends, inr
安装由已安装包建议一并安装的新包
- 更新管理:
+ 更新管理:
update, up 更新已安装包至更新版本
list-updates, lu 列出可用更新
patch 安装必要的补丁
@@ -91,7 +92,7 @@ root@kerneltalks # zypper
dist-upgrade, dup 进行发行版更新
patch-check, pchk 检查补丁
- 查询:
+ 查询:
search, se 查找符合匹配模式的包
info, if 展示特定包的完全信息
patch-info 展示特定补丁的完全信息
@@ -103,27 +104,28 @@ root@kerneltalks # zypper
products, pd 列出所有可用的产品
what-provides, wp 列出提供特定功能的包
- 包锁定:
+ 包锁定:
addlock, al 添加一个包锁定
removelock, rl 移除一个包锁定
locks, ll 列出当前的包锁定
cleanlocks, cl 移除无用的锁定
- 其他命令:
+ 其他命令:
versioncmp, vcmp 比较两个版本字符串
targetos, tos 打印目标操作系统 ID 字符串
licenses 打印已安装包的证书和 EULAs 报告
download 使用命令行下载指定 rpm 包到本地目录
source-download 下载所有已安装包的源码 rpm 包到本地目录
- 子命令:
+ 子命令:
subcommand 列出可用子命令
输入 'zypper help ' 来获得特定命令的帮助。
```
-##### 如何使用 zypper 安装包
-`zypper` 通过 `in` 或 `install` 开关来在你的系统上安装包。它的用法与 [yum package installation][3] 相同。你只需要提供包名作为参数,包管理器(此处是 zypper)就会处理所有的依赖并与你指定的包一并安装。
+### 如何使用 zypper 安装包
+
+`zypper` 通过 `in` 或 `install` 子命令来在你的系统上安装包。它的用法与 [yum 软件包安装][3] 相同。你只需要提供包名作为参数,包管理器(此处是 `zypper`)就会处理所有的依赖并与你指定的包一并安装。
```
# zypper install telnet
@@ -147,11 +149,11 @@ Checking for file conflicts: ...................................................
以上是我们安装 `telnet` 包时的输出,供你参考。
-推荐阅读 : [在 YUM 和 APT 系统中安装包][3]
+推荐阅读:[在 YUM 和 APT 系统中安装包][3]
-##### 如何使用 zypper 移除包
+### 如何使用 zypper 移除包
-要在 Suse Linux 中擦除或移除包,使用 `zypper` 命令附带 `remove` 或 `rm` 开关。
+要在 Suse Linux 中擦除或移除包,使用 `zypper` 附带 `remove` 或 `rm` 子命令。
```
root@kerneltalks # zypper rm telnet
@@ -167,13 +169,14 @@ After the operation, 113.3 KiB will be freed.
Continue? [y/n/...? shows all options] (y): y
(1/1) Removing telnet-1.2-165.63.x86_64 ..........................................................................................................................[done]
```
+
我们在此处移除了先前安装的 telnet 包。
-##### 使用 zypper 检查依赖或者认证已安装包的完整性
+### 使用 zypper 检查依赖或者认证已安装包的完整性
有时可以通过强制忽略依赖关系来安装软件包。`zypper` 使你能够扫描所有已安装的软件包并检查其依赖性。如果缺少任何依赖项,它将提供你安装或重新安装它的机会,从而保持已安装软件包的完整性。
-使用附带 `verify` 或 `ve` 开关的 `zypper` 命令来检查已安装包的完整性。
+使用附带 `verify` 或 `ve` 子命令的 `zypper` 命令来检查已安装包的完整性。
```
root@kerneltalks # zypper ve
@@ -184,9 +187,10 @@ Reading installed packages...
Dependencies of all installed packages are satisfied.
```
+
在上面的输出中,你能够看到最后一行说明已安装包的所有依赖都已安装完全,并且无需更多操作。
-##### 如何在 Suse Linux 中使用 zypper 下载包
+### 如何在 Suse Linux 中使用 zypper 下载包
`zypper` 提供了一种方法使得你能够将包下载到本地目录而不去安装它。你可以在其他具有同样配置的系统上使用这个已下载的软件包。包会被下载至 `/var/cache/zypp/packages///` 目录。
@@ -206,13 +210,14 @@ total 52
-rw-r--r-- 1 root root 53025 Feb 21 03:17 telnet-1.2-165.63.x86_64.rpm
```
+
你能看到我们使用 `zypper` 将 telnet 包下载到了本地。
-推荐阅读 : [在 YUM 和 APT 系统中只下载包而不安装][4]
+推荐阅读:[在 YUM 和 APT 系统中只下载包而不安装][4]
-##### 如何使用 zypper 列出可用包更新
+### 如何使用 zypper 列出可用包更新
-`zypper` 允许你浏览已安装包的所有可用更新,以便你可以提前计划更新活动。使用 `list-updates` 或 `lu` 开关来显示已安装包的所有可用更新。
+`zypper` 允许你浏览已安装包的所有可用更新,以便你可以提前计划更新活动。使用 `list-updates` 或 `lu` 子命令来显示已安装包的所有可用更新。
```
root@kerneltalks # zypper lu
@@ -229,11 +234,12 @@ v | SLE-Module-Containers12-Updates | containerd | 0.2.5+gitr6
v | SLES12-SP3-Updates | crash | 7.1.8-4.3.1 | 7.1.8-4.6.2 | x86_64
v | SLES12-SP3-Updates | rsync | 3.1.0-12.1 | 3.1.0-13.10.1 | x86_64
```
+
输出特意被格式化以便于阅读。每一列分别代表包所属仓库名称、包名、已安装版本、可用的更新版本和架构。
-##### 在 Suse Linux 中列出和安装补丁
+### 在 Suse Linux 中列出和安装补丁
-使用 `list-patches` 或 `lp` 开关来显示你的 Suse Linux 系统需要被应用的所有可用补丁。
+使用 `list-patches` 或 `lp` 子命令来显示你的 Suse Linux 系统需要被应用的所有可用补丁。
```
root@kerneltalks # zypper lp
@@ -260,9 +266,9 @@ Found 37 applicable patches:
你可以通过发出 `zypper patch` 命令安装所有需要的补丁。
-##### 如何使用 zypper 更新包
+### 如何使用 zypper 更新包
-要使用 zypper 更新包,使用 `update` 或 `up` 开关后接包名。在上述列出的更新命令中,我们知道在我们的服务器上 `rsync` 包更新可用。让我们现在来更新它吧!
+要使用 `zypper` 更新包,使用 `update` 或 `up` 子命令后接包名。在上述列出的更新命令中,我们知道在我们的服务器上 `rsync` 包更新可用。让我们现在来更新它吧!
```
root@kerneltalks # zypper update rsync
@@ -284,9 +290,9 @@ Checking for file conflicts: ...................................................
(1/1) Installing: rsync-3.1.0-13.10.1.x86_64 .....................................................................................................................[done]
```
-##### 在 Suse Linux 上使用 zypper 查找包
+### 在 Suse Linux 上使用 zypper 查找包
-如果你不确定包的全名也不要担心。你可以使用 zypper 附带 `se` 或 `search` 开关并提供查找字符串来查找包。
+如果你不确定包的全名也不要担心。你可以使用 `zypper` 附带的 `se` 或 `search` 子命令并提供查找字符串来查找包。
```
root@kerneltalks # zypper se lvm
@@ -303,14 +309,15 @@ S | Name | Summary | Type
| llvm-devel | Header Files for LLVM | package
| lvm2 | Logical Volume Manager Tools | srcpackage
i+ | lvm2 | Logical Volume Manager Tools | package
- | lvm2-devel | Development files for LVM2 | package
-
+ | lvm2-devel | Development files for LVM2 | package
```
-在上述示例中我们查找了 `lvm` 字符串并得到了如上输出列表。你能在 zypper install/remove/update 命令中使用 `Name` 字段的名字。
-##### 使用 zypper 检查已安装包信息
+在上述示例中我们查找了 `lvm` 字符串并得到了如上输出列表。你能在 `zypper install/remove/update` 命令中使用 `Name` 字段的名字。
+
+### 使用 zypper 检查已安装包信息
+
+你能够使用 `zypper` 检查已安装包的详细信息。`info` 或 `if` 子命令将列出已安装包的信息。它也可以显示未安装包的详细信息,在该情况下,`Installed` 参数将返回 `No` 值。
-你能够使用 zypper 检查已安装包的详细信息。`info` 或 `if` 开关将列出已安装包的信息。它也可以显示未安装包的详细信息,在该情况下,`Installed` 参数将返回 `No` 值。
```
root@kerneltalks # zypper info rsync
Refreshing service 'SMT-http_smt-ec2_susecloud_net'.
@@ -343,9 +350,9 @@ Description :
for backups and mirroring and as an improved copy command for everyday use.
```
-##### 使用 zypper 列出仓库
+### 使用 zypper 列出仓库
-使用 zypper 命令附带 `lr` 或 `repos` 开关列出仓库。
+使用 `zypper` 命令附带 `lr` 或 `repos` 子命令列出仓库。
```
root@kerneltalks # zypper lr
@@ -364,7 +371,7 @@ Repository priorities are without effect. All enabled repositories share the sam
此处你需要检查 `enabled` 列来确定哪些仓库是已被启用的而哪些没有。
-##### 在 Suse Linux 中使用 zypper 添加或移除仓库
+### 在 Suse Linux 中使用 zypper 添加或移除仓库
要添加仓库你需要仓库或 .repo 文件的 URI,否则你会遇到如下错误。
@@ -390,16 +397,17 @@ Priority : 99 (default priority)
Repository priorities are without effect. All enabled repositories share the same priority.
```
-在 Suse 中使用附带 `addrepo` 或 `ar` 开关的 `zypper` 命令添加仓库,后接 URI 以及你需要提供一个别名。
+在 Suse 中使用附带 `addrepo` 或 `ar` 子命令的 `zypper` 命令添加仓库,后接 URI 以及你需要提供一个别名。
+
+要在 Suse 中移除一个仓库,使用附带 `removerepo` 或 `rr` 子命令的 `zypper` 命令。
-要在 Suse 中移除一个仓库,使用附带 `removerepo` 或 `rr` 开关的 `zypper` 命令。
```
root@kerneltalks # zypper removerepo nVidia-Driver-SLE12-SP3
Removing repository 'nVidia-Driver-SLE12-SP3' ....................................................................................................................[done]
Repository 'nVidia-Driver-SLE12-SP3' has been removed.
```
-##### 清除 zypper 本地缓存
+### 清除 zypper 本地缓存
使用 `zypper clean` 命令清除 zypper 本地缓存。
@@ -414,7 +422,7 @@ via: https://kerneltalks.com/commands/12-useful-zypper-command-examples/
作者:[KernelTalks][a]
译者:[cycoe](https://github.com/cycoe)
-校对:[校对者ID](https://github.com/校对者ID)
+校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
diff --git a/published/20180226 -Getting to Done- on the Linux command line.md b/published/201812/20180226 -Getting to Done- on the Linux command line.md
similarity index 100%
rename from published/20180226 -Getting to Done- on the Linux command line.md
rename to published/201812/20180226 -Getting to Done- on the Linux command line.md
diff --git a/published/20180228 Emacs -2- Introducing org-mode.md b/published/201812/20180228 Emacs -2- Introducing org-mode.md
similarity index 100%
rename from published/20180228 Emacs -2- Introducing org-mode.md
rename to published/201812/20180228 Emacs -2- Introducing org-mode.md
diff --git a/published/20180302 Emacs -3- More on org-mode.md b/published/201812/20180302 Emacs -3- More on org-mode.md
similarity index 100%
rename from published/20180302 Emacs -3- More on org-mode.md
rename to published/201812/20180302 Emacs -3- More on org-mode.md
diff --git a/published/20180328 What NASA Has Been Doing About Open Science.md b/published/201812/20180328 What NASA Has Been Doing About Open Science.md
similarity index 100%
rename from published/20180328 What NASA Has Been Doing About Open Science.md
rename to published/201812/20180328 What NASA Has Been Doing About Open Science.md
diff --git a/published/20180331 Emacs -4- Automated emails to org-mode and org-mode syncing.md b/published/201812/20180331 Emacs -4- Automated emails to org-mode and org-mode syncing.md
similarity index 100%
rename from published/20180331 Emacs -4- Automated emails to org-mode and org-mode syncing.md
rename to published/201812/20180331 Emacs -4- Automated emails to org-mode and org-mode syncing.md
diff --git a/translated/tech/20180404 Emacs -5- Documents and Presentations with org-mode.md b/published/201812/20180404 Emacs -5- Documents and Presentations with org-mode.md
similarity index 54%
rename from translated/tech/20180404 Emacs -5- Documents and Presentations with org-mode.md
rename to published/201812/20180404 Emacs -5- Documents and Presentations with org-mode.md
index ad420da202..5082ec2fc9 100644
--- a/translated/tech/20180404 Emacs -5- Documents and Presentations with org-mode.md
+++ b/published/201812/20180404 Emacs -5- Documents and Presentations with org-mode.md
@@ -1,59 +1,58 @@
-Emacs #5: org-mode 之文档与 Presentations
+Emacs 系列(五):Org 模式之文档与演示稿
======
-### 1 org-mode 的输出
+这是 [Emacs 和 Org 模式系列][20]的第五篇。
+
+这篇博文是由 Org 模式的源文件生成的,其有几种格式:[博客页面][21]、[演示稿][22] 和 [PDF 文档][23]。
+
+### 1 Org 模式的输出
#### 1.1 背景
-org-mode 不仅仅只是一个议程生成程序, 它也能输出许多不同的格式: LaTeX,PDF,Beamer,iCalendar(议程),HTML,Markdown,ODT,普通文本,帮助页面(man pages)和其它更多的复杂的格式,比如说网页文件。
+Org 模式不仅仅只是一个议程生成程序,它也能输出许多不同的格式: LaTeX、PDF、Beamer、iCalendar(议程)、HTML、Markdown、ODT、普通文本、手册页和其它更多的复杂的格式,比如说网页文件。
-这也不只是一些事后的想法,这是 org-mode 的设计核心部分并且集成的很好。
+这也不只是一些事后的想法,这是 Org 模式的设计核心部分并且集成的很好。
-一个文件可以同时是源代码,自动生成的输出,任务列表,文档和 presentation。
+这一个文件可以同时是源代码、自动生成的输出、任务列表、文档和展示。
-有些人将 org-mode 作为他们首选的标记格式,甚至对于 LaTeX 文档也是如此。org-mode 手册中的 [section on exporting][13] 有更详细的介绍。
+有些人将 Org 模式作为他们首选的标记格式,甚至对于 LaTeX 文档也是如此。Org 模式手册中的 [输出一节][13] 有更详细的介绍。
#### 1.2 开始
-对于任意的 org-mode 的文档,只要按下 C-c C-e键,就会弹出一个让你选择多种输出格式和选项的菜单。这些选项通常是次键选择,所以很容易设置和执行。例如:要输出一个 PDF 文档,按 C-c C-e l p,要输出 HMTL 格式的, 按 C-c C-e h h。
+对于任意的 Org 模式的文档,只要按下 `C-c C-e` 键,就会弹出一个让你选择多种输出格式和选项的菜单。这些选项通常是次键选择,所以很容易设置和执行。例如:要输出一个 PDF 文档,按 `C-c C-e l p`,要输出 HMTL 格式的, 按 `C-c C-e h h`。
对于所有的输出选项,都有许多可用的设置;详情参见手册。事实上,使用 LaTeX 格式相当于同时使用 LaTeX 和 HTML 模式,在不同的模式中插入任意的前言和设置等。
#### 1.3 第三方插件
-[ELPA][19] 中也包含了许多额外的输出格式,详情参见 [ELPA][19].
+[ELPA][19] 中也包含了许多额外的输出格式,详情参见 [ELPA][19]。
-### 2 org-mode 的 Beamer 演示
+### 2 Org 模式的 Beamer 演示
#### 2.1 关于 Beamer
-[Beamer][14] 是一个生成 presentation 的 LaTeX 环境. 它包括了一下特性:
+[Beamer][14] 是一个生成演示稿的 LaTeX 环境. 它包括了以下特性:
-* 在 presentation 中自动生成结构化的元素(例如 [the Marburg theme][1])。 在 presentation 时,这个特性可以为观众提供了视觉参考。
+* 在演示稿中自动生成结构化的元素(例如 [Marburg 主题][1])。 在演示稿中,这个特性可以为观众提供了视觉参考。
+* 对组织演示稿有很大的帮助。
+* 主题
+* 完全支持 LaTeX
-* 对组织 presentation 有很大的帮助。
+#### 2.2 Org 模式中 Beamer 的优点
-* 主题
-
-* 完全支持 LaTeX
-
-#### 2.2 org-mode 中 Beamer 的优点
-
-在 org-mode 中用 Beamer 有很多好处,总的来说:
-
-* org-mode 很简单而且对可视化支持的很好,同时改变结构可以快速的重组你的材料。
+在 Org 模式中用 Beamer 有很多好处,总的来说:
+* Org 模式很简单而且对可视化支持的很好,同时改变结构可以快速的重组你的材料。
* 与 org-babel 绑定在一起,实时语法高亮源码和内嵌结果。
-
* 语法通常更容易使用。
-我已经完全用 org-mode 和 beamer 替换掉 LibreOffice/Powerpoint/GoogleDocs 的使用。事实上,当我必须使用其中一种工具时,这是相当令人沮丧的,因为它们在可视化表示结构方面远远比不上 org-mode。
+我已经完全用 Org 模式和 beamer 替换掉使用 LibreOffice/Powerpoint/GoogleDocs。事实上,当我必须使用其中一种工具时,这是相当令人沮丧的,因为它们在可视化表示演讲稿结构方面远远比不上 Org 模式。
#### 2.3 标题层次
-org-mode 的 Beamer 会将你文档中的部分(文中定义了标题的)转换成幻灯片。当然,问题是:哪些部分?这是由 H [export setting][15](org-export-headline-levels)决定的。
+Org 模式的 Beamer 会将你文档中的部分(文中定义了标题的)转换成幻灯片。当然,问题是:哪些部分?这是由 H [输出设置][15](`org-export-headline-levels`)决定的。
-针对不同的人,有许多不同的方法。我比较喜欢我的 presentation 这样:
+针对不同的人,有许多不同的方法。我比较喜欢我的演示稿这样:
```
#+OPTIONS: H:2
@@ -64,7 +63,7 @@ org-mode 的 Beamer 会将你文档中的部分(文中定义了标题的)转
#### 2.4 主题和配置
-你可以在 org 文件的顶部来插入几行来配置 Beamer 和 LaTeX。在本文中,例如,你可以这样定义:
+你可以在 Org 模式的文件顶部来插入几行来配置 Beamer 和 LaTeX。在本文中,例如,你可以这样定义:
```
#+TITLE: Documents and presentations with org-mode
@@ -96,13 +95,13 @@ org-mode 的 Beamer 会将你文档中的部分(文中定义了标题的)转
#+BEAMER_HEADER: \setlength{\parskip}{\smallskipamount}
```
-在这里, aspectratio=169 将纵横比设为 16:9, 其它部分都是标准的 LaTeX/Beamer 配置。
+在这里,`aspectratio=169` 将纵横比设为 16:9, 其它部分都是标准的 LaTeX/Beamer 配置。
#### 2.6 缩小 (适应屏幕)
有时你会遇到一些非常大的代码示例,你可能更倾向与将幻灯片缩小以适应它们。
-只要按下 C-c C-c p 将 BEAMER_opt属性设为 shrink=15\.(或者设为更大的 shrink 值)。上一张幻灯片就用到了这个。
+只要按下 `C-c C-c p` 将 `BEAMER_opt` 属性设为 `shrink=15`\。(或者设为更大的 shrink 值)。上一张幻灯片就用到了这个。
#### 2.7 效果
@@ -114,28 +113,24 @@ org-mode 的 Beamer 会将你文档中的部分(文中定义了标题的)转
#### 3.1 交互式的 Emacs 幻灯片
-使用 [org-tree-slide package][17] 这个插件的话, 就可以在 Emacs 的右侧显示幻灯片了。 只要按下 M-x,然后输入 org-tree-slide-mode,回车,然后你就可以用 C-> 和 C-< 在幻灯片之间切换了。
+使用 [org-tree-slide][17] 这个插件的话,就可以在 Emacs 的右侧显示幻灯片了。 只要按下 `M-x`,然后输入 `org-tree-slide-mode`,回车,然后你就可以用 `C->` 和 `C-<` 在幻灯片之间切换了。
-你可能会发现 C-c C-x C-v (即 org-toggle-inline-images)有助于使系统显示内嵌的图像。
+你可能会发现 `C-c C-x C-v` (即 `org-toggle-inline-images`)有助于使系统显示内嵌的图像。
#### 3.2 HTML 幻灯片
-有许多方式可以将 org-mode 的 presentation 导出为 HTML,并有不同级别的 JavaScript 集成。有关详细信息,请参见 org-mode 的 wiki 中的 [non-beamer presentations section][18]。
+有许多方式可以将 Org 模式的演讲稿导出为 HTML,并有不同级别的 JavaScript 集成。有关详细信息,请参见 Org 模式的 wiki 中的 [非 beamer 演讲稿一节][18]。
### 4 更多
#### 4.1 本文中的附加资源
* [orgmode.org beamer tutorial][2]
-
* [LaTeX wiki][3]
-
* [Generating section title slides][4]
-
* [Shrinking content to fit on slide][5]
-
-* 很棒的资源: refcard-org-beamer 详情参见其 [Github repo][6] 中的 PDF 和 .org 文件。
-
+* 很棒的资源: refcard-org-beamer
+ * 详情参见其 [Github repo][6] 中的 PDF 和 .org 文件。
* 很漂亮的主题: [Theme matrix][7]
#### 4.2 下一个 Emacs 系列
@@ -148,9 +143,9 @@ mu4e 邮件!
via: http://changelog.complete.org/archives/9900-emacs-5-documents-and-presentations-with-org-mode
作者:[John Goerzen][a]
-译者:[oneforalone](https://github.com/oneforalone)
-校对:[校对者ID](https://github.com/校对者ID)
选题:[lujun9972](https://github.com/lujun9972)
+译者:[oneforalone](https://github.com/oneforalone)
+校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
@@ -174,3 +169,9 @@ via: http://changelog.complete.org/archives/9900-emacs-5-documents-and-presentat
[17]:https://orgmode.org/worg/org-tutorials/non-beamer-presentations.html#org-tree-slide
[18]:https://orgmode.org/worg/org-tutorials/non-beamer-presentations.html
[19]:https://www.emacswiki.org/emacs/ELPA
+[20]:https://changelog.complete.org/archives/tag/emacs2018
+[21]:https://github.com/jgoerzen/public-snippets/blob/master/emacs/emacs-org-beamer/emacs-org-beamer.org
+[22]:http://changelog.complete.org/archives/9900-emacs-5-documents-and-presentations-with-org-mode
+[23]:https://github.com/jgoerzen/public-snippets/raw/master/emacs/emacs-org-beamer/emacs-org-beamer.pdf
+[24]:https://github.com/jgoerzen/public-snippets/raw/master/emacs/emacs-org-beamer/emacs-org-beamer-document.pdf
+
diff --git a/translated/talk/20180412 A new approach to security instrumentation.md b/published/201812/20180412 A new approach to security instrumentation.md
similarity index 77%
rename from translated/talk/20180412 A new approach to security instrumentation.md
rename to published/201812/20180412 A new approach to security instrumentation.md
index c177e8f5fe..1d11efb63f 100644
--- a/translated/talk/20180412 A new approach to security instrumentation.md
+++ b/published/201812/20180412 A new approach to security instrumentation.md
@@ -1,11 +1,13 @@
-一种新的用于安全检测的方法
+一种新的安全检测的方法
======
+> 不要只测试已有系统,强安全要求更积极主动的策略。
+

我们当中有多少人曾说出过下面这句话:“我希望这能起到作用!”?
-毫无疑问,我们中的大多数人可能都不止一次地说过这句话。这句话不是用来激发信心的,相反它揭示了我们对自身能力和当前正在测试功能的怀疑。不幸的是,这句话非常好地描述了我们传统的安全模型。我们的运营基于这样的假设,并希望我们实施的控制措施——从 web 应用的漏扫到终端上的杀毒软件——防止恶意的病毒和软件进入我们的系统,损坏或偷取我们的信息。
+毫无疑问,我们中的大多数人可能都不止一次地说过这句话。这句话不是用来激发信心的,相反它揭示了我们对自身能力和当前正在测试的功能的怀疑。不幸的是,这句话非常好地描述了我们传统的安全模型。我们的运营基于这样的假设,并希望我们实施的控制措施 —— 从 web 应用的漏扫到终端上的杀毒软件 —— 防止恶意的病毒和软件进入我们的系统,损坏或偷取我们的信息。
渗透测试通过积极地尝试侵入网络、向 web 应用注入恶意代码或者通过发送钓鱼邮件来传播病毒等等这些步骤来避免我们对假设的依赖。由于我们在不同的安全层面上来发现和渗透漏洞,手动测试无法解决漏洞被主动打开的情况。在安全实验中,我们故意在受控的情形下创造混乱,模拟事故的情形,来客观地检测我们检测、阻止这类问题的能力。
@@ -13,15 +15,15 @@
在分布式系统的安全性和复杂性方面,需要反复地重申混沌工程界的一句名言,“希望不是一种有效的策略”。我们多久会主动测试一次我们设计或构建的系统,来确定我们是否已失去对它的控制?大多数组织都不会发现他们的安全控制措施失效了,直到安全事件的发生。我们相信“安全事件不是侦察措施”,而且“希望不要出事也不是一个有效的策略”应该是 IT 专业人士执行有效安全实践的口号。
-工业在传统上强调预防性的安全措施和纵深防御,但我们的任务是通过侦探实验来驱动对安全工具链新的知识和见解。因为过于专注于预防机制,我们很少尝试一次以上地或者年度性地手动测试要求的安全措施,来验证这些控件是否按设计的那样执行。
+行业在传统上强调预防性的安全措施和纵深防御,但我们的任务是通过侦探实验来驱动对安全工具链的新知识和见解。因为过于专注于预防机制,我们很少尝试一次以上地或者年度性地手动测试要求的安全措施,来验证这些控件是否按设计的那样执行。
-随着现代分布式系统中的无状态变量的不断改变,人们很难充分理解他们的系统的行为,因为会随时变化。解决这个问题的一种途径是通过强大的系统性的设备进行检测,对于安全性检测,你可以将这个问题分成两个主要方面,测试,和我们称之为实验的部分。测试是对我们已知部分的验证和评估,简单来说,就是我们在开始找之前,要先弄清楚我们在找什么。另一方面,实验是去寻找获得我们之前并不清楚的见解和知识。虽然测试对于一个成熟的安全团队来说是一项重要实践,但以下示例会有助于进一步地阐述两者之间的差异,并对实验的附加价值提供一个更为贴切的描述。
+随着现代分布式系统中的无状态变量的不断改变,人们很难充分理解他们的系统的行为,因为会随时变化。解决这个问题的一种途径是通过强大的系统性的设备进行检测,对于安全性检测,你可以将这个问题分成两个主要方面:**测试**,和我们称之为**实验**的部分。测试是对我们已知部分的验证和评估,简单来说,就是我们在开始找之前,要先弄清楚我们在找什么。另一方面,实验是去寻找获得我们之前并不清楚的见解和知识。虽然测试对于一个成熟的安全团队来说是一项重要实践,但以下示例会有助于进一步地阐述两者之间的差异,并对实验的附加价值提供一个更为贴切的描述。
### 示例场景:精酿啤酒
思考一个用于接收精酿啤酒订单的 web 服务或者 web 应用。
-这是这家精酿啤酒运输公司的一项重要服务,这些订单来自客户的移动设备,网页,和通过为这家公司精酿啤酒提供服务的餐厅的 API。这项重要服务运行在 AWS EC2 环境上,并且公司认为它是安全的。这家公司去年成功地通过了 PCI 规则,并且每年都会请第三方进行渗透测试,所以公司认为这个系统是安全的。
+这是这家精酿啤酒运输公司的一项重要服务,这些订单来自客户的移动设备、网页,和通过为这家公司精酿啤酒提供服务的餐厅的 API。这项重要服务运行在 AWS EC2 环境上,并且公司认为它是安全的。这家公司去年成功地通过了 PCI 规则,并且每年都会请第三方进行渗透测试,所以公司认为这个系统是安全的。
这家公司有时一天两次部署来进行 DevOps 和持续交付工作,公司为其感到自豪。
@@ -35,10 +37,8 @@
* 该配置会从已选择的目标中随机指定对象,同时端口的范围和数量也会被改变。
* 团队还会设置进行实验的时间并缩小爆破攻击的范围,来确保对业务的影响最小。
* 对于第一次测试,团队选择在他们的测试环境中运行实验并运行一个单独的测试。
- * 在真实的游戏日风格里,团队在预先计划好的两个小时的窗口期内,选择灾难大师来运行实验。在那段窗口期内,灾难大师会在 EC2 实例安全组中的一个上执行这次实验。
- * 一旦游戏日结束,团队就会开始进行一个彻底的、无可指责的事后练习。它的重点在于针对稳定状态和原始假设的实验结果。问题会类似于下面这些:
-
-
+ * 在真实的游戏日风格里,团队在预先计划好的两个小时的窗口期内,选择灾难大师来运行实验。在那段窗口期内,灾难大师会在 EC2 实例安全组中的一个实例上执行这次实验。
+ * 一旦游戏日结束,团队就会开始进行一个彻底的、免于指责的事后练习。它的重点在于针对稳定状态和原始假设的实验结果。问题会类似于下面这些:
### 事后验证问题
@@ -53,24 +53,22 @@
* 获得警报的 SOC 分析师是否能对警报采取措施,还是缺少必要的信息?
* 如果 SOC 确定警报是真实的,那么安全事件响应是否能简单地从数据中进行分类活动?
-
-
我们系统中对失败的承认和预期已经开始揭示我们对系统工作的假设。我们的使命是利用我们所学到的,并更加广泛地应用它。以此来真正主动地解决安全问题,来超越当前传统主流的被动处理问题的安全模型。
随着我们继续在这个新领域内进行探索,我们一定会发布我们的研究成果。如果您有兴趣想了解更多有关研究的信息或是想参与进来,请随时联系 Aaron Rinehart 或者 Grayson Brewer。
特别感谢 Samuel Roden 对本文提供的见解和想法。
-**[看我们相关的文章,是否需要 DevSecOps 这个词?][3]]**
+- [看我们相关的文章:是否需要 DevSecOps 这个词?][3]
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/4/new-approach-security-instrumentation
作者:[Aaron Rinehart][a]
-译者:[hopefully2333](https://github.com/hopefully2333)
-校对:[校对者ID](https://github.com/校对者ID)
选题:[lujun9972](https://github.com/lujun9972)
+译者:[hopefully2333](https://github.com/hopefully2333)
+校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
diff --git a/published/201812/20180419 Migrating to Linux- Network and System Settings.md b/published/201812/20180419 Migrating to Linux- Network and System Settings.md
new file mode 100644
index 0000000000..b9fe12b66e
--- /dev/null
+++ b/published/201812/20180419 Migrating to Linux- Network and System Settings.md
@@ -0,0 +1,114 @@
+迁移到 Linux:网络和系统设置
+======
+
+> 这个系列我们提供了基础知识的概述,以帮助您成功地从另一个操作系统过渡到 Linux;这篇中我们涉及到 Linux 桌面系统上的一些常见设置。
+
+
+
+在这个系列中,我们提供了基础知识的概述,以帮助您成功地从另一个操作系统过渡到 Linux。如果你错过了以前的文章,可以从这访问:
+
+- [第1部分 - 入门介绍][1]
+- [第2部分 - 磁盘、文件和文件系统][2]
+- [第3部分 - 图形操作环境][3]
+- [第4部分 - 命令行][4]
+- [第5部分 - 使用 sudo][5]
+- [第5部分 - 安装软件][6]
+
+Linux 提供了一系列网络和系统设置。在你的桌面计算机上,Linux 允许您调整系统上的任何内容。大多数这些设置都出现在 `/etc` 目录下的纯文本文件中。这里我将介绍你使用桌面 Linux 操作系统的过程中最常用的设置。
+
+大多数设置都能够在“设置”程序里面找到,这些设置可能对于不同的 Linux 发行版有所不同。通常来说,你可以修改背景、调整音量、连接打印机、进行显示设置等。对于这些设置尽管我不会全部谈论,但你可以自己探索。
+
+### 连接互联网
+
+在 Linux 中连接到互联网通常非常简单。如果您通过以太网电缆连接,Linux 通常会在插入电缆时或启动时(如果电缆已连接)获得 IP 地址并自动连接。
+
+如果您使用无线网络,则在大多数发行版中都有一个菜单,可以在指示器面板中或在“设置”中(取决于您的发行版),您可以在其中选择无线网络的 SSID。如果网络受密码保护,它通常会提示您输入密码。然后连接,这个过程相当顺利。
+
+在图形界面您可以通过进入设置来调整网络设置。通常称为“系统设置”或者是“设置”。通常可以轻松找到设置程序,因为它的图标是齿轮或工具图片(图1)。
+
+![Network Settings][8]
+
+*图1: Gnome 桌面网络设置指示器图标。*
+
+### 网络接口名称
+
+在 Linux 下,网络设备有名称。 从历史上看,它们的名称分别为 eth0 和 wlan0 —— 或“以太网”和“无线网络”。 较新的 Linux 系统一直使用看起来更深奥的不同名称,如 enp4s0 和 wlp5s0 。 如果名称以 en 开头,则它是有线以太网接口。 如果它以 wl 开头,那么它就是一个无线接口。 其余的字母和数字反映了设备如何连接到硬件。
+
+### 通过命令行进行网络管理
+
+如果您希望更好地控制网络设置,或者如果您在没有图形桌面的情况下管理网络连接,则还可以从命令行管理网络。
+
+请注意,用于在图形桌面中管理网络的最常用服务是“网络管理器”,而网络管理器通常会覆盖在命令行上进行的设置更改。如果您正在使用网络管理器,最好在其界面中更改您的设置,以防止撤消您从命令行或其他位置所做的更改。
+
+在图形环境中的更改设置与在网络管理器中很类似,您还可以使用名为 `nmtui` 的工具从命令行更改网络管理器设置。`nmtui` 工具提供了您在图形环境中找到的所有设置,但是是在基于文本的半图形界面中提供了该设置,该界面可在命令行上运行(图 2)。
+
+
+
+*图 2:nmtui 界面*
+
+在命令行上,有一个名为 `ifconfig` 的旧工具来管理网络,还有一个名为 `ip` 的新工具。在某些发行版中,`ifconfig` 被认为是不推荐使用的,默认情况下甚至没有安装。在其他发行版上,`ifconfig` 仍可以使用。
+
+以下是一些允许您显示和更改网络设置的命令:
+
+
+
+### 进程和系统信息
+
+在 Windows 系统中,你可以使用任务管理器来查看所有正在运行的程序和服务的列表。你可以停止运行中的程序,并且可以在其中显示的某些选项卡中查看系统性能。
+
+在 Linux 系统下你可以使用命令行或者图形界面中做同样的事情。Linux 系统中根据你的发行版本会有不同的几个可用的图形工具。大多数所共有的工具是“系统监视器”和 KSysGuard。在这些工具中,你可以查看系统性能,查看进程列表甚至是杀死进程(图 3)。
+
+
+
+*图 3:NetHogs 截图*
+
+在这些工具中,你也可以查看系统全局网络流量(图 4)。
+
+![System Monitor][11]
+
+*图 4:Gnome System Monitor 的截图*
+
+### 管理进程和系统使用
+
+您还可以从命令行使用相当多的工具。使用 `ps` 命令可以查看系统中的进程列表。默认情况下,这个命令的结果是显示当前终端会话下的所有进程列表。但是你也可以通过使用各种命令行参数显示其他进程。如果 `ps` 命令不会使用,可以使用命令 `info ps` 或者 `man ps` 获取帮助。
+
+大多数人都希望得到一个进程列表,因为他们想要停止占用过多内存或 CPU 时间的进程。这种情况下有两个非常简单的命令,分别是 `top` 和 `htop` 命令(图 5)。
+
+
+
+*图 5:top 截屏*
+
+`top` 和 `htop` 工具使用效果非常相似。两个命令每秒或者两秒会更新重新排序,这样会把占用 CPU 资源最多的放置在列表顶部。你也可以根据其他资源的使用情况比如内存使用情况来排序。
+
+使用这两个命令时(`top` 和 `htop`),你可以输入 `?` 来获取使用帮助,输入 `q` 来退出程序。使用 `top` 命令你可以按 `k` 键然后输入进程 ID 来杀死某个进程。
+
+使用 `htop` 命令时你可以使用 `↑` `↓` 键来将列表中的一条记录进行高亮显示,按下 `F9` 键会杀死进程(需要回车确认)。
+
+本系列中提供的信息和工具将帮助您开始使用 Linux。 只需一点时间和耐心,您就会感到这非常舒服。
+
+想学习更多 Linux 内容可访问免费的 [Linux 简介][12]课程,此课程来自 Linux 基金会和 edx。
+
+------
+
+via: https://www.linux.com/blog/learn/2018/4/migrating-linux-network-and-system-settings
+
+作者:[John Bonesio][a]
+选题:[lujun9972](https://github.com/lujun9972)
+译者:[ScarboroughCoral](https://github.com/ScarboroughCoral)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]: https://www.linux.com/users/johnbonesio
+[1]: https://linux.cn/article-9212-1.html
+[2]: https://linux.cn/article-9213-1.html
+[3]: https://linux.cn/article-9293-1.html
+[4]: https://linux.cn/article-9565-1.html
+[5]: https://linux.cn/article-9819-1.html
+[6]: https://linux.cn/article-9823-1.html
+[7]: https://www.linux.com/files/images/figure-1png-2
+[8]: https://www.linux.com/sites/lcom/files/styles/rendered_file/public/figure-1_2.png?itok=J-C6q-t5 "Network Settings"
+[9]: https://www.linux.com/licenses/category/used-permission
+[10]: https://www.linux.com/files/images/figure-4png-1
+[11]: https://www.linux.com/sites/lcom/files/styles/rendered_file/public/figure-4_1.png?itok=boI-L1mF "System Monitor"
+[12]: https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux
diff --git a/published/20180420 How To Remove Password From A PDF File in Linux.md b/published/201812/20180420 How To Remove Password From A PDF File in Linux.md
similarity index 100%
rename from published/20180420 How To Remove Password From A PDF File in Linux.md
rename to published/201812/20180420 How To Remove Password From A PDF File in Linux.md
diff --git a/published/201812/20180422 Command Line Tricks For Data Scientists - kade killary.md b/published/201812/20180422 Command Line Tricks For Data Scientists - kade killary.md
new file mode 100644
index 0000000000..e4190cf7dd
--- /dev/null
+++ b/published/201812/20180422 Command Line Tricks For Data Scientists - kade killary.md
@@ -0,0 +1,483 @@
+数据科学家的命令行技巧
+======
+
+
+
+对于许多数据科学家来说,数据操作从始至终就是 Pandas 或 Tidyverse。从理论上讲,这样做没有任何问题。毕竟,这就是这些工具存在的原因。然而,对于像分隔符转换这样的简单任务,这些工具是大材小用了。
+
+立志掌握命令行应该在每个开发人员的学习清单上,特别是数据科学家。学习 shell 的来龙去脉将无可否认地提高你的生产力。除此之外,命令行还是计算领域的一个重要历史课程。例如,awk —— 一种数据驱动的脚本语言。1977 年,在 [Brain Kernighan][1](即传奇的 [K&R 书][2]中 K)的帮助下,awk 首次出现。今天,大约五十年过去了,awk 仍然活跃在每年[新出版的书][3]里面。因此,可以安全地假设对命令行魔法的付出不会很快贬值。
+
+### 我们将涵盖什么
+
+* ICONV
+* HEAD
+* TR
+* WC
+* SPLIT
+* SORT & UNIQ
+* CUT
+* PASTE
+* JOIN
+* GREP
+* SED
+* AWK
+
+### ICONV
+
+文件编码可能会很棘手。现在大部分文件都是 UTF-8 编码的。要了解 UTF-8 背后的一些魔力,请查看这个出色的[视频][4]。尽管如此,有时我们收到的文件不是这种编码。这可能引起对改变编码模式的一些胡乱尝试。这里,`iconv` 是一个拯救者。`iconv` 是一个简单的程序,它将获取采用一种编码的文本并输出采用另一种编码的文本。
+
+```
+# Converting -f (from) latin1 (ISO-8859-1)
+# -t (to) standard UTF_8
+
+iconv -f ISO-8859-1 -t UTF-8 < input.txt > output.txt
+```
+
+实用选项:
+
+* `iconv -l` 列出所有已知编码
+* `iconv -c` 默默丢弃无法转换的字符
+
+### HEAD
+
+如果你是一个 Pandas 重度用户,那么会很熟悉 `head`。通常在处理新数据时,我们想做的第一件事就是了解其内容。这就得启动 Pandas,读取数据然后调用 `df.head()` —— 要说这有点费劲。没有任何选项的 `head` 将打印出文件的前 10 行。`head` 的真正力量在于干净利落的测试操作。例如,如果我们想将文件的分隔符从逗号更改为管道。一个快速测试将是:`head mydata.csv | sed 's/,/|/g'`。
+
+```bash
+# Prints out first 10 lines
+head filename.csv
+
+# Print first 3 lines
+head -n 3 filename.csv
+```
+
+实用选项:
+
+* `head -n` 打印特定行数
+* `head -c` 打印特定字节数
+
+### TR
+
+`tr` 类似于翻译。这个功能强大的实用程序是文件基础清理的主力。理想的用例是替换文件中的分隔符。
+
+```bash
+# Converting a tab delimited file into commas
+cat tab_delimited.txt | tr "\t" "," comma_delimited.csv
+```
+
+`tr` 另一个功能是你可以用内建 `[:class:]` 变量(POSIX 字符类)发挥威力。这些包括了:
+
+- `[:alnum:]` 所有字母和数字
+- `[:alpha:]` 所有字母
+- `[:blank:]` 所有水平空白
+- `[:cntrl:]` 所有控制字符
+- `[:digit:]` 所有数字
+- `[:graph:]` 所有可打印字符,但不包括空格
+- `[:lower:]` 所有小写字母
+- `[:print:]` 所有可打印字符,包括空格
+- `[:punct:]` 所有标点符号
+- `[:space:]` 所有水平或垂直空白
+- `[:upper:]` 所有大写字母
+- `[:xdigit:]` 所有 16 进制数字
+
+你可以将这些连接在一起以组成强大的程序。以下是一个基本的字数统计程序,可用于检查 README 是否被滥用。
+
+```
+cat README.md | tr "[:punct:][:space:]" "\n" | tr "[:upper:]" "[:lower:]" | grep . | sort | uniq -c | sort -nr
+```
+
+另一个使用基本正则表达式的例子:
+
+```
+# Converting all upper case letters to lower case
+cat filename.csv | tr '[A-Z]' '[a-z]'
+```
+
+实用选项:
+
+* `tr -d` 删除字符
+* `tr -s` 压缩字符
+* `\b` 退格
+* `\f` 换页
+* `\v` 垂直制表符
+* `\NNN` 八进制字符
+
+### WC
+
+单词计数。它的价值主要来自其 `-l` 选项,它会给你提供行数。
+
+```
+# Will return number of lines in CSV
+wc -l gigantic_comma.csv
+```
+
+这个工具可以方便地确认各种命令的输出。所以,如果我们在转换文件中的分隔符之后运行 `wc -l`,我们会期待总行数是一样的,如果不一致,我们就知道有地方出错了。
+
+实用选项:
+
+* `wc -c` 打印字节数
+* `wc -m` 打印字符数
+* `wc -L` 打印最长行的长度
+* `wc -w` 打印单词数量
+
+### SPLIT
+
+文件大小的范围可以很广。对于有的任务,拆分文件或许是有好处的,所以使用 `split` 吧。`split` 的基本语法是:
+
+```bash
+# We will split our CSV into new_filename every 500 lines
+split -l 500 filename.csv new_filename_
+# filename.csv
+# ls output
+# new_filename_aaa
+# new_filename_aab
+# new_filename_aa
+```
+
+它有两个奇怪的地方是命名约定和缺少文件扩展名。后缀约定可以通过 `-d` 标志变为数字。要添加文件扩展名,你需要运行以下 `find` 命令。它将通过附加 `.csv` 扩展名来更改当前目录中所有文件的名称,所以小心了。
+
+```bash
+find . -type f -exec mv '{}' '{}'.csv \;
+# ls output
+# filename.csv.csv
+# new_filename_aaa.csv
+# new_filename_aab.csv
+# new_filename_aac.csv
+```
+
+实用选项:
+
+* `split -b N` 按特定字节大小分割
+* `split -a N` 生成长度为 N 的后缀
+* `split -x` 使用十六进制后缀
+
+### SORT & UNIQ
+
+上面两个命令很明显:它们的作用就是字面意思。这两者结合起来可以提供最强大的冲击 (例如,唯一单词的数量)。这是由于 `uniq` 只作用于重复的相邻行。这也是在输出前进行 `sort` 的原因。一个有趣的事情是 `sort -u` 会达到和典型的 `sort file.txt | uniq` 模式一样的结果。
+
+`sort` 对数据科学家来说确实具有潜在的有用能力:能够根据特定列对整个 CSV 进行排序。
+
+```bash
+# Sorting a CSV file by the second column alphabetically
+sort -t"," -k2,2 filename.csv
+
+# Numerically
+sort -t"," -k2n,2 filename.csv
+
+# Reverse order
+sort -t"," -k2nr,2 filename.csv
+```
+
+这里的 `-t` 选项将逗号指定为分隔符,通常假设分隔符是空格或制表符。此外,`-k` 选项是为了确定我们的键。这里的语法是 `-km,n`,`m` 作为开始列,`n` 作为结束列。
+
+实用选项:
+
+* `sort -f` 忽略大小写
+* `sort -r` 反向排序
+* `sort -R` 乱序
+* `uniq -c` 统计出现次数
+* `uniq -d` 只打印重复行
+
+### CUT
+
+`cut` 用于删除列。作为演示,如果我们只想删除第一和第三列。
+
+```bash
+cut -d, -f 1,3 filename.csv
+```
+
+要选择除了第一行外的所有行。
+
+```bash
+cut -d, -f 2- filename.csv
+```
+
+结合其他命令,将 `cut` 用作过滤器。
+
+```bash
+# Print first 10 lines of column 1 and 3, where "some_string_value" is present
+head filename.csv | grep "some_string_value" | cut -d, -f 1,3
+```
+
+查出第二列中唯一值的数量。
+
+```bash
+cat filename.csv | cut -d, -f 2 | sort | uniq | wc -l
+
+# Count occurences of unique values, limiting to first 10 results
+cat filename.csv | cut -d, -f 2 | sort | uniq -c | head
+```
+
+### PASTE
+
+`paste` 是一个带有趣味性功能的特定命令。如果你有两个需要合并的文件,并且它们已经排序好了,`paste` 帮你解决了接下来的步骤。
+
+```bash
+# names.txt
+adam
+john
+zach
+
+# jobs.txt
+lawyer
+youtuber
+developer
+
+# Join the two into a CSV
+paste -d ',' names.txt jobs.txt > person_data.txt
+
+# Output
+adam,lawyer
+john,youtuber
+zach,developer
+```
+
+更多 SQL 式变种,见下文。
+
+### JOIN
+
+`join` 是一个简单的、准切向的 SQL。最大的区别是 `join` 将返回所有列以及只能在一个字段上匹配。默认情况下,`join` 将尝试使用第一列作为匹配键。为了获得不同结果,必须使用以下语法:
+
+```bash
+# Join the first file (-1) by the second column
+# and the second file (-2) by the first
+join -t "," -1 2 -2 1 first_file.txt second_file.txt
+```
+
+标准的 `join` 是内连接。然而,外连接通过 `-a` 选项也是可行的。另一个值得一提的技巧是 `-q` 标志,如果发现有缺失的字段,可用于替换值。
+
+```bash
+# Outer join, replace blanks with NULL in columns 1 and 2
+# -o which fields to substitute - 0 is key, 1.1 is first column, etc...
+join -t"," -1 2 -a 1 -a2 -e ' NULL' -o '0,1.1,2.2' first_file.txt second_file.txt
+```
+
+它不是最用户友好的命令,而是绝望时刻的绝望措施。
+
+实用选项:
+
+* `join -a` 打印不可配对的行
+* `join -e` 替换丢失的输入字段
+* `join -j` 相当于 `-1 FIELD -2 FIELD`
+
+### GREP
+
+`grep` 即 用正则表达式全局搜索并且打印,可能是最有名的命令,并且名副其实。`grep` 很强大,特别适合在大型代码库中查找。在数据科学的王国里,它充当其他命令的提炼机制。虽然它的标准用途也很有价值。
+
+```
+# Recursively search and list all files in directory containing 'word'
+
+grep -lr 'word' .
+
+# List number of files containing word
+
+grep -lr 'word' . | wc -l
+
+```
+
+计算包含单词或模式的总行数。
+
+```
+grep -c 'some_value' filename.csv
+
+# Same thing, but in all files in current directory by file name
+
+grep -c 'some_value' *
+```
+
+对多个值使用“或”运算符: `\|`。
+
+```
+grep "first_value\|second_value" filename.csv
+```
+
+实用选项:
+
+* `alias grep="grep --color=auto"` 使 grep 色彩丰富
+* `grep -E` 使用扩展正则表达式
+* `grep -w` 只匹配整个单词
+* `grep -l` 打印匹配的文件名
+* `grep -v` 非匹配
+
+### 大人物们
+
+`sed` 和 `awk` 是本文中最强大的两个命令。为简洁起见,我不打算详细讨论这两个命令。相反,我将介绍各种能证明其令人印象深刻的力量的命令。如果你想了解更多,[这儿就有一本书][5]是关于它们的。
+
+### SED
+
+`sed` 本质上是一个流编辑器。它擅长替换,但也可以用于所有输出重构。
+
+最基本的 `sed` 命令由 `s/old/new/g` 组成。它的意思是搜索 `old`,全局替换为 `new`。 如果没有 `/g`,我们的命令将在 `old` 第一次出现后终止。
+
+为了快速了解它的功能,我们可以深入了解一个例子。 在以下情景中,你已有以下文件:
+
+```
+balance,name
+$1,000,john
+$2,000,jack
+```
+
+我们可能想要做的第一件事是删除美元符号。`-i` 标志表示原位。`''` 表示零长度文件扩展名,从而覆盖我们的初始文件。理想情况下,你可以单独测试,然后输出到新文件。
+
+```
+sed -i '' 's/\$//g' data.txt
+# balance,name
+# 1,000,john
+# 2,000,jack
+```
+
+接下来,去除 `blance` 列的逗号。
+
+```
+sed -i '' 's/\([0-9]\),\([0-9]\)/\1\2/g' data.txt
+# balance,name
+# 1000,john
+# 2000,jack
+```
+
+最后 jack 有一天决定辞职。所以,再见了,我的朋友。
+
+```
+sed -i '' '/jack/d' data.txt
+# balance,name
+# 1000,john
+```
+
+正如你所看到的,`sed` 有很多强大的功能,但乐趣并不止于此。
+
+### AWK
+
+最好的留在最后。`awk` 不仅仅是一个简单的命令:它是一个成熟的语言。在本文中涉及的所有内容中,`awk` 是目前为止最酷的。如果你感兴趣,这里有很多很棒的资源 —— 看 [这里][6]、[这里][7] 和 [这里][8]。
+
+`awk` 的常见用例包括:
+
+* 文字处理
+* 格式化文本报告
+* 执行算术运算
+* 执行字符串操作
+
+`awk` 可以以最原生的形式并行 `grep`。
+
+```
+awk '/word/' filename.csv
+```
+
+或者更加神奇:将 `grep` 和 `cut` 组合起来。在这里,对于所有带我们指定单词 `word` 的行,`awk` 打印第三和第四列,用 `tab` 分隔。`-F,` 用于指定切分时的列分隔符为逗号。
+
+```bash
+awk -F, '/word/ { print $3 "\t" $4 }' filename.csv
+```
+
+`awk` 内置了许多精巧的变量。比如,`NF` —— 字段数,和 `NR` —— 记录数。要获取文件中的第 53 条记录:
+
+```bash
+awk -F, 'NR == 53' filename.csv
+```
+
+更多的花招是其基于一个或多个值进行过滤的能力。下面的第一个示例将打印第一列等于给定字符串的行的行号和列。
+
+```bash
+awk -F, ' $1 == "string" { print NR, $0 } ' filename.csv
+
+# Filter based off of numerical value in second column
+awk -F, ' $2 == 1000 { print NR, $0 } ' filename.csv
+```
+
+多个数值表达式:
+
+```bash
+# Print line number and columns where column three greater
+# than 2005 and column five less than one thousand
+
+awk -F, ' $3 >= 2005 && $5 <= 1000 { print NR, $0 } ' filename.csv
+```
+
+求出第三列的总和:
+
+```bash
+awk -F, '{ x+=$3 } END { print x }' filename.csv
+```
+
+在第一列等于 `something` 的那些行,求出第三列值的总和。
+
+```bash
+awk -F, '$1 == "something" { x+=$3 } END { print x }' filename.csv
+```
+
+获取文件的行列数:
+
+```bash
+awk -F, 'END { print NF, NR }' filename.csv
+
+# Prettier version
+awk -F, 'BEGIN { print "COLUMNS", "ROWS" }; END { print NF, NR }' filename.csv
+```
+
+打印出现了两次的行:
+
+```bash
+awk -F, '++seen[$0] == 2' filename.csv
+```
+
+删除重复的行:
+
+```bash
+# Consecutive lines
+awk 'a !~ $0; {a=$0}']
+
+# Nonconsecutive lines
+awk '! a[$0]++' filename.csv
+
+# More efficient
+awk '!($0 in a) {a[$0];print}
+```
+
+使用内置函数 `gsub()` 替换多个值。
+
+```bash
+awk '{gsub(/scarlet|ruby|puce/, "red"); print}'
+```
+
+这个 `awk` 命令将组合多个 CSV 文件,忽略标题,然后在最后附加它。
+
+```bash
+awk 'FNR==1 && NR!=1{next;}{print}' *.csv > final_file.csv
+```
+
+需要缩小一个庞大的文件? `awk` 可以在 `sed` 的帮助下处理它。具体来说,该命令根据行数将一个大文件分成多个较小的文件。这个一行脚本将增加一个扩展名。
+
+```bash
+sed '1d;$d' filename.csv | awk 'NR%NUMBER_OF_LINES==1{x="filename-"++i".csv";}{print > x}'
+
+# Example: splitting big_data.csv into data_(n).csv every 100,000 lines
+sed '1d;$d' big_data.csv | awk 'NR%100000==1{x="data_"++i".csv";}{print > x}'
+```
+
+### 结语
+
+命令行拥有无穷无尽的力量。本文中介绍的命令足以将你从一无所知提升到英雄人物。除了涵盖的内容之外,还有许多实用程序可以考虑用于日常数据操作。[Csvkit][9]、[xsv][10] 还有 [q][11] 是需要记住的三个。如果你希望更深入地了解命令行数据科学,查看[这本书][12]。它也可以[免费][13]在线获得!
+
+--------------------------------------------------------------------------------
+
+via: http://kadekillary.work/post/cli-4-ds/
+
+作者:[Kade Killary][a]
+选题:[lujun9972](https://github.com/lujun9972)
+译者:[GraveAccent](https://github.com/graveaccent)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:http://kadekillary.work/authors/kadekillary
+[1]:https://en.wikipedia.org/wiki/Brian_Kernighan
+[2]:https://en.wikipedia.org/wiki/The_C_Programming_Language
+[3]:https://www.amazon.com/Learning-AWK-Programming-cutting-edge-text-processing-ebook/dp/B07BT98HDS
+[4]:https://www.youtube.com/watch?v=MijmeoH9LT4
+[5]:https://www.amazon.com/sed-awk-Dale-Dougherty/dp/1565922255/ref=sr_1_1?ie=UTF8&qid=1524381457&sr=8-1&keywords=sed+and+awk
+[6]:https://www.amazon.com/AWK-Programming-Language-Alfred-Aho/dp/020107981X/ref=sr_1_1?ie=UTF8&qid=1524388936&sr=8-1&keywords=awk
+[7]:http://www.grymoire.com/Unix/Awk.html
+[8]:https://www.tutorialspoint.com/awk/index.htm
+[9]:http://csvkit.readthedocs.io/en/1.0.3/
+[10]:https://github.com/BurntSushi/xsv
+[11]:https://github.com/harelba/q
+[12]:https://www.amazon.com/Data-Science-Command-Line-Time-Tested/dp/1491947853/ref=sr_1_1?ie=UTF8&qid=1524390894&sr=8-1&keywords=data+science+at+the+command+line
+[13]:https://www.datascienceatthecommandline.com/
diff --git a/translated/talk/20180504 How a university network assistant used Linux in the 90s.md b/published/201812/20180504 How a university network assistant used Linux in the 90s.md
similarity index 50%
rename from translated/talk/20180504 How a university network assistant used Linux in the 90s.md
rename to published/201812/20180504 How a university network assistant used Linux in the 90s.md
index 3c8b0e8a5d..38a99e4310 100644
--- a/translated/talk/20180504 How a university network assistant used Linux in the 90s.md
+++ b/published/201812/20180504 How a university network assistant used Linux in the 90s.md
@@ -1,34 +1,36 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
-[#]: reviewer: ( )
-[#]: publisher: ( )
+[#]: reviewer: (wxy)
+[#]: publisher: (wxy)
[#]: subject: (How a university network assistant used Linux in the 90s)
[#]: via: (https://opensource.com/article/18/5/my-linux-story-student)
[#]: author: ([Alan Formy-Duva](https://opensource.com/users/alanfdoss)
-[#]: url: ( )
+[#]: url: (https://linux.cn/article-10359-1.html)
-大学网络助理如何在 90 年代使用 Linux
+90 年代的大学网管如何使用 Linux
======
+

-在 20 世纪 90 年代中期,我报名了计算机科学课。我大学的计算机科学系为学生提供了一台 SunOS 服务器,它是一个多用户、多任务的 Unix 系统。我们登录它并编写我们在学习的编程语言代码,例如 C、C++ 和 ADA。在那些日子里,在社交网络和 IM 出现之前,我们还使用该系统相互通信,发送电子邮件和使用诸如 `write` 和 `talk` 之类的程序。我们每个人被允许托管一个个人网站。我很高兴它能够完成我的作业并联系其他用户。
+
+在上世纪 90 年代中期,我报名了计算机科学课。我大学的计算机科学系为学生提供了一台 SunOS 服务器,它是一个多用户、多任务的 Unix 系统。我们登录它并编写我们学习的编程语言代码,例如 C、C++ 和 ADA。在那时,在社交网络和 IM 出现之前,我们还使用该系统发送电子邮件和使用诸如 `write` 和 `talk` 之类的程序来相互通信。我们每个人被允许托管一个个人网站。我很高兴能够使用它完成我的作业并联系其他用户。
这是我第一次体验这种类型的操作环境,但我很快就了解了另一个可以做同样事情的操作系统:Linux。
-当我还是一名学生的时候,我还在大学兼职工作。我的第一个职位是住房和住宅部 (H&R) 的网络安装人员。这包含将学生宿舍与校园网络连接起来。由于这是该大学的第一个宿舍网络服务,因此只有两幢楼和大约 75 名学生已经连接。
+那会我还是学生,我在大学找了份兼职工作。我的第一个职位是住房和住宅部(H&R)的网络安装人员。这工作涉及到将学生宿舍与校园网络连接起来。由于这是该大学的第一个宿舍网络服务,因此只有两幢楼和大约 75 名学生连上了网。
-在我工作的第二年,该网络扩展到另外两幢楼。H&R 决定让该大学的信息技术办公室 (OIT) 管理这不断增长的业务。我进入 OIT 并开始担任 OIT 网络经理的学生助理。这就是我发现 Linux 的方式。我的新职责之一是管理防火墙系统,它为宿舍提供网络和互联网访问。
+在第二年,该网络扩展到另外两幢楼。H&R 决定让该大学的信息技术办公室(OIT)管理这不断增长的业务。我进入 OIT 并开始担任 OIT 网络经理的学生助理。这就是我发现 Linux 的方式。我的新职责之一是管理防火墙系统,它为宿舍提供网络和互联网访问。
-每个学生都注册了他们硬件的 MAC 地址。注册学生可以连接到宿舍网络并获得 IP 地址及访问互联网。与大学使用的其他昂贵的 SunOS 和 VMS 服务器不同,这些防火墙使用运行着免费和开源 Linux 操作系统的低成本计算机。截至年底,该系统已注册近 500 名学生。
+每个学生都注册了他们硬件的 MAC 地址。注册的学生可以连接到宿舍网络并获得 IP 地址及访问互联网。与大学使用的其他昂贵的 SunOS 和 VMS 服务器不同,这些防火墙使用运行着自由开源的 Linux 操作系统的低成本计算机。截至年底,该系统已注册近 500 名学生。
![Red hat Linux install disks][1]
-OIT 网络工作人员使用 Linux 运行 HTTP、FTP 和其他服务。他们还在个人桌面上使用 Linux。就在那时,我意识到我手上的计算机看起来和运行起来就像 CS 系昂贵的 SunOS 机器一样但没有高昂的成本。Linux 可以在商用 x86 硬件上运行,例如有 8 MB RAM 和 133Mhz Intel Pentium CPU 的 Dell Latitude。那对我来说是个卖点!我在从一个剩余的仓库中清理出来的机器上安装了 Red Hat Linux 5.2,并给了我的朋友登录帐户。
+OIT 网络工作人员使用 Linux 运行 HTTP、FTP 和其他服务。他们还在个人桌面上使用 Linux。就在那时,我意识到我手上的计算机看起来和运行起来就像 CS 系昂贵的 SunOS 机器一样,但没有高昂的成本。Linux 可以在商用 x86 硬件上运行,例如有 8 MB RAM 和 133Mhz Intel Pentium CPU 的 Dell Latitude。那对我来说是个卖点!我在从一个存货仓库中清理出来的机器上安装了 Red Hat Linux 5.2,并给了我的朋友登录帐户。
我使用我的新 Linux 服务器来托管我的网站并向我的朋友提供帐户,同时它还提供 CS 系服务器没有的图形功能。它使用了 X Windows 系统,我可以使用 Netscape Navigator 浏览网页,使用 [XMMS][2] 播放音乐,并尝试不同的窗口管理器。我也可以下载并编译其他开源软件并编写自己的代码。
-我了解到 Linux 提供了一些非常先进的功能,其中许多功能比更主流的操作系统更方便或更优越。例如,许多操作系统尚未提供应用更新的简单方法。在 Linux 中,这很简单,感谢 [autoRPM][3],一个由 Kirk Bauer 编写的更新管理器,它向 root 用户每日发送邮件,其中包含可用的更新。它有一个直观的界面,用于审查和选择要安装的软件更新 - 这对于 90 年代中期来说非常了不起。
+我了解到 Linux 提供了一些非常先进的功能,其中许多功能比更主流的操作系统更方便或更优越。例如,许多操作系统尚未提供应用更新的简单方法。在 Linux 中,这很简单,感谢 [autoRPM][3],一个由 Kirk Bauer 编写的更新管理器,它向 root 用户每日发送邮件,其中包含可用的更新。它有一个直观的界面,用于审查和选择要安装的软件更新 —— 这对于 90 年代中期来说非常了不起。
-Linux may not have been well-known back then, and it was often received with skepticism, but I was convinced it would survive. And survive it did!
+当时 Linux 可能并不为人所知,而且它经常受到怀疑,但我确信它会存活下来。而它确实生存下来了!
--------------------------------------------------------------------------------
@@ -37,11 +39,11 @@ via: https://opensource.com/article/18/5/my-linux-story-student
作者:[Alan Formy-Duval][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[geekpi](https://github.com/geekpi)
-校对:[校对者ID](https://github.com/校对者ID)
+校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/alanfdoss
[1]:https://opensource.com/sites/default/files/styles/panopoly_image_original/public/images/life-uploads/red_hat_linux_install_disks.png?itok=VSw6Cke9 (Red hat Linux install disks)
[2]:http://www.xmms.org/
-[3]:http://www.ccp14.ac.uk/solution/linux/autorpm_redhat7_3.html
\ No newline at end of file
+[3]:http://www.ccp14.ac.uk/solution/linux/autorpm_redhat7_3.html
diff --git a/published/201812/20180508 Person with diabetes finds open source and builds her own medical device.md b/published/201812/20180508 Person with diabetes finds open source and builds her own medical device.md
new file mode 100644
index 0000000000..c874777c07
--- /dev/null
+++ b/published/201812/20180508 Person with diabetes finds open source and builds her own medical device.md
@@ -0,0 +1,87 @@
+糖尿病患者们是怎样使用开源造出自己的医疗设备的
+======
+> Red Hat 的 2018 女性开源社区奖获得者 Dana Lewis 的故事。
+
+
+
+Dana Lewis 被评选为[开源社区 2018 年度最佳女性][1]!下面是开源怎样改善了她的健康的故事。
+
+Dana 患有 I 型糖尿病,但当时市面上流通的药品和医疗设备都对她无效。她用来管理血糖的动态血糖监测(CGM)报警器的声音太小了,根本叫不醒熟睡的她,产品这样的设计无法保证她每天睡眠时间的生命安全。
+
+“我和生产厂家见了一面商议提出意见,厂家的回复是‘我们产品的音量已经足够大了,很少有人叫不醒’,我被告知‘这不是普遍问题,我们正在改进,请期待我们的新产品。’听到这些时我真的很挫败,但我从没想象过我能做出什么改变,毕竟那是通过了 FDA 标准的医疗设备,不是我们能随意改变的。”
+
+面临着这些阻碍,Dana 想着如果她能把自己的数据从设备里导出,就可以设置手机闹铃来叫醒自己。在 2013 年末,她看到的一条推特解决了她的疑问。那条推特的作者是一位糖尿病患儿的家长,他把动态血糖监测仪进行了逆向工程,这样就可以导出孩子的血糖数据进行远程监控了。
+
+她意识到如果对方愿意把过程分享给她,她也可以用那些代码做一个自己的响亮的血糖监测仪了。
+
+“我并不知道向别人要源代码是件稀松平常的事,那是我第一次接触开源。”
+
+那个系统演化成一个响亮闹钟的代码,她也可以把代码在网页上分享给别人。和她的丈夫 Scott Leibrand 一起,她逐步向闹铃添加属性,最终形成了一个算法,这个算法不仅能监测实时血糖水平,还能主动预测未来血糖波动。
+
+随着 Dana 与开源糖尿病患者社区的接触越来越深,她认识了 Ben West,他花了很多年才研究出与 Dana 使用的胰岛素泵沟通数据的方法,与血糖监测仪不同,胰岛素泵不是简单的报告血糖,它是个单独的设备,要按人体需要持续推注胰岛素,比血糖监测仪要复杂得多。
+
+“老路行不通了,我们说‘哦,如果我们能用这段代码和胰岛素泵沟通,就像我们之前用算法和血糖监测仪沟通实时数据那样,我们就能获取两个设备的实时数据,创建一个闭路系统。’”
+
+我们得到的是一个自制人工胰腺系统 (DIY APS)。
+
+这个系统可以使用算法处理胰岛素泵和血糖监测仪的数据,来预测患者血糖水平,据此调整胰岛素的注射量,从而保持患者的血糖稳定。这个人工胰岛素系统取代了从前患者每日多次对胰岛素注射量的计算和调整,减轻了糖尿病患者的负担。
+
+“正因为我们使用的是开源软件,在做出这个系统之后我们就把成果开源化了,这样可以造福更多的人。”开源人工胰腺系统 (OpenAPS) 由此诞生。
+
+OpenAPS 社区已经拥有超过 600 名用户,大家都提供了各种各样的自制“闭路”系统代码。OpenAPS 贡献者们聚集到了 #WeAreNotWaiting 话题之下,以表达患者群体不该干等着医疗保健工厂制造出真正有效便捷产品的理念。
+
+“你可以选择等待未来的商业解决方案,这无可厚非,选择等待是你的自由。等待可以是一种选择,但不能是无法改变的现状。对我来说,开源在医疗保健方面做出的这个举动让等待变成了一种选择。你可以选择不自行解决,你可以选择等待商业解决方案,但如果你不想等了,你无需再等。现在你有很多选择,开源社区的人们已经解决了很多问题。”
+
+OpenAPS 社区由糖尿病患者、患者家属,还有想要合理利用这项技术的人们。在社区的帮助下,Dana 学会了很多种贡献开源项目的方式。她发现许多从 Facebook 或 [Gitter][2] 上过来的非技术贡献者也对 OpenAPS 做出了很大贡献。
+
+“贡献有很多方式,我们要认识到各种方式的贡献都是平等的。它们一般涉及不同的兴趣领域和技能组合,只有把这些综合起来,才能做成社区的项目。”
+
+她亲身经历过,所以知道自己的贡献不被社区的其他成员认可是怎样难过的感受。对于人们习惯把女性的贡献打折的这一现象,她也不回避。在她的 [2014 年博客][3] 和 [反思][4] 文章中她初次写到在入围开源年度最佳人物时所遭受到的区别待遇,这些待遇让她意识到身为女性的不同。
+
+在她最初的博客中,她写道了自己和丈夫 Scott 同为开源社区成员,遭受到的区别待遇。他们都注意到,Dana 总是被提出一些细枝末节的要求,但 Scott 就不会。而 Scott 总被问道一些技术性问题,即使他向他们推荐 Dana,人们也更倾向于问身为男性的 Scott。大家都或多或少经历过这些行为,Dana 的博文在社区里引起了广泛的讨论。
+
+“人们更愿意认为项目是‘Scott 发起的’而非‘Dana 和 Scott 一起发起的’。”这让我感受到千刀万剐般的痛苦和挫败,我写了博客把这个现象提到明面上,我说,‘看看这些行为,我知道你们有些是故意的,有些是无意的,但如果我们的社区想要得到多元化参与者的支持,想要发展壮大,我们就要规范自己的行为,有不妥之处也不要回避,直接摊开来交流。”值得赞扬的是,社区里的大部分成员都加入进来,认真地讨论这个问题。他们都说,‘好的,我知道有哪里需要改了,如果我再无意识这样做时提醒我一下。’这就是我们社区形成的风气。”
+
+她还说如果没有 Scott 这位社区里活跃开发者的支持,还有社区里其他女性贡献者的鼓励,她可能就半途而废了。
+
+“我想如果我就放弃努力了,可能开源世界里糖尿病患者们的现状会有很大不同。我知道别人不幸的遭遇,他们在开源社区中感受不到认同感和自身价值,最终离开了开源。我希望我们可以继续这种讨论,大家都能意识到如果我们不故意打击贡献者,我们可以变得更加温暖,成员们也能感受到认同感,大家的付出也能得到相应的认可。
+
+OpenAPS 社区的交流和分享给我们提供了一个很好的例子,它说明非技术性的贡献者对于整个社区的成功都是至关重要的。Dana 在现实社会中的关系和交流经历对她为开源社区做出的宣传有着很大的贡献。她为社区在 [DIYPS 博客][5] 上写了很多篇文章,她还在 [TEDx Talk][6] 做过一场演讲, 在 [开源大会 (OSCON)][7] 上也演讲过很多次,诸如此类的还有很多。
+
+“不是每个项目都像 OpenAPS 一样,对患者有那么大的影响,甚至成为患者中间的主流项目。糖尿病社区在项目的沟通中真的做了很多贡献,引来了很多糖尿病患者,也让需要帮助的人们知道了我们的存在。”
+
+Dana 现在的目标是帮助其他疾病的患者社区创建项目。她尤其想要把社区成员们学到的工具和技术和其他的患者社区分享,特别是那些想要把项目进一步提升,进行深入研究,或者想和公司合作的社区。
+
+“我听说很多参与项目的患者都听过这样的话,‘你应该申请个专利;你应该拿它开个公司;你应该成立个非营利组织。’但这些都是大事,它们太耗时间了,不仅占据你的工作时间,甚至强行改变你的专业领域。我这样的人并不想做那样的事,我们更倾向于把精力放在壮大其他项目上,以此帮助更多的人。”
+
+在此之后,她开始寻找其他不那么占用时间的任务,比如给小孩们写一本书。Dana 在 2017 年进行了这项挑战,她写了本书给侄子侄女,讲解他们婶婶的糖尿病设备是怎样工作的。在她侄女问她“胳膊上的东西是什么”(那是她的血糖监测仪)时,她意识到她不知道怎么和一个小孩子解释糖尿病患者是什么,所以写了[《卡罗琳的机器人亲戚》][8]这本书。
+
+“我想用我侄子侄女那个年纪的语言和他们交流,毕竟不同年龄的人说话方式也不同。我当时想,‘真希望有本这方面的儿童读物,那我为什么不自己写一本呢?’”
+
+她写了书在亚马逊上出版,因为她想把开源的价值分享给更多的人。她还开了一个名为[“自己在亚马逊上出书”][9]的博客,希望大家也可以把自己的经历写进书里出版。
+
+像《卡罗琳的机器人亲戚》这本书还有开源社区年度最佳女性这样的奖项都说明生活中包括开源在内的不同领域中,还有很多人的工作等待着大众的认知。
+
+“社区越多元,事情越好办。”
+
+--------------------------------------------------------------------------------
+
+via: https://opensource.com/article/18/5/dana-lewis-women-open-source-community-award-winner-2018
+
+作者:[Taylor Greene][a]
+选题:[lujun9972](https://github.com/lujun9972)
+译者:[Valoniakim](https://github.com/Valoniakim)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://opensource.com/users/tgreene
+[1]:https://www.redhat.com/en/about/women-in-open-source
+[2]:https://gitter.im/
+[3]:https://diyps.org/2014/08/25/being-female-a-patient-and-co-designing-diyps-means-often-being-discounted/
+[4]:https://diyps.org/2018/02/01/women-in-open-source-make-a-difference/
+[5]:https://diyps.org/
+[6]:https://www.youtube.com/watch?v=kgu-AYSnyZ8
+[7]:https://www.youtube.com/watch?v=eQGWrdgu_fE
+[8]:https://www.amazon.com/gp/product/1977641415/ref=as_li_tl?ie=UTF8&tag=diyps-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=1977641415&linkId=96bb65e21b5801901586e9fabd12c860
+[9]:https://diyps.org/2017/11/01/makers-gonna-make-a-book-about-diabetes-devices-kids-book-written-by-danamlewis/
diff --git a/published/20180518 How to Manage Fonts in Linux.md b/published/201812/20180518 How to Manage Fonts in Linux.md
similarity index 100%
rename from published/20180518 How to Manage Fonts in Linux.md
rename to published/201812/20180518 How to Manage Fonts in Linux.md
diff --git a/published/20180523 How to dual-boot Linux and Windows.md b/published/201812/20180523 How to dual-boot Linux and Windows.md
similarity index 100%
rename from published/20180523 How to dual-boot Linux and Windows.md
rename to published/201812/20180523 How to dual-boot Linux and Windows.md
diff --git a/published/20180525 How to Set Different Wallpaper for Each Monitor in Linux.md b/published/201812/20180525 How to Set Different Wallpaper for Each Monitor in Linux.md
similarity index 100%
rename from published/20180525 How to Set Different Wallpaper for Each Monitor in Linux.md
rename to published/201812/20180525 How to Set Different Wallpaper for Each Monitor in Linux.md
diff --git a/published/201812/20180623 The IBM 029 Card Punch.md b/published/201812/20180623 The IBM 029 Card Punch.md
new file mode 100644
index 0000000000..07002cef6e
--- /dev/null
+++ b/published/201812/20180623 The IBM 029 Card Punch.md
@@ -0,0 +1,77 @@
+IBM 029 型打孔机
+======
+
+我知道这很学院派,可一行超过 80 个字符的代码还是让我抓狂。我也在网上见过不少人认为即使在现代的视网膜屏幕下也应当采用行长度为 80 个字符的标准,可他们都不理解我对破坏这一标准的怒火,就算多 1 个字符也不行。
+
+在这一标准的黄金时期,一行代码的长度几乎不会超过 80 个字符的限制。在那时,这一限制是物理的,没有第 81 列用于存放第 81 个字符。每一个试图把函数名起的又长又臭的程序员都会在短暂的愉悦后迎来更多的麻烦,而这仅仅是因为没有足够的空间放下整个函数的声明。
+
+这一黄金时期也是打孔卡编程时期。在 20 世纪 60 年代,IBM 打孔卡设立了标准,这个标准就是打孔卡的宽度为 80 列。这个 80 列标准在后来的电传打字机和哑终端时期得以延续,并逐渐成为操作系统中隐藏的细节。时至今日,即使我们用上了更大、更好的屏幕,偏向于使用更长的标识符而不是类似 `iswcntrl()` 这样令人难以猜测的函数名,可当你打开新的终端模拟器窗口时,默认的宽度依然是 80 个字符。
+
+从 Quora 上的很多问题中可以发现,很多人并不能想象如何使用打孔卡给计算机编程。我承认,在很长的一段时间里我也不能理解打孔卡编程是如何工作的,因为这让我想到就像劳工一样不停的给这些打孔卡打孔。当然,这是一个误解,程序员不需要亲自给打孔卡打孔,就像是火车调度员不用亲自扳道岔。程序员们有打孔机(也被称为键控打孔机),这让他们可以使用打字机式的键盘给打孔卡打孔。这样的设备在 19 世纪 90 年代时就已经不是什么新技术了。
+
+那时,最为广泛使用的打孔机之一便是 IBM 029 型打孔机。就算在今天,它也许是最棒的打孔机。
+
+![][1]
+
+IBM 029 型打孔机在 1964 年作为 IBM 的 System/360 大型电脑的配件发售的。System/360 是计算系统与外设所组成的一个系列,在 20 世纪 60 年代晚期,它几乎垄断了整个大型计算机市场。就像其它 System/360 外设一样,029 型打孔机也是个大块头。那时,计算机和家具的界限还很模糊,但 029 型打孔机可不是那种会占领你的整张桌子的机器。它改进自 026 型打孔机,增加了新的字符支持,如括号,总体上也更加安静。与前辈 026 型所展出 20 世纪 40 年代的圆形按钮与工业化的样貌相比,029 型的按键方正扁平、功能按键还有酷炫的蓝色高亮提示。它的另一个重要买点是它能够在数字区左侧自动的填充 0 ,这证明了 JavaScript 程序员不是第一批懒得自己做左填充的程序员。(LCTT 译注:这项功能需要额外的 4 张 [标准模块系统卡](https://en.wikipedia.org/wiki/IBM_Standard_Modular_System)才能使用。例如设置数字区域长度为 6 列时,操作员只需要输入 73 ,打孔机会自动填充起始位置上的 4 个 0 ,故最终输出 000073。[更多信息](https://en.wikipedia.org/wiki/Keypunch#IBM_029_Card_Punch))
+
+等等!你说的是 IBM 在 1964 年发布了全新的打孔机?你知道那张在贝尔实验室拍摄的 Unix 之父正在使用电传打字机的照片吗?那是哪一年的来着?1970?打孔机不是应该在 20 世纪 60 年代中期到晚期时就过时了吗?是的,你也许会奇怪,为什么直到 1984 年,IBM 的产品目录中还会出现 029 型打孔机的身影 [^1]。事实上,直到 20 世纪 70 年代,大多数程序员仍然在使用打孔卡编程。其实二战期间就已经有人在用电传打字机了,可那时并没能普及。客观的讲,电传打字机几乎和打孔卡一样古老。也许和你想象的恰恰相反,并不是电传打字机本身限制了它的普及,而是计算时间。人们拒绝使用电传打字机的原因是,它是可交互的,它和计算机使用“在线”的传输方式。在以 Unix 为代表的分时操作系统被发明前,你和电脑的交互会被任何人的使用而打断,而这一点延迟通常意味着几千美元的损失。所以程序员们普遍选择离线地使用打孔机编程,再将打孔卡放入大型计算机中,作为批任务执行。在那时,还没有即廉价又可靠的存储设备,可打孔卡的廉价优势已经足够让它成为那时最流行的数据存储方式了。那时的程序是书架上一摞打孔卡而不是硬盘里的一堆文件。
+
+那么实际使用 IBM 029 型打孔机是个什么样子呢?这很难向没有实际看过打孔卡的人解释。一张打孔卡通常有 12 行 80 列。打孔卡下面是从 1 到 9 的数字行,打孔卡上的每一列都有这些行所对应的数字。最上面的三行是空间行,通常由两行空白行和一行 0 行组成。第 12 行是打孔卡最顶部的行,接下来是 11 行,随后是从数字 0 到 9 所在的行。这个有点让人感到困惑的顺序的原因是打孔卡的上边缘被称为12 边、下边缘被称为 9 边。那时,为了让打孔卡便于整理,常常会剪去打孔卡的一个角。
+
+![][2]
+
+(LCTT 译注:可参考[EBCDIC 编码](https://zh.wikipedia.org/wiki/EBCDIC))
+
+在打孔卡发明之初,孔洞的形状是圆形的,但是 IBM 最终意识到如果使用窄长方形作为孔洞,一张卡就可以放下更多的列了。每一列中孔洞的不同组合就可以表达不同的字符。像 029 型这样的拥有人性化设计的打孔机除了完成本质的打孔任务外,还会在打孔卡最上方打印出每一列所对应的字符。输入是数字就在对应的数字行上打孔。输入的是字母或符号就用一个在空间列的孔和一或俩个在数字列的孔的组合表示,例如字母 A 就用一个在第 12 空间行的空和一个数字 1 所在行的孔表示。这是一种顺序编码,在第一台打孔机被发明后,也叫 Hollerith 编码。这种编码只能表示相对较小的一套字符集,小写字母就没有包含在这套字符集中。如今一些聪明的工程师可能想知道为什么打卡不干脆使用二进制编码 —— 毕竟,有 12 行,你可以编码超过 4000 个字符。 使用 Hollerith 编码是因为它确保在单个列中出现不超过三个孔。这保留了卡的结构强度。二进制编码会带来太多的孔,会因为孔洞过于密集而断裂。
+
+打孔卡也有不同。在 20 世纪 60 年代,80 列虽然是标准,但表达的方式不一定相同。基础打孔卡是无标注的,但用于 COBOL 编程的打孔卡会把最后的 8 列保留,供标识数保存使用。这一标识数可以在打孔卡被打乱 (例如一叠打孔卡掉在地上了) 后用于自动排序。此外,第 7 列被用于表示本张打孔卡上的是否与上一张打孔卡一起构成一条语句。也就是说当你真的对 80 字符的限制感到绝望的时候,还可以用两张卡甚至更多的卡拼接成一条长语句。用于 FORTRAN 编程的打孔卡和 COBOL 打孔卡类似,但是定义的列不同。大学里使用的打孔卡通常会由其计算机中心加上水印,其它的设计则会在如 [1976 年美国独立 200 周年][3] 的特殊场合才会加入。
+
+最终,这些打孔卡都要被计算机读取和计算。IBM 出售的 System/360 大型计算机的外设 IBM 2540 可以以每分钟 1000 张打孔卡的速度读取这些卡片[^2] 。IBM 2540 使用电刷扫过每张打孔卡,电刷通过孔洞就可以接触到卡片后面的金属板完成一次读取。一旦读取完毕,System/360 大型计算机就会把每张打孔卡上的数据使用一种定长的 8 位编码保存,这种编码是扩增二进式十进交换码,简写为 EBCDIC 编码。它是一种二进制编码,可以追溯自早期打孔卡所使用的 BCDIDC 编码 —— 其 6 位编码使用低 4 位表示数字行,高 2 位表示空间行。程序员们在打孔卡上编写完程序后,会把卡片们交给计算机操作员,操作员们会把这些卡片放入 IBM 2540 ,再把打印结果交给程序员。那时的程序员大多都没有见过计算机长什么样。
+
+程序员们真正能见到的是很多打孔机。029 型打孔机虽然不是计算机,但这并不意味着它不是一台复杂的机器。看看这个由密歇根大学计算机中心在 1967 年制作的[教学视频][4],你就能更好的理解使用一台 029 型打孔机是什么情形了。我会尽可能在这里总结这段视频,但如果你不去亲自看看的话,你会错过许多惊奇和感叹。
+
+029 型打孔机的结构围绕着一个打孔卡穿过机器的 U 形轨道开始。使用打孔机时,右手边也就是 U 形轨道的右侧顶部是进卡卡槽,使用前通常在里面放入一叠未使用的打孔卡。虽然 029 型打孔机主要使用 80 列打孔卡,但在需要的情况下也可以使用更小号的打孔卡。在打孔机的使用过程中,打孔卡离开轨道右上端的进卡卡槽,顺着 U 形轨道移动并最终进入左上端的出卡卡槽。这一流程可以保证出卡卡槽中的打孔卡按打孔时的先后顺序排列。
+
+029 型打孔机的开关在桌面下膝盖高度的位置。在开机后,连按两次 “装入” 键让机器自动将打孔卡从进卡卡槽中取出并移动到机器内。 U 形轨道的底部是打孔机的核心区域,它由三个部分组成:右侧是等待区,中间是打孔操作区,左侧是阅读区。连按两次 “装入” 键,机器就会把一张打孔卡装入打孔机的打孔操作区,另一张打孔卡进入等待区。在打孔操作区上方有一个列数指示器来显示当前打孔所在的列的位置。这时,每按下一个按键,机器就会在打孔卡对应的位置打孔并在卡片的顶部打印按键对应的字符,随后将打孔卡向左移动一列。如果一张卡片的 80 列全部被打上了数据,这张卡片会被打孔操作区自动释放并进入阅读区,同时,一张新的打孔卡会被装入打孔操作区。如果没有打完全部的 80 列,可以使用 “释放” 键完成上面的操作。
+
+在打孔卡上打印对应的字符这一设计让人很容易分辨出错误。但就像密歇根大学的视频中警告的那样,打孔卡上修正一个错误可不像擦掉一个打印的字符然后再写上一个新的那样容易,因为计算机只会根据卡片上的孔来读取信息。因为被打出的孔不能被复原,所以并不能直接退回一列然后再打上一个新的字符。打出更多的孔也只能让这一列的组合变成一个无效字符。IBM 029 型打孔机上虽然有一个可以让打孔卡回退一列的退格按键,但这个按键被放置在机器上而非在键盘上。这样的设计也许是为了阻止这个按键的使用,因为实际上很少有用户需要这个功能。
+
+实际上,只有废弃错误的打孔卡再在新的打孔卡上重新打孔这一种修正错误的方式。这就是阅读区的用武之处了。当你发现打孔卡上的第 68 列出错时,你需要在新的打孔卡上小心的给前 67 列重新打孔,然后给第 68 列打上正确的字母。另一种操作方式是把带有错误信息的打孔卡放在阅读区,同时在打孔操作区载入一张新的打孔卡,然后按下 “重复” 按键直到列数指示器显示 68 列。这时按下正确的字符来修正错误。阅读区和重复按键使得 029 型打孔机很容易复制打孔卡上的内容。当然,这一功能的使用可能有各种各样的原因,但改错是最常见的。
+
+(LCTT 译注:有一种说法是“补丁”这个用于对已经发布的软件进行修复的术语来源于对打孔纸带或打孔卡上打错的孔贴上补丁的做法。可能对于长长的一卷打孔纸带来说,由于个别字母的错误而整个废弃成本过高,会采用“补丁”的方式;而对于这种单张式的打孔卡来说,重新打印一张正确的更为方便。)
+
+“重复”按键允许 029 型打孔机的操作员手动调用重复的函数。但是 029 型打孔机还可以设置为自动重复。当用于记录数据而不是编程时,这项功能十分有效。举个例子,当用打孔卡来记录大学生的信息时,每张卡片上都需要输入学生的宿舍楼的名字,如果发现所输入信息的学生都在同一栋楼,就可以使用 029 型打孔机的自动重复功能来完成宿舍楼名称的填写。
+
+像这样的自动化操作可以通过程序鼓编程到 029 型打孔机里面。程序鼓就安装在打孔操作区上方的 U 形轨道中间部分的右上角。通过在打孔卡上写下程序,然后把打孔卡装入程序鼓中,就完成了一次给 029 型打孔机的编程任务。用户可以通过这种方式对打孔卡的每一列都按需要定义不同的自动化操作。029 型打孔机允许指定某些列重复上一张打孔卡相同位置的字符,这就是它能更快的输入学生信息的理由。它还允许指定某些列只能输入数字或者字母,指定特定的列为空或者到某一列时就直接跳过一整张打孔卡。编程鼓使它在打孔特定列有特殊含义的固定模式卡片时很容易。密歇根大学制作的另一个[进阶教学视频][5]包括了给 029 型打孔机编程的过程,如果你已经掌握了它的基础操作,就快去看看吧。
+
+这会儿,无论你是否看了密歇根大学制作的视频,都会感叹打孔机的操作之简便。虽然修正错误的过程很乏味,但除此之外,操作一台打孔机并不像想象的那样复杂。我甚至可以想象打孔卡之间的无缝切换让 COBOL 和 FORTRAN 程序员忘记了他们的程序是打在不同的打孔卡上而不是写在一个连续的文本文件内。另一方面,思考一下打孔机是如何影响编程语言的发展也是很有趣的,虽然它仅仅是一台输入设备。结构化编程最终会出现并鼓励程序员把整个代码块视为一个整体,但可以想象打孔卡程序员们强调每一行的作用且难以认同结构化编程的场景。同时你能够理解他们为什么不把代码块闭合所使用的括号放在单独的一行,只是因为这样会浪费打孔卡。
+
+现在,虽然没有人再使用打孔卡编程了,每个程序员都该试试[这个][6],哪怕一次也好。或许你因此能够更好的理解 COBOL 和 FORTRAN 的历史,或许你就能体会到为什么每个人把 80 个字符作为长度限制的标注。
+
+喜欢吗?这里每两周都会发表一篇这样的文章。请在推特上关注我们 [@TwoBitHistory][7] 或者订阅我们的 [RSS][8],这样你就能在第一时间收到新文章的通知。
+
+[^1]: “IBM 29 Card Punch,” IBM Archives, accessed June 23, 2018, https://www-03.ibm.com/ibm/history/exhibits/vintage/vintage_4506VV4002.html.
+[^2]: IBM, IBM 2540 Component Description and Operation Procedures (Rochester, MN: IBM Product Publications, 1965), September 06, 2009, accessed June 23, 2018, http://bitsavers.informatik.uni-stuttgart.de/pdf/ibm/25xx/A21-9033-1_2540_Card_Punch_Component_Description_1965.pdf.
+
+--------------------------------------------------------------------------------
+
+via: https://twobithistory.org/2018/06/23/ibm-029-card-punch.html
+
+作者:[Two-Bit History][a]
+选题:[lujun9972][b]
+译者:[wwhio](https://github.com/wwhio)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]: https://twobithistory.org
+[b]: https://github.com/lujun9972
+[1]: https://twobithistory.org/images/ibm029_front.jpg
+[2]: https://twobithistory.org/images/card.png
+[3]: http://www.jkmscott.net/data/Punched%20card%20013.jpg
+[4]: https://www.youtube.com/watch?v=kaQmAybWn-w
+[5]: https://www.youtube.com/watch?v=SWD1PwNxpoU
+[6]: http://www.masswerk.at/keypunch/
+[7]: https://twitter.com/TwoBitHistory
+[8]: https://twobithistory.org/feed.xml
diff --git a/published/20180707 Version Control Before Git with CVS.md b/published/201812/20180707 Version Control Before Git with CVS.md
similarity index 100%
rename from published/20180707 Version Control Before Git with CVS.md
rename to published/201812/20180707 Version Control Before Git with CVS.md
diff --git a/published/20180709 5 Firefox extensions to protect your privacy.md b/published/201812/20180709 5 Firefox extensions to protect your privacy.md
similarity index 100%
rename from published/20180709 5 Firefox extensions to protect your privacy.md
rename to published/201812/20180709 5 Firefox extensions to protect your privacy.md
diff --git a/published/201812/20180710 Users, Groups, and Other Linux Beasts.md b/published/201812/20180710 Users, Groups, and Other Linux Beasts.md
new file mode 100644
index 0000000000..65cbacecb2
--- /dev/null
+++ b/published/201812/20180710 Users, Groups, and Other Linux Beasts.md
@@ -0,0 +1,154 @@
+用户、组及其它 Linux 特性
+======
+
+> Linux 和其他类 Unix 操作系统依赖于用户组,而不是逐个为用户分配权限和特权。一个组就是你想象的那样:一群在某种程度上相关的用户。
+
+
+
+到这个阶段,[在看到如何操作目录或文件夹之后][1],但在让自己一头扎进文件之前,我们必须重新审视 _权限_、_用户_ 和 _组_。幸运的是,[有一个网站上已经有了一个优秀而全面的教程,讲到了权限][2],所以你应该去立刻阅读它。简而言之,你使用权限来确定谁可以对文件和目录执行操作,以及他们可以对每个文件和目录执行什么操作 —— 从中读取、写入、移动、擦除等等。
+
+要尝试本教程涵盖的所有内容,你需要在系统上创建新用户。让我们实践起来,为每一个需要借用你电脑的人创建一个用户,我们称之为 `guest` 账户。
+
+**警告:** 例如,如果你错误地删除了自己的用户和目录,那么创建用户,特别是删除用户以及主目录会严重损坏系统。你可能不想在你日常的工作机中练习,那么请在另一台机器或者虚拟机上练习。无论你是否想要安全地练习,经常备份你的东西总是一个好主意。检查备份是否正常工作,为你自己以后避免很多咬牙切齿的事情。
+
+### 一个新用户
+
+你可以使用 `useradd` 命令来创建一个新用户。使用超级用户或 root 权限运行 `useradd`,即使用 `sudo` 或 `su`,这具体取决于你的系统,你可以:
+
+```
+sudo useradd -m guest
+```
+
+然后输入你的密码。或者也可以这样:
+
+```
+su -c "useradd -m guest"
+```
+
+然后输入 root 或超级用户的密码。
+
+( _为了简洁起见,我们将从现在开始假设你使用 `sudo` 获得超级用户或 root 权限。_ )
+
+通过使用 `-m` 参数,`useradd` 将为新用户创建一个主目录。你可以通过列出 `/home/guest` 来查看其内容。
+
+然后你可以使用以下命令来为新用户设置密码:
+
+```
+sudo passwd guest
+```
+
+或者你也可以使用 `adduser`,这是一个交互式的命令,它会询问你一些问题,包括你要为用户分配的 shell(是的,shell 有不止一种),你希望其主目录在哪里,你希望他们属于哪些组(有关这点稍后会讲到)等等。在运行 `adduser` 结束时,你可以设置密码。注意,默认情况下,在许多发行版中都没有安装 `adduser`,但安装了 `useradd`。
+
+顺便说一下,你可以使用 `userdel` 来移除一个用户:
+
+```
+sudo userdel -r guest
+```
+
+使用 `-r` 选项,`userdel` 不仅删除了 `guest` 用户,还删除了他们的主目录和邮件中的条目(如果有的话)。
+
+### 主目录中的内容
+
+谈到用户的主目录,它依赖于你所使用的发行版。你可能已经注意到,当你使用 `-m` 选项时,`useradd` 使用子目录填充用户的目录,包括音乐、文档和诸如此类的内容以及各种各样的隐藏文件。要查看 `guest` 主目录中的所有内容,运行 `sudo ls -la /home/guest`。
+
+进入新用户目录的内容通常是由 `/etc/skel` 架构目录确定的。有时它可能是一个不同的目录。要检查正在使用的目录,运行:
+
+```
+useradd -D
+GROUP=100
+HOME=/home
+INACTIVE=-1
+EXPIRE=
+SHELL=/bin/bash
+SKEL=/etc/skel
+CREATE_MAIL_SPOOL=no
+```
+
+这会给你一些额外的有趣信息,但你现在感兴趣的是 `SKEL=/etc/skel` 这一行,在这种情况下,按照惯例,它指向 `/etc/skel/`。
+
+由于 Linux 中的所有东西都是可定制的,因此你可以更改那些放入新创建的用户目录的内容。试试这样做:在 `/etc/skel/` 中创建一个新目录:
+
+```
+sudo mkdir /etc/skel/Documents
+```
+
+然后创建一个包含欢迎消息的文件,并将其复制过来:
+
+```
+sudo cp welcome.txt /etc/skel/Documents
+```
+
+现在删除 `guest` 账户:
+
+```
+sudo userdel -r guest
+```
+
+再次创建:
+
+```
+sudo useradd -m guest
+```
+
+嘿!你的 `Documents/` 目录和 `welcome.txt` 文件神奇地出现在了 `guest` 的主目录中。
+
+你还可以在创建用户时通过编辑 `/etc/default/useradd` 来修改其他内容。我的看起来像这样:
+
+```
+GROUP=users
+HOME=/home
+INACTIVE=-1
+EXPIRE=
+SHELL=/bin/bash
+SKEL=/etc/skel
+CREATE_MAIL_SPOOL=no
+```
+
+这些选项大多数都是不言自明的,但让我们仔细看看 `GROUP` 选项。
+
+### 群组心态
+
+Linux 和其他类 Unix 操作系统依赖于用户组,而不是逐个为用户分配权限和特权。一个组就是你想象的那样:一群在某种程度上相关的用户。在你的系统上可能有一组允许使用打印机的用户,他们属于 `lp`(即 “_line printer_”)组。传统上 `wheel` 组的成员是唯一可以通过使用 `su` 成为超级用户或 root 的成员。`network` 用户组可以启动或关闭网络。还有许多诸如此类的。
+
+不同的发行版有不同的组,具有相同或相似名称的组具有不同的权限,这也取决于你使用的发行版。因此,如果你在前一段中读到的内容与你系统中的内容不匹配,不要感到惊讶。
+
+不管怎样,要查看系统中有哪些组,你可以使用:
+
+```
+getent group
+```
+
+`getent` 命令列出了某些系统数据库的内容。
+
+要查找当前用户所属的组,尝试:
+
+```
+groups
+```
+
+当你使用 `useradd` 创建新用户时,除非你另行指定,否则用户将只属于一个组:他们自己。`guest` 用户属于 `guest` 组。组使用户有权管理自己的东西,仅此而已。
+
+你可以使用 `groupadd` 命令创建新组,然后添加用户:
+
+```
+sudo groupadd photos
+```
+
+例如,这将创建 `photos` 组。下一次,我们将使用它来构建一个共享目录,该组的所有成员都可以读取和写入,我们将更多地了解权限和特权。敬请关注!
+
+
+--------------------------------------------------------------------------------
+
+via: https://www.linux.com/learn/intro-to-linux/2018/7/users-groups-and-other-linux-beasts
+
+作者:[Paul Brown][a]
+选题:[lujun9972](https://github.com/lujun9972)
+译者:[MjSeven](https://github.com/MjSeven)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://www.linux.com/users/bro66
+[1]:https://linux.cn/article-10066-1.html
+[2]:https://www.linux.com/learn/understanding-linux-file-permissions
+[3]:https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux
diff --git a/published/201812/20180716 Users, Groups and Other Linux Beasts- Part 2.md b/published/201812/20180716 Users, Groups and Other Linux Beasts- Part 2.md
new file mode 100644
index 0000000000..b71802c145
--- /dev/null
+++ b/published/201812/20180716 Users, Groups and Other Linux Beasts- Part 2.md
@@ -0,0 +1,114 @@
+用户、组及其它 Linux 特性(二)
+======
+> 我们继续创建和管理用户和组的 Linux 教程之旅。
+
+
+
+在正在进行的 Linux 之旅中,我们了解了[如何操作文件夹或目录][1],现在我们继续讨论 _权限_、_用户_ 和 _组_,这对于确定谁可以操作哪些文件和目录是必要的。[上次][2],我们展示了如何创建新用户,现在我们将重新起航:
+
+你可以使用 `groupadd` 命令创建新组,然后随意添加用户。例如,使用:
+
+```
+sudo groupadd photos
+```
+
+这将会创建 `photos` 组。
+
+你需要在根目录下[创建一个目录][1]:
+
+```
+sudo mkdir /photos
+```
+
+如果你运行 `ls -l /`,结果中会有如下这一行:
+
+```
+drwxr-xr-x 1 root root 0 jun 26 21:14 photos
+```
+
+输出中的第一个 `root` 是所属的用户,第二个 `root` 是所属的组。
+
+要将 `/photos` 目录的所有权转移到 `photos` 组,使用:
+
+```
+chgrp photos /photos
+```
+
+`chgrp` 命令通常采用两个参数,第一个参数是将要获得文件或目录所有权的组,第二个参数是希望交给组的文件或目录。
+
+接着,运行 `ls -l /`,你会发现刚才那一行变了:
+
+```
+drwxr-xr-x 1 root photos 0 jun 26 21:14 photos
+```
+
+你已成功将新目录的所有权转移到了 `photos` 组。
+
+然后,将你自己的用户和 `guest` 用户添加到 `photos` 组:
+
+```
+sudo usermod <你的用户名> -a -G photos
+sudo usermod guest -a -G photos
+```
+
+你可能必须注销并重新登录才能看到更改,但是当你这样做时,运行 `groups` 会将 `photos` 显示为你所属的组之一。
+
+关于上面提到的 `usermod` 命令,需要指明几点。第一:注意要使用 `-G` 选项而不是 `-g` 选项。`-g` 选项更改你的主要组,如果你意外地使用它,它可能会锁定你的一些东西。另一方面,`-G` 将你添加到列出的组中,并没有干扰主要组。如果要将用户添加到多个组中,在 `-G` 之后逐个列出它们,用逗号分隔,不要有空格:
+
+```
+sudo usermod -a -G photos,pizza,spaceforce
+```
+
+第二点:小心点不要忘记 `-a` 参数。`-a` 参数代表追加,将你传递给 `-G` 的组列表附加到你已经属于的组。这意味着,如果你不包含 `-a`,那么你之前所属的组列表将被覆盖,再次将你拒之门外。
+
+这些都不是灾难性问题,但这意味着你必须手动将用户添加回你所属的所有组,这可能是个麻烦,特别是如果你失去了对 `sudo` 和 `wheel` 组的访问权限。
+
+### 权限
+
+在将图像复制到 `/photos` 目录之前,还要做一件事情。注意,当你执行上面的 `ls -l /` 时,该文件夹的权限将以 `drwxr-xr-x` 形式返回。
+
+如果你阅读[我在本文开头推荐的文章][3],你将知道第一个 `d` 表示文件系统中的条目是一个目录,接着你有三组三个字符(`rwx`、`r-x`、`r-x`),它们表示目录的所属用户(`rwx`)的权限,然后是所属组(`r-x`)的权限,最后是其他用户(`r-x`)的权限。这意味着到目前为止唯一具有写权限的人,即能够在 `/photos` 目录中复制或创建文件的唯一人员是 `root` 用户。
+
+但是[我提到的那篇文章也告诉你如何更改目录或文件的权限][3]:
+
+```
+sudo chmod g+w /photos
+```
+
+运行 `ls -l /`,你会看到 `/photos` 权限变为了 `drwxrwxr-x`。这就是你希望的:组成员现在可以对目录进行写操作了。
+
+现在你可以尝试将图像或任何其他文件复制到目录中,它应该没有问题:
+
+```
+cp image.jpg /photos
+```
+
+`guest` 用户也可以从目录中读取和写入。他们也可以读取和写入,甚至移动或删除共享目录中其他用户创建的文件。
+
+### 总结
+
+Linux 中的权限和特权系统已经磨练了几十年,它继承自昔日的旧 Unix 系统。就其本身而言,它工作的非常好,而且经过了深思熟虑。熟悉它对于任何 Linux 系统管理员都是必不可少的。事实上,除非你理解它,否则你根本就无法做很多事情。但是,这并不难。
+
+下一次,我们将深入研究文件,并以一个创新的方式查看创建,操作和销毁文件的不同方法。最后一个总是很有趣。
+
+回头见!
+
+通过 Linux 基金会和 edX 的免费[“Linux 简介”][4]课程了解有关 Linux 的更多信息。
+
+
+--------------------------------------------------------------------------------
+
+via: https://www.linux.com/blog/learn/intro-to-linux/2018/7/users-groups-and-other-linux-beasts-part-2
+
+作者:[Paul Brown][a]
+选题:[lujun9972](https://github.com/lujun9972)
+译者:[MjSeven](https://github.com/MjSeven)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://www.linux.com/users/bro66
+[1]:https://linux.cn/article-10066-1.html
+[2]:https://linux.cn/article-10370-1.html
+[3]:https://www.linux.com/learn/understanding-linux-file-permissions
+[4]:https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux
diff --git a/published/201812/20180717 11 Uses for a Raspberry Pi Around the Office.md b/published/201812/20180717 11 Uses for a Raspberry Pi Around the Office.md
new file mode 100644
index 0000000000..cb5b51fe98
--- /dev/null
+++ b/published/201812/20180717 11 Uses for a Raspberry Pi Around the Office.md
@@ -0,0 +1,142 @@
+[#]: collector: (lujun9972)
+[#]: translator: (geekpi)
+[#]: reviewer: (wxy)
+[#]: publisher: (wxy)
+[#]: url: (https://linux.cn/article-10375-1.html)
+[#]: subject: (11 Uses for a Raspberry Pi Around the Office)
+[#]: via: (https://blog.dxmtechsupport.com.au/11-uses-for-a-raspberry-pi-around-the-office/)
+[#]: author: (James Mawson https://blog.dxmtechsupport.com.au/author/james-mawson/)
+
+树莓派在办公室的 11 种用法
+======
+
+我知道你在想什么:树莓派只能用在修修补补、原型设计和个人爱好中。它实际不能用在业务中。
+
+毫无疑问,这台电脑的处理能力相对较低、易损坏的 SD 卡、缺乏电池备份以及支持的 DIY 性质,这意味着它不会是一个能在任何时候执行最关键的操作的[专业的、已安装好、配置好的商业服务器][1]的可行替代品。
+
+但是它电路板便宜、功耗很小、小到几乎适合任何地方、无限灵活 —— 这实际上是处理办公室一些基本任务的好方法。
+
+而且,更好的是,已经有一些人完成了这些项目并很乐意分享他们是如何做到的。
+
+### DNS 服务器
+
+每次在浏览器中输入网站地址或者点击链接时,都需要将域名转换为数字 IP 地址,然后才能显示内容。
+
+通常这意味着向互联网上某处 DNS 服务器发出请求 —— 但你可以通过本地处理来加快浏览速度。
+
+你还可以分配自己的子域,以便本地访问办公室中的计算机。
+
+[这里了解它是如何工作的。][2]
+
+### 厕所占用标志
+
+在厕所排过队吗?
+
+这对于那些等待的人来说很烦人,花在处理它上面的时间会耗费你在办公室的工作效率。
+
+我想你希望在办公室里也悬挂飞机上那个厕所有人的标志。
+
+[Occu-pi][3] 是一个非常简单的解决方案,使用磁性开关和树莓派来判断螺栓何时关闭,并在 Slack 频道中更新“厕所在使用中” —— 这意味着整个办公室的人都可以看一眼电脑或者移动设备知道是否有空闲的隔间。
+
+### 针对黑客的蜜罐陷阱
+
+黑客破坏了网络的第一个线索是一些事情变得糟糕,这应该会吓到大多数企业主。
+
+这就是可以用到蜜罐的地方:一台没有任何服务的计算机位于你的网络,将特定端口打开,伪装成黑客喜欢的目标。
+
+安全研究人员经常在网络外部部署蜜罐,以收集攻击者正在做的事情的数据。
+
+但对于普通的小型企业来说,这些作为一种绊脚石部署在内部更有用。因为普通用户没有真正的理由想要连接到蜜罐,所以任何发生的登录尝试都是正在进行捣乱的非常好的指示。
+
+这可以提供对外部人员入侵的预警,并且也可以提供对值得信赖的内部人员的预警。
+
+在较大的客户端/服务器网络中,将它作为虚拟机运行可能更为实用。但是在无线路由器上运行的点对点的小型办公室/家庭办公网络中,[HoneyPi][4] 之类的东西是一个很小的防盗报警器。
+
+### 打印服务器
+
+联网打印机更方便。
+
+但更换所有打印机可能会很昂贵 —— 特别是如果你对现有的打印机感到满意的话。
+
+[将树莓派设置为打印服务器][5]可能会更有意义。
+
+### 网络附加存储(NAS)
+
+将硬盘变为 NAS 是树莓派最早的实际应用之一,并且它仍然是最好的之一。
+
+[这是如何使用树莓派创建 NAS。][6]
+
+### 工单服务器
+
+想要在预算不足的情况下在服务台中支持工单?
+
+有一个名为 osTicket 的完全开源的工单程序,它可以安装在你的树莓派上,它甚至还有[随时可用的 SD 卡镜像][7]。
+
+### 数字标牌
+
+无论是用于活动、广告、菜单还是其他任何东西,许多企业都需要一种显示数字标牌的方式 —— 而树莓派的廉价和省电使其成为一个非常有吸引力的选择。
+
+[这有很多可供选择的选项。] [8]
+
+### 目录和信息亭
+
+[FullPageOS][9] 是一个基于 Raspbian 的 Linux 发行版,它直接引导到 Chromium 的全屏版本 —— 这非常适合导购、图书馆目录等。
+
+### 基本的内联网 Web 服务器
+
+对于托管一个面向公众的网站,你最好有一个托管帐户。树莓派不适合面对真正的网络流量。
+
+但对于小型办公室,它可以托管内部业务维基或基本的公司内网。它还可以用作沙箱环境,用于试验代码和服务器配置。
+
+[这里是如何在树莓派上运行 Apache、MySQL 和 PHP。][10]
+
+### 渗透测试器
+
+Kali Linux 是专为探测网络安全漏洞而构建的操作系统。通过将其安装在树莓派上,你就拥有了一个超便携式穿透测试器,其中包含 600 多种工具。
+
+[你可以在这里找到树莓派镜像的种子链接。][11]
+
+绝对要小心只在你自己的网络或你有权对它安全审计的网络中使用它 —— 使用此方法来破解其他网络是严重的犯罪行为。
+
+### VPN 服务器
+
+当你外出时,依靠的是公共无线互联网,你无法控制还有谁在网络中、谁在窥探你的所有流量。这就是为什么通过 VPN 连接加密所有内容可以让人放心。
+
+你可以订阅任意数量的商业 VPN 服务,并且你可以在云中安装自己的服务,但是在办公室运行一个 VPN,这样你也可以从任何地方访问本地网络。
+
+对于轻度使用 —— 比如偶尔的商务旅行 —— 树莓派是一种强大的,节约能源的设置 VPN 服务器的方式。(首先要检查一下你的路由器是不是不支持这个功能,许多路由器是支持的。)
+
+[这是如何在树莓派上安装 OpenVPN。][12]
+
+### 无线咖啡机
+
+啊,美味:好喝的饮料是神赐之物,也是公司内工作效率的支柱。
+
+那么,为什么不[将办公室的咖啡机变成可以精确控制温度和无线连接的智能咖啡机呢?][13]
+
+--------------------------------------------------------------------------------
+
+via: https://blog.dxmtechsupport.com.au/11-uses-for-a-raspberry-pi-around-the-office/
+
+作者:[James Mawson][a]
+选题:[lujun9972][b]
+译者:[geekpi](https://github.com/geekpi)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]: https://blog.dxmtechsupport.com.au/author/james-mawson/
+[b]: https://github.com/lujun9972
+[1]: https://dxmtechsupport.com.au/server-configuration
+[2]: https://www.1and1.com/digitalguide/server/configuration/how-to-make-your-raspberry-pi-into-a-dns-server/
+[3]: https://blog.usejournal.com/occu-pi-the-bathroom-of-the-future-ed69b84e21d5
+[4]: https://trustfoundry.net/honeypi-easy-honeypot-raspberry-pi/
+[5]: https://opensource.com/article/18/3/print-server-raspberry-pi
+[6]: https://howtoraspberrypi.com/create-a-nas-with-your-raspberry-pi-and-samba/
+[7]: https://everyday-tech.com/a-raspberry-pi-ticketing-system-image-with-osticket/
+[8]: https://blog.capterra.com/7-free-and-open-source-digital-signage-software-options-for-your-next-event/
+[9]: https://github.com/guysoft/FullPageOS
+[10]: https://maker.pro/raspberry-pi/projects/raspberry-pi-web-server
+[11]: https://www.offensive-security.com/kali-linux-arm-images/
+[12]: https://medium.freecodecamp.org/running-your-own-openvpn-server-on-a-raspberry-pi-8b78043ccdea
+[13]: https://www.techradar.com/au/how-to/how-to-build-your-own-smart-coffee-machine
diff --git a/published/20180806 GPaste Is A Great Clipboard Manager For Gnome Shell.md b/published/201812/20180806 GPaste Is A Great Clipboard Manager For Gnome Shell.md
similarity index 100%
rename from published/20180806 GPaste Is A Great Clipboard Manager For Gnome Shell.md
rename to published/201812/20180806 GPaste Is A Great Clipboard Manager For Gnome Shell.md
diff --git a/published/20180806 Systemd Timers- Three Use Cases.md b/published/201812/20180806 Systemd Timers- Three Use Cases.md
similarity index 100%
rename from published/20180806 Systemd Timers- Three Use Cases.md
rename to published/201812/20180806 Systemd Timers- Three Use Cases.md
diff --git a/published/201812/20180814 HTTP request routing and validation with gorilla-mux.md b/published/201812/20180814 HTTP request routing and validation with gorilla-mux.md
new file mode 100644
index 0000000000..4dcf7f7f52
--- /dev/null
+++ b/published/201812/20180814 HTTP request routing and validation with gorilla-mux.md
@@ -0,0 +1,472 @@
+使用 gorilla/mux 进行 HTTP 请求路由和验证
+======
+
+> gorilla/mux 包以直观的 API 提供了 HTTP 请求路由、验证和其它服务。
+
+
+
+Go 网络库包括 `http.ServeMux` 结构类型,它支持 HTTP 请求多路复用(路由):Web 服务器将托管资源的 HTTP 请求与诸如 `/sales4today` 之类的 URI 路由到代码处理程序;处理程序在发送 HTTP 响应(通常是 HTML 页面)之前执行适当的逻辑。 这是该体系的草图:
+
+```
+ +-----------+ +--------+ +---------+
+HTTP 请求---->| web 服务器 |---->| 路由 |---->| 处理程序 |
+ +-----------+ +--------+ +---------+
+```
+
+调用 `ListenAndServe` 方法后启动 HTTP 服务器:
+
+```
+http.ListenAndServe(":8888", nil) // args: port & router
+```
+
+第二个参数 `nil` 意味着 `DefaultServeMux` 用于请求路由。
+
+`gorilla/mux` 库包含 `mux.Router` 类型,可替代 `DefaultServeMux` 或自定义请求多路复用器。 在 `ListenAndServe` 调用中,`mux.Router` 实例将代替 `nil` 作为第二个参数。 下面的示例代码很好的说明了为什么 `mux.Router`如此吸引人:
+
+### 1、一个简单的 CRUD web 应用程序
+
+crud web 应用程序(见下文)支持四种 CRUD(创建/读取/更新/删除)操作,它们分别对应四种 HTTP 请求方法:POST、GET、PUT 和 DELETE。 在这个 CRUD 应用程序中,所管理的资源是套话与反套话的列表,每个都是套话及其反面的的套话,例如这对:
+
+```
+Out of sight, out of mind. Absence makes the heart grow fonder.
+```
+
+可以添加新的套话对,可以编辑或删除现有的套话对。
+
+CRUD web 应用程序:
+
+```
+package main
+
+import (
+ "gorilla/mux"
+ "net/http"
+ "fmt"
+ "strconv"
+)
+
+const GETALL string = "GETALL"
+const GETONE string = "GETONE"
+const POST string = "POST"
+const PUT string = "PUT"
+const DELETE string = "DELETE"
+
+type clichePair struct {
+ Id int
+ Cliche string
+ Counter string
+}
+
+// Message sent to goroutine that accesses the requested resource.
+type crudRequest struct {
+ verb string
+ cp *clichePair
+ id int
+ cliche string
+ counter string
+ confirm chan string
+}
+
+var clichesList = []*clichePair{}
+var masterId = 1
+var crudRequests chan *crudRequest
+
+// GET /
+// GET /cliches
+func ClichesAll(res http.ResponseWriter, req *http.Request) {
+ cr := &crudRequest{verb: GETALL, confirm: make(chan string)}
+ completeRequest(cr, res, "read all")
+}
+
+// GET /cliches/id
+func ClichesOne(res http.ResponseWriter, req *http.Request) {
+ id := getIdFromRequest(req)
+ cr := &crudRequest{verb: GETONE, id: id, confirm: make(chan string)}
+ completeRequest(cr, res, "read one")
+}
+
+// POST /cliches
+func ClichesCreate(res http.ResponseWriter, req *http.Request) {
+ cliche, counter := getDataFromRequest(req)
+ cp := new(clichePair)
+ cp.Cliche = cliche
+ cp.Counter = counter
+ cr := &crudRequest{verb: POST, cp: cp, confirm: make(chan string)}
+ completeRequest(cr, res, "create")
+}
+
+// PUT /cliches/id
+func ClichesEdit(res http.ResponseWriter, req *http.Request) {
+ id := getIdFromRequest(req)
+ cliche, counter := getDataFromRequest(req)
+ cr := &crudRequest{verb: PUT, id: id, cliche: cliche, counter: counter, confirm: make(chan string)}
+ completeRequest(cr, res, "edit")
+}
+
+// DELETE /cliches/id
+func ClichesDelete(res http.ResponseWriter, req *http.Request) {
+ id := getIdFromRequest(req)
+ cr := &crudRequest{verb: DELETE, id: id, confirm: make(chan string)}
+ completeRequest(cr, res, "delete")
+}
+
+func completeRequest(cr *crudRequest, res http.ResponseWriter, logMsg string) {
+ crudRequests<-cr
+ msg := <-cr.confirm
+ res.Write([]byte(msg))
+ logIt(logMsg)
+}
+
+func main() {
+ populateClichesList()
+
+ // From now on, this gorountine alone accesses the clichesList.
+ crudRequests = make(chan *crudRequest, 8)
+ go func() { // resource manager
+ for {
+ select {
+ case req := <-crudRequests:
+ if req.verb == GETALL {
+ req.confirm<-readAll()
+ } else if req.verb == GETONE {
+ req.confirm<-readOne(req.id)
+ } else if req.verb == POST {
+ req.confirm<-addPair(req.cp)
+ } else if req.verb == PUT {
+ req.confirm<-editPair(req.id, req.cliche, req.counter)
+ } else if req.verb == DELETE {
+ req.confirm<-deletePair(req.id)
+ }
+ }
+ }()
+ startServer()
+}
+
+func startServer() {
+ router := mux.NewRouter()
+
+ // Dispatch map for CRUD operations.
+ router.HandleFunc("/", ClichesAll).Methods("GET")
+ router.HandleFunc("/cliches", ClichesAll).Methods("GET")
+ router.HandleFunc("/cliches/{id:[0-9]+}", ClichesOne).Methods("GET")
+
+ router.HandleFunc("/cliches", ClichesCreate).Methods("POST")
+ router.HandleFunc("/cliches/{id:[0-9]+}", ClichesEdit).Methods("PUT")
+ router.HandleFunc("/cliches/{id:[0-9]+}", ClichesDelete).Methods("DELETE")
+
+ http.Handle("/", router) // enable the router
+
+ // Start the server.
+ port := ":8888"
+ fmt.Println("\nListening on port " + port)
+ http.ListenAndServe(port, router); // mux.Router now in play
+}
+
+// Return entire list to requester.
+func readAll() string {
+ msg := "\n"
+ for _, cliche := range clichesList {
+ next := strconv.Itoa(cliche.Id) + ": " + cliche.Cliche + " " + cliche.Counter + "\n"
+ msg += next
+ }
+ return msg
+}
+
+// Return specified clichePair to requester.
+func readOne(id int) string {
+ msg := "\n" + "Bad Id: " + strconv.Itoa(id) + "\n"
+
+ index := findCliche(id)
+ if index >= 0 {
+ cliche := clichesList[index]
+ msg = "\n" + strconv.Itoa(id) + ": " + cliche.Cliche + " " + cliche.Counter + "\n"
+ }
+ return msg
+}
+
+// Create a new clichePair and add to list
+func addPair(cp *clichePair) string {
+ cp.Id = masterId
+ masterId++
+ clichesList = append(clichesList, cp)
+ return "\nCreated: " + cp.Cliche + " " + cp.Counter + "\n"
+}
+
+// Edit an existing clichePair
+func editPair(id int, cliche string, counter string) string {
+ msg := "\n" + "Bad Id: " + strconv.Itoa(id) + "\n"
+ index := findCliche(id)
+ if index >= 0 {
+ clichesList[index].Cliche = cliche
+ clichesList[index].Counter = counter
+ msg = "\nCliche edited: " + cliche + " " + counter + "\n"
+ }
+ return msg
+}
+
+// Delete a clichePair
+func deletePair(id int) string {
+ idStr := strconv.Itoa(id)
+ msg := "\n" + "Bad Id: " + idStr + "\n"
+ index := findCliche(id)
+ if index >= 0 {
+ clichesList = append(clichesList[:index], clichesList[index + 1:]...)
+ msg = "\nCliche " + idStr + " deleted\n"
+ }
+ return msg
+}
+
+//*** utility functions
+func findCliche(id int) int {
+ for i := 0; i < len(clichesList); i++ {
+ if id == clichesList[i].Id {
+ return i;
+ }
+ }
+ return -1 // not found
+}
+
+func getIdFromRequest(req *http.Request) int {
+ vars := mux.Vars(req)
+ id, _ := strconv.Atoi(vars["id"])
+ return id
+}
+
+func getDataFromRequest(req *http.Request) (string, string) {
+ // Extract the user-provided data for the new clichePair
+ req.ParseForm()
+ form := req.Form
+ cliche := form["cliche"][0] // 1st and only member of a list
+ counter := form["counter"][0] // ditto
+ return cliche, counter
+}
+
+func logIt(msg string) {
+ fmt.Println(msg)
+}
+
+func populateClichesList() {
+ var cliches = []string {
+ "Out of sight, out of mind.",
+ "A penny saved is a penny earned.",
+ "He who hesitates is lost.",
+ }
+ var counterCliches = []string {
+ "Absence makes the heart grow fonder.",
+ "Penny-wise and dollar-foolish.",
+ "Look before you leap.",
+ }
+
+ for i := 0; i < len(cliches); i++ {
+ cp := new(clichePair)
+ cp.Id = masterId
+ masterId++
+ cp.Cliche = cliches[i]
+ cp.Counter = counterCliches[i]
+ clichesList = append(clichesList, cp)
+ }
+}
+```
+
+为了专注于请求路由和验证,CRUD 应用程序不使用 HTML 页面作为请求响应。 相反,请求会产生明文响应消息:套话对的列表是对 GET 请求的响应,确认新的套话对已添加到列表中是对 POST 请求的响应,依此类推。 这种简化使得使用命令行实用程序(如 [curl][1])可以轻松地测试应用程序,尤其是 `gorilla/mux` 组件。
+
+`gorilla/mux` 包可以从 [GitHub][2] 安装。 CRUD app 无限期运行;因此,应使用 `Control-C` 或同等命令终止。 CRUD 应用程序的代码,以及自述文件和简单的 curl 测试,可以在[我的网站] [3]上找到。
+
+### 2、请求路由
+
+`mux.Router` 扩展了 REST 风格的路由,它赋给 HTTP 方法(例如,GET)和 URL 末尾的 URI 或路径(例如 `/cliches`)相同的权重。 URI 用作 HTTP 动词(方法)的名词。 例如,在HTTP请求中有一个起始行,例如:
+
+```
+GET /cliches
+```
+
+意味着得到所有的套话对,而一个起始线,如:
+
+```
+POST /cliches
+```
+
+意味着从 HTTP 正文中的数据创建一个套话对。
+
+在 CRUD web 应用程序中,有五个函数充当 HTTP 请求的五种变体的请求处理程序:
+
+```
+ClichesAll(...) # GET: 获取所有的套话对
+ClichesOne(...) # GET: 获取指定的套话对
+ClichesCreate(...) # POST: 创建新的套话对
+ClichesEdit(...) # PUT: 编辑现有的套话对
+ClichesDelete(...) # DELETE: 删除指定的套话对
+```
+
+每个函数都有两个参数:一个 `http.ResponseWriter` 用于向请求者发送一个响应,一个指向 `http.Request` 的指针,该指针封装了底层 HTTP 请求的信息。 使用 `gorilla/mux` 包可以轻松地将这些请求处理程序注册到Web服务器,并执行基于正则表达式的验证。
+
+CRUD 应用程序中的 `startServer` 函数注册请求处理程序。 考虑这对注册,`router` 作为 `mux.Router` 实例:
+
+```
+router.HandleFunc("/", ClichesAll).Methods("GET")
+router.HandleFunc("/cliches", ClichesAll).Methods("GET")
+```
+
+这些语句意味着对单斜线 `/` 或 `/cliches` 的 GET 请求应该路由到 `ClichesAll` 函数,然后处理请求。 例如,curl 请求(使用 `%` 作为命令行提示符):
+
+```
+% curl --request GET localhost:8888/
+```
+
+会产生如下结果:
+
+```
+1: Out of sight, out of mind. Absence makes the heart grow fonder.
+2: A penny saved is a penny earned. Penny-wise and dollar-foolish.
+3: He who hesitates is lost. Look before you leap.
+```
+
+这三个套话对是 CRUD 应用程序中的初始数据。
+
+在这句注册语句中:
+
+```
+router.HandleFunc("/cliches", ClichesAll).Methods("GET")
+router.HandleFunc("/cliches", ClichesCreate).Methods("POST")
+```
+
+URI 是相同的(`/cliches`),但动词不同:第一种情况下为 GET 请求,第二种情况下为 POST 请求。 此注册举例说明了 REST 样式的路由,因为仅动词的不同就足以将请求分派给两个不同的处理程序。
+
+注册中允许多个 HTTP 方法,尽管这会影响 REST 风格路由的精髓:
+
+```
+router.HandleFunc("/cliches", DoItAll).Methods("POST", "GET")
+```
+
+除了动词和 URI 之外,还可以在功能上路由 HTTP 请求。 例如,注册
+
+```
+router.HandleFunc("/cliches", ClichesCreate).Schemes("https").Methods("POST")
+```
+
+要求对 POST 请求进行 HTTPS 访问以创建新的套话对。以类似的方式,注册可能需要具有指定的 HTTP 头元素(例如,认证凭证)的请求。
+
+### 3、 Request validation
+
+`gorilla/mux` 包采用简单,直观的方法通过正则表达式进行请求验证。 考虑此请求处理程序以获取一个操作:
+
+```
+router.HandleFunc("/cliches/{id:[0-9]+}", ClichesOne).Methods("GET")
+```
+
+此注册排除了 HTTP 请求,例如:
+
+```
+% curl --request GET localhost:8888/cliches/foo
+```
+
+因为 foo 不是十进制数字。该请求导致熟悉的 404(未找到)状态码。 在此处理程序注册中包含正则表达式模式可确保仅在请求 URI 以十进制整数值结束时才调用 `ClichesOne` 函数来处理请求:
+
+```
+% curl --request GET localhost:8888/cliches/3 # ok
+```
+
+另一个例子,请求如下:
+
+```
+% curl --request PUT --data "..." localhost:8888/cliches
+```
+
+此请求导致状态代码为 405(错误方法),因为 /cliches URI 在 CRUD 应用程序中仅在 GET 和 POST 请求中注册。 像 GET 请求一样,PUT 请求必须在 URI 的末尾包含一个数字 id:
+
+```
+router.HandleFunc("/cliches/{id:[0-9]+}", ClichesEdit).Methods("PUT")
+```
+
+### 4、并发问题
+
+`gorilla/mux` 路由器作为单独的 Go 协程执行对已注册的请求处理程序的每次调用,这意味着并发性被内置于包中。 例如,如果有十个同时发出的请求,例如
+
+```
+% curl --request POST --data "..." localhost:8888/cliches
+```
+
+然后 `mux.Router` 启动十个 Go 协程来执行 `ClichesCreate` 处理程序。
+
+GET all、GET one、POST、PUT 和 DELETE 中的五个请求操作中,最后三个改变了所请求的资源,即包含套话对的共享 `clichesList`。 因此,CRUD app 需要通过协调对 `clichesList` 的访问来保证安全的并发性。 在不同但等效的术语中,CRUD app 必须防止 `clichesList` 上的竞争条件。 在生产环境中,可以使用数据库系统来存储诸如 `clichesList` 之类的资源,然后可以通过数据库事务来管理安全并发。
+
+CRUD 应用程序采用推荐的Go方法来实现安全并发:
+
+* 只有一个 Go 协程,资源管理器在 CRUD app `startServer` 函数中启动,一旦 Web 服务器开始侦听请求,就可以访问 `clichesList`。
+* 诸如 `ClichesCreate` 和 `ClichesAll` 之类的请求处理程序向 Go 通道发送(指向)`crudRequest` 实例(默认情况下是线程安全的),并且资源管理器单独从该通道读取。 然后,资源管理器对 `clichesList` 执行请求的操作。
+
+安全并发体系结构绘制如下:
+
+```
+ crudRequest 读/写
+
+请求处理程序 -------------> 资源托管者 ------------> 套话列表
+
+```
+
+在这种架构中,不需要显式锁定 `clichesList`,因为一旦 CRUD 请求开始进入,只有一个 Go 协程(资源管理器)访问 `clichesList`。
+
+为了使 CRUD 应用程序尽可能保持并发,在一方请求处理程序与另一方的单一资源管理器之间进行有效的分工至关重要。 在这里,为了审查,是 `ClichesCreate` 请求处理程序:
+
+```
+func ClichesCreate(res http.ResponseWriter, req *http.Request) {
+ cliche, counter := getDataFromRequest(req)
+ cp := new(clichePair)
+ cp.Cliche = cliche
+ cp.Counter = counter
+ cr := &crudRequest{verb: POST, cp: cp, confirm: make(chan string)}
+ completeRequest(cr, res, "create")
+}
+```
+
+`ClichesCreate` 调用实用函数 `getDataFromRequest`,它从 POST 请求中提取新的套话和反套话。 然后 `ClichesCreate` 函数创建一个新的 `ClichePair`,设置两个字段,并创建一个 `crudRequest` 发送给单个资源管理器。 此请求包括一个确认通道,资源管理器使用该通道将信息返回给请求处理程序。 所有设置工作都可以在不涉及资源管理器的情况下完成,因为尚未访问 `clichesList`。
+
+请求处理程序调用实用程序函数,该函数从 POST 请求中提取新的套话和反套话。 然后,该函数创建一个新的,设置两个字段,并创建一个 crudRequest 发送到单个资源管理器。 此请求包括一个确认通道,资源管理器使用该通道将信息返回给请求处理程序。 所有设置工作都可以在不涉及资源管理器的情况下完成,因为尚未访问它。
+
+`completeRequest` 实用程序函数在 `ClichesCreate` 函数和其他请求处理程序的末尾调用:
+
+```
+completeRequest(cr, res, "create") // shown above
+```
+
+通过将 `crudRequest` 放入 `crudRequests` 频道,使资源管理器发挥作用:
+
+```
+func completeRequest(cr *crudRequest, res http.ResponseWriter, logMsg string) {
+ crudRequests<-cr // 向资源托管者发送请求
+ msg := <-cr.confirm // 等待确认
+ res.Write([]byte(msg)) // 向请求方发送确认
+ logIt(logMsg) // 打印到标准输出
+}
+```
+
+对于 POST 请求,资源管理器调用实用程序函数 `addPair`,它会更改 `clichesList` 资源:
+
+```
+func addPair(cp *clichePair) string {
+ cp.Id = masterId // 分配一个唯一的 ID
+ masterId++ // 更新 ID 计数器
+ clichesList = append(clichesList, cp) // 更新列表
+ return "\nCreated: " + cp.Cliche + " " + cp.Counter + "\n"
+}
+```
+
+资源管理器为其他 CRUD 操作调用类似的实用程序函数。 值得重复的是,一旦 Web 服务器开始接受请求,资源管理器就是唯一可以读取或写入 `clichesList` 的 goroutine。
+
+对于任何类型的 Web 应用程序,`gorilla/mux` 包在简单直观的 API 中提供请求路由、请求验证和相关服务。 CRUD web 应用程序突出了软件包的主要功能。
+
+--------------------------------------------------------------------------------
+
+via: https://opensource.com/article/18/8/http-request-routing-validation-gorillamux
+
+作者:[Marty Kalin][a]
+选题:[lujun9972](https://github.com/lujun9972)
+译者:[yongshouzhang](https://github.com/yongshouzhang)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://opensource.com/users/mkalindepauledu
+[1]:https://curl.haxx.se/
+[2]:https://github.com/gorilla/mux
+[3]:http://condor.depaul.edu/mkalin
diff --git a/published/20180817 Mixing software development roles produces great results.md b/published/201812/20180817 Mixing software development roles produces great results.md
similarity index 100%
rename from published/20180817 Mixing software development roles produces great results.md
rename to published/201812/20180817 Mixing software development roles produces great results.md
diff --git a/published/201812/20180826 How to Install and Use FreeDOS on VirtualBox.md b/published/201812/20180826 How to Install and Use FreeDOS on VirtualBox.md
new file mode 100644
index 0000000000..3474815526
--- /dev/null
+++ b/published/201812/20180826 How to Install and Use FreeDOS on VirtualBox.md
@@ -0,0 +1,153 @@
+如何在 VirtualBox 上安装并使用 FreeDOS?
+======
+
+> 这份指南将带你如何一步一步在 Linux 平台下利用 VirtualBox 安装 FreeDOS。
+
+### Linux 下借助 VirtualBox 安装 FreeDOS
+
+- [How to Install FreeDOS in Linux using Virtual Box](https://www.youtube.com/p1MegqzFAqA)
+
+2017 年的 11 月份,我[采访了 Jim Hall][1] 关于 [FreeDOS 项目][2] 背后的历史故事。今天,我将告诉你如何安装并使用 FreeDOS。需要注意到是:我将在 [Solus][4](一种针对家庭用户的 Linux 桌面发行版)下使用 5.2.14 版本的 [VirtualBox][3] 来完成这些操作。
+
+> 注意:在本教程我将使用 Solus 作为主机系统因为它很容易设置。另一个你需要注意的事情是 Solus 的软件中心有两个版本的 VirtualBox:`virtualbox` 和 `virtualbox-current`。Solus 会让你选择是使用 linux-lts 内核还是 linux-current 内核。最终区别就是,`virtualbox` 适用于 linux-lts 而 `virtualbx-current` 适用于 linux-current。
+
+#### 第一步 – 创建新的虚拟机
+
+![][5]
+
+当你打开 VirtualBox,点击 “New” 按钮来新建一个虚拟机。你可以自定义这台虚拟机的名字,我将它命名为 “FreeDOS”。你也可以在标注栏内指明你正在安装的 FreeDOS 的版本。你还需要选择你将要安装的操作系统的类型和版本。选择 “Other” 下的 “DOS”。
+
+#### 第二步 – 设置内存大小
+
+![][6]
+
+下一个对话框会问你要给 FreeDOS 主机分配多少可用的内存空间。默认分配 32 MB。不必更改它。在 DOS 系统盛行的年代,32 MB 大小的内存对于一台搭载 FreeDOS 的机器已经很足够了。如果你有需要,你可以通过对你针对 FreeDOS 新建的虚拟机右键并选择 “Setting -> Symtem” 来增加内存。
+
+![][7]
+
+#### 第三步 – 创建虚拟硬盘
+
+![][8]
+
+下一步,你会被要求创建一个虚拟硬盘用来存储 FreeDOS 和它的文件。如果你还没有创建,只需要点击 “Create”。
+
+下一个对话框会问你想用什么磁盘文件类型。默认的类型 (VirtualBox Disk Image) 效果就挺好。点击 “Next”。
+
+下一个你遇到的问题是你想虚拟硬盘以何种方式创建。你是否希望虚拟硬盘占据的空间刚开始很小然后会随着你创建文件和安装软件逐渐增加直至达到你设置的上限?那么选择动态分配。如果你更喜欢虚拟硬盘 (VHD) 按照既定大小直接创建,选择固定大小即可。如果你不打算使用整个 VHD 或者你的硬盘空余空间不是太足够,那么动态分配是个很不错的分配方式。(需要注意的是,动态分配的虚拟硬盘占据的空间会随着你增加文件而增加,但不会因为你删除文件而变小) 我个人更喜欢动态分配,但你可以根据实际需要来选择最合适你的分配类型然后点击 “Next”。
+
+![][9]
+
+现在,你可以选择虚拟磁盘的大小和位置。500 MB 已经很足够了。需要注意的是很多你之后用到的程序都是基于文本的,这意味着它们占据的空间非常小。在你做好这些调整后,点击 “Create”。
+
+#### 第四步 – 关联 .iso 文件
+
+在我们继续之前,你需要[下载][10] FreeDOS 的 .iso 文件。你需要选择 CDROM 格式的 “standard” 安装程序。
+
+![][11]
+
+当文件下载完毕后,返回到 VirtualBox。选中你的虚拟机并打开设置。你可以通过对虚拟机右键并选中 “Setting” 或者选中虚拟机并点击 “Setting” 按钮。
+
+接下来,点击 “Storage” 选项卡。在 “Storage Devices” 下面,选中 CD 图标。(它应该会在图标旁边显示 “Empty”。) 在右边的 “Attribute” 面板,点中 CD 图标然后在对应路径选中你刚下载的 .iso 文件。
+
+> 提示:通常,在你通过 VirtualBox 安装完一个操作系统后你就可以删除对应的 .iso 文件了。但这并不适合 FreeDOS 。如果你想通过 FreeDOS 的包管理器来安装应用程序,你需要这个 .iso 文件。我通常会让这个 .iso 文件连接到虚拟机以便我安装一些程序。如果你也这么做了,你必须要确认下你让 FreeDOS 虚拟机每次启动的时候是从硬盘启动因为虚拟机的默认设置是从已关联的 .iso 文件启动。如果你忘了关联 .iso 文件,也不用担心。你可以通过选择 FreeDOS 虚拟机窗口上方的 “Devices” 来关联。然后就会发现 .iso 文件列在 “Optical Drives”。
+
+#### 第五步 – 安装 FreeDOS
+
+![][12]
+
+既然我们已经完成了所有的准备工作,让我们来开始安装 FreeDOS 吧。
+
+首先,你需要知道关于最新版本的 VirtualBox 的一个 bug。当我们创建好虚拟硬盘然后选中 “Install to harddisk” 后,如果你开启虚拟机你会发现在 FreeDOS 的欢迎界面出现过后就是不断滚动无群无尽的机器代码。我最近就遇到过这个问题而且不管是 Linux 还是 Windows 平台的 VirtualBox 都会碰到这个问题。(我知道解决办法。)
+
+为了避开这个问题,你需要做一个简单的修改。当你看到 FreeDOS 的欢迎界面的时候,按下 Tab 键。(确认 “Install to harddrive” 已经选中。)在 “fdboot.img” 之后输入 `raw` 然后按下回车键。接下来就会启动 FreeDOS 的安装程序。
+
+![][13]
+
+安装程序会首先处理你的虚拟磁盘的格式化。当格式化完成后,安装程序会重启。当 FreeDOS 的欢迎界面再次出现的时候,你必须重新输入 `raw` 就像你之前输入的内容那样。
+
+要确保在安装过程中你遇到的所有问题你选的都是 “Yes”。但也要注意有一个很重要的问题:“What FreeDOS packages do you want to install?” 的答案并不是 “Yes” 或者 “No”。答案有两个选择分别是 “Base packages” 和 “Full installation”。“Base packages” 针对的是想体验类似原始的 MS-DOS 环境的人群。“Full installation” 则包括了一系列工具和实用的程序来提升 DOS。
+
+在整个安装过程的最后,你可以选择重启或者继续停留在 DOS。选择“reboot”。
+
+#### 第六步 – 设置网络
+
+不同于原始的 DOS,FreeDOS 可以访问互联网。你可以安装新的软件包或者更新你已经安装的软件包。要想使用网络,你还需要在 FreeDOS 安装些应用程序。
+
+![][14]
+
+首先,启动进入你新创建的 FreeDOS 虚拟机。在 FreeDOS 的选择界面,选中 “Boot from System harddrive”。
+
+![][15]
+
+现在,你可以通过输入 `fdimples` 来访问 FreeDOS 的软件包管理工具。你也可以借助方向键来浏览软件包管理器,然后用空格键选择类别或者软件包。在 “Networking” 类别中,你需要选中 `fdnet`。FreeDOS project 推荐也安装 `mtcp` 和 `wget`。多次点击 Tab 键直到选中 “OK” 然后在按下回车键。安装完成后,输入 `reboot` 并按下回车键确认执行。系统重启后,引导你的系统驱动。如果网络安装成功的话,你会在终端看到一些关于你的网络信息的新消息。
+
+![][16]
+
+注意:
+
+有时候 VirtualBox 的默认设置并没有生效。如果遇到这种情况,先关闭你的 FreeDOS 虚拟机窗口。在 VirtualBox 主界面右键你的虚拟机并选中 “Setting”。VirtualBox 默认的网络设置是 “NAT”。将它改为 “Bridged Adapter” 后再尝试安装 FreeDOS 的软件包。现在就应该能正常运作了。
+
+#### 第七步 – FreeDOS 的基本使用
+
+##### 常见命令
+
+既然你已经成功安装了 FreeDOS,让我们来看些基础命令。如果你已经在 Windows 平台使用过命令提示符,那么你会发现有很多命令都是相似的。
+
+ * `DIR`– 显示当前目录的内容
+ * `CD` – 改变当前所在的目录
+ * `COPY OLD.TXT NEW.TXT`– 复制文件
+ * `TYPE TEST.TXT` – 显示文件内容
+ * `DEL TEST.TXT` – 删除文件
+ * `XCOPY DIR NEWDIR` – 复制目录及目录下的所有内容
+ * `EDIT TEST.TXT`– 编辑一个文件
+ * `MKDIR NEWDIR` – 创建一个新目录
+ * `CLS` – 清除屏幕
+
+你可以借助互联网或者 Jim Hall 所创建的 [方便的速查表][17] 来找到更多基本的 DOS 命令。
+
+##### 运行一个程序
+
+在 FreeDOS 上运行程序相当简单。需要注意的是当你借助 `fdimples` 软件包管理器来安装一个应用程序的时候,要确保你指定了待安装程序的 .EXE 文件的路径。这个路径会在应用程序的详细信息中显示。要想运行程序,通常你还需要进入到程序所在文件夹并输入该程序的名字。
+
+例如,FreeDOS 中你可以安装一个叫 `FED` 的编辑器。安装完成后,你还需要做的就是进入 `C:\FED` 这个文件夹下并输入 `FED`。
+
+对于位于 `\bin` 这个文件夹的程序,比如 Pico。这些程序可以在任意文件夹中被调用。
+
+对于游戏通常会有一个或者两个 .EXE 程序,你玩游戏之前不得不先运行它们。这些设置文件通常能够修复你遇到的声音,视频,或者控制问题。
+
+如果你遇到一些本教程中没指出的问题,别忘记访问 [FreeDOS 主站][2] 来寻求解决办法。他们有一个 wiki 和一些其他的支持选项。
+
+你使用过 FreeDOS 吗?你还想看关于 FreeDOS 哪些方面的教程?请在下面的评论区告诉我们。
+
+如果你觉得本篇文章很有趣,请花一分钟的时间将它分享在你的社交媒体,Hacker News 或者 [Reddit][18]。
+
+--------------------------------------------------------------------------------
+
+via: https://itsfoss.com/install-freedos/
+
+作者:[John Paul][a]
+选题:[lujun9972](https://github.com/lujun9972)
+译者:[WangYueScream](https://github.com/WangYueScream)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]: https://itsfoss.com/author/john/
+[1]:https://itsfoss.com/interview-freedos-jim-hall/
+[2]:http://www.freedos.org/
+[3]:https://www.virtualbox.org/
+[4]:https://solus-project.com/home/
+[5]:https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-1.jpg?w=787&ssl=1
+[6]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-2.jpg?w=792&ssl=1
+[7]:https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-3.jpg?w=797&ssl=1
+[8]:https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-4.jpg?w=684&ssl=1
+[9]:https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-6.jpg?w=705&ssl=1
+[10]:http://www.freedos.org/download/
+[11]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-7.jpg?w=800&ssl=1
+[12]:https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-8.png?w=789&ssl=1
+[13]:https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-9.png?w=748&ssl=1
+[14]:https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-10.png?w=792&ssl=1
+[15]:https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-11.png?w=739&ssl=1
+[16]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-12.png?w=744&ssl=1
+[17]:https://opensource.com/article/18/6/freedos-commands-cheat-sheet
+[18]:http://reddit.com/r/linuxusersgroup
diff --git a/published/201812/20180828 An Introduction to Quantum Computing with Open Source Cirq Framework.md b/published/201812/20180828 An Introduction to Quantum Computing with Open Source Cirq Framework.md
new file mode 100644
index 0000000000..c1be5d0ddf
--- /dev/null
+++ b/published/201812/20180828 An Introduction to Quantum Computing with Open Source Cirq Framework.md
@@ -0,0 +1,225 @@
+量子计算的开源框架 Cirq 介绍
+======
+
+我们即将讨论的内容正如标题所示,本文通过使用 Cirq 的一个开源视角,尝试去了解我们已经在量子计算领域取得多大的成就,和该领域的发展方向,以加快科学和技术研究。
+
+首先,我们将引领你进入量子计算的世界。在我们深入了解 Cirq 在未来的量子计算中扮演什么样的重要角色之前,我们将尽量向你解释其背后的基本概念。你最近可能听说过,在这个领域中有件重大新闻,就是 Cirq。在这篇开放科学栏目的文章中,我们将去尝试找出答案。
+
+- [How it Works - Quantum Computing](https://www.youtube.com/WVv5OAR4Nik)
+
+在我们开始了解量子计算之前,必须先去了解“量子”这个术语,量子是已知的 [亚原子粒子][1] 中最小的物质。[量子][2] 这个词来自拉丁语 Quantus,意思是 “有多小”,在下面的短视频链接中有描述:
+
+- [What is a quantum Why is it significant](https://www.youtube.com/-pUOxVsxu3o)
+
+为了易于我们理解量子计算,我们将量子计算与经典计算(LCTT 译注:也有译做“传统计算”)进行比较。经典计算是指今天的传统计算机如何设计工作的,正如你现在用于阅读本文的设备,就是我们所谓的经典计算设备。
+
+### 经典计算
+
+经典计算只是描述计算机如何工作的另一种方式。它们通过一个二进制系统工作,即信息使用 1 或 0 来存储。经典计算机不会理解除 1 或 0 之外的任何其它东西。
+
+直白来说,在计算机内部一个晶体管只能是开(1)或关(0)。我们输入的任何信息都被转换为无数个 1 和 0,以便计算机能理解和存储。所有的东西都只能用无数个 1 和 0 的组合来表示。
+
+- [Why Do Computers Use 1s and 0s Binary and Transistors Explained](https://www.youtube.com/Xpk67YzOn5w)
+
+### 量子计算
+
+然而,量子计算不再像经典计算那样遵循 “开或关” 的模式。而是,借助量子的名为 [叠加和纠缠][3] 的两个现象,能同时处理信息的多个状态,因此能以更快的速率加速计算,并且在信息存储方面效率更高。
+
+请注意,叠加和纠缠 [不是同一个现象][4]。
+
+- [How Do Quantum Computers Work!](https://www.youtube.com/jiXuVIEg10Q)
+
+![][5]
+
+就像在经典计算中,我们有比特,在量子计算中,我们相应也有量子比特(即 Quantum bit)。想了解它们二者之间的巨大差异之处,请查看这个 [页面][6],从那里的图片中可以得到答案。
+
+量子计算机并不是来替代我们的经典计算机的。但是,有一些非常巨大的任务用我们的经典计算机是无法完成的,而那些正是量子计算机大显身手的好机会。下面链接的视频详细描述了上述情况,同时也描述了量子计算机的原理。
+
+- [Quantum Computers Explained – Limits of Human Technology](https://www.youtube.com/JhHMJCUmq28)
+
+下面的视频全面描述了量子计算领域到目前为止的最新进展:
+
+- [Quantum Computing 2018 Update](https://www.youtube.com/CeuIop_j2bI)
+
+### 嘈杂中型量子
+
+根据最新更新的(2018 年 7 月 31 日)研究论文,术语 “嘈杂” 是指由于对量子比特未能完全控制所产生的不准确性。正是这种不准确性在短期内严重制约了量子设备实现其目标。
+
+“中型” 指的是在接下来的几年中,量子计算机将要实现的量子规模大小,届时,量子比特的数目将可能从 50 到几百个不等。50 个量子比特是一个重大的量程碑,因为它将超越现有的最强大的 [超级计算机][8] 的 [暴力破解][7] 所能比拟的计算能力。更多信息请阅读 [这里的][9] 论文。
+
+随着 Cirq 出现,许多事情将会发生变化。
+
+### Cirq 是什么?
+
+Cirq 是一个 Python 框架,它用于创建、编辑和调用我们前面讨论的嘈杂中型量子(NISQ)。换句话说,Cirq 能够解决挑战,去改善精确度和降低量子计算中的噪声。
+
+Cirq 并不需要必须有一台真实的量子计算机。Cirq 能够使用一个类似模拟器的界面去执行量子电路模拟。
+
+Cirq 的前进步伐越来越快了,[Zapata][10] 是使用它的首批用户之一,Zapata 是由来自哈佛大学的专注于量子计算的[一群科学家][11]在去年成立的。
+
+### Linux 上使用 Cirq 入门
+
+开源的 [Cirq 库][12] 开发者建议将它安装在像 [virtualenv][14] 这样的一个 [虚拟 Python 环境][13] 中。在 Linux 上的开发者安装指南可以在 [这里][15] 找到。
+
+但我们在 Ubuntu 16.04 的系统上成功地安装和测试了 Python3 的 Cirq 库,安装步骤如下:
+
+#### 在 Ubuntu 上安装 Cirq
+
+![Cirq Framework for Quantum Computing in Linux][16]
+
+首先,我们需要 `pip` 或 `pip3` 去安装 Cirq。[Pip][17] 是推荐用于安装和管理 Python 包的工具。
+
+对于 Python 3.x 版本,Pip 能够用如下的命令来安装:
+
+```
+sudo apt-get install python3-pip
+```
+
+Python3 包能够通过如下的命令来安装:
+
+```
+pip3 install
+```
+
+我们继续去使用 Pip3 为 Python3 安装 Cirq 库:
+
+```
+pip3 install cirq
+```
+
+#### 启用 Plot 和 PDF 生成(可选)
+
+可选系统的依赖没有被 Pip 安装的,可以使用如下命令去安装它:
+
+```
+sudo apt-get install python3-tk texlive-latex-base latexmk
+```
+
+ * python3-tk 是 Python 自有的启用了绘图功能的图形库
+ * texlive-latex-base 和 latexmk 启动了 PDF 输出功能。
+
+最后,我们使用如下的命令和代码成功测试了 Cirq:
+
+```
+python3 -c 'import cirq; print(cirq.google.Foxtail)'
+```
+
+我们得到的输出如下图:
+
+![][18]
+
+#### 为 Cirq 配置 Pycharm IDE
+
+我们也配置了一个 Python IDE [PyCharm][19] 去测试同样的结果:
+
+因为在我们的 Linux 系统上为 Python3 安装了 Cirq,我们在 IDE 中配置项目解释器路径为:
+
+```
+/usr/bin/python3
+```
+
+![][20]
+
+在上面的输出中,你可能注意到我们刚设置的项目解释器路径与测试程序文件(`test.py`)的路径显示在一起。退出代码 0 表示程序已经成功退出,没有错误。
+
+因此,那是一个已经就绪的 IDE 环境,你可以导入 Cirq 库去开始使用 Python 去编程和模拟量子电路。
+
+#### Cirq 使用入门
+
+Criq 入门的一个好的开端就是它 GitHub 页面上的 [示例][21]。
+
+Cirq 的开发者在 GitHub 上已经放置了学习 [教程][22]。如果你想认真地学习量子计算,他们推荐你去看一本非常好的书,它是[由 Nielsen 和 Chuang 写的名为 《量子计算和量子信息》][23]。
+
+#### OpenFermion-Cirq
+
+[OpenFermion][24] 是一个开源库,它是为了在量子计算机上模拟获取和操纵代表的费米系统(包含量子化学)。根据 [粒子物理学][26] 理论,按照 [费米—狄拉克统计][27],费米系统与 [费米子][25] 的产生相关。
+
+OpenFermion 被称为从事 [量子化学][29] 的化学家和研究人员的 [一个极好的实践工具][28]。量子化学主要专注于 [量子力学][30] 在物理模型和化学系统实验中的应用。量子化学也被称为 [分子量子力学][31]。
+
+Cirq 的出现使 OpenFermion 通过提供程序和工具去扩展功能成为了可能,通过使用 Cirq 可以去编译和构造仿真量子电路。
+
+#### Google Bristlecone
+
+2018 年 3 月 5 日,在洛杉矶举行的一年一度的 [美国物理学会会议][33] 上,Google 发布了 [Bristlecone][32],这是他们的最新的量子处理器。这个 [基于门的超导系统][34] 为 Google 提供了一个测试平台,用以研究 [量子比特技术][37] 的 [系统错误率][35] 和 [扩展性][36] ,以及在量子 [仿真][38]、[优化][39] 和 [机器学习][40] 方面的应用。
+
+Google 希望在不久的将来,能够制造出它的 [云可访问][41] 的 72 个量子比特的 Bristlecone 量子处理器。Bristlecone 将越来越有能力完成一个经典超级计算机无法在合理时间内完成的任务。
+
+Cirq 将让研究人员直接在云上为 Bristlecone 写程序变得很容易,它提供了一个非常方便的、实时的、量子编程和测试的接口。
+
+Cirq 将允许我们去:
+
+ * 量子电路的微调管理
+ * 使用原生门去指定 [门][42] 行为
+ * 在设备上放置适当的门
+ * 并调度这个门的时刻
+
+### 开放科学关于 Cirq 的观点
+
+我们知道 Cirq 是在 GitHub 上开源的,在开源科学社区之外,特别是那些专注于量子研究的人们,都可以通过高效率地合作,通过开发新方法,去降低现有量子模型中的错误率和提升精确度,以解决目前在量子计算中所面临的挑战。
+
+如果 Cirq 不走开源模型的路线,事情可能变得更具挑战。一个伟大的创举可能就此错过,我们可能在量子计算领域止步不前。
+
+### 总结
+
+最后我们总结一下,我们首先通过与经典计算相比较,介绍了量子计算的概念,然后是一个非常重要的视频来介绍了自去年以来量子计算的最新发展。接着我们简单讨论了嘈杂中型量子,也就是为什么要特意构建 Cirq 的原因所在。
+
+我们看了如何在一个 Ubuntu 系统上安装和测试 Cirq。我们也在一个更好用的 IDE 环境中做了安装测试,并使用一些资源去开始学习有关概念。
+
+最后,我们看了两个示例 OpenFermion 和 Bristlecone,介绍了在量子计算中,Cirq 在开发研究中具有什么样的基本优势。最后我们以 Open Science 社区的视角对 Cirq 进行了一些精彩的思考,结束了我们的话题。
+
+我们希望能以一种易于理解的方式向你介绍量子计算框架 Cirq 的使用。如果你有与此相关的任何反馈,请在下面的评论区告诉我们。感谢阅读,希望我们能在开放科学栏目的下一篇文章中再见。
+
+--------------------------------------------------------------------------------
+
+via: https://itsfoss.com/qunatum-computing-cirq-framework/
+
+作者:[Avimanyu Bandyopadhyay][a]
+选题:[lujun9972](https://github.com/lujun9972)
+译者:[qhwdw](https://github.com/qhwdw)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]: https://itsfoss.com/author/avimanyu/
+[1]:https://en.wikipedia.org/wiki/Subatomic_particle
+[2]:https://en.wikipedia.org/wiki/Quantum
+[3]:https://www.clerro.com/guide/491/quantum-superposition-and-entanglement-explained
+[4]:https://physics.stackexchange.com/questions/148131/can-quantum-entanglement-and-quantum-superposition-be-considered-the-same-phenom
+[5]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/08/bit-vs-qubit.jpg?w=576&ssl=1
+[6]:http://www.rfwireless-world.com/Terminology/Difference-between-Bit-and-Qubit.html
+[7]:https://en.wikipedia.org/wiki/Proof_by_exhaustion
+[8]:https://www.explainthatstuff.com/how-supercomputers-work.html
+[9]:https://arxiv.org/abs/1801.00862
+[10]:https://www.xconomy.com/san-francisco/2018/07/19/google-partners-with-zapata-on-open-source-quantum-computing-effort/
+[11]:https://www.zapatacomputing.com/about/
+[12]:https://github.com/quantumlib/Cirq
+[13]:https://itsfoss.com/python-setup-linux/
+[14]:https://virtualenv.pypa.io
+[15]:https://cirq.readthedocs.io/en/latest/install.html#installing-on-linux
+[16]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/08/cirq-framework-linux.jpeg
+[17]:https://pypi.org/project/pip/
+[18]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/08/cirq-test-output.jpg
+[19]:https://itsfoss.com/install-pycharm-ubuntu/
+[20]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/08/cirq-tested-on-pycharm.jpg
+[21]:https://github.com/quantumlib/Cirq/tree/master/examples
+[22]:https://github.com/quantumlib/Cirq/blob/master/docs/tutorial.md
+[23]:http://mmrc.amss.cas.cn/tlb/201702/W020170224608149940643.pdf
+[24]:http://openfermion.org
+[25]:https://en.wikipedia.org/wiki/Fermion
+[26]:https://en.wikipedia.org/wiki/Particle_physics
+[27]:https://en.wikipedia.org/wiki/Fermi-Dirac_statistics
+[28]:https://phys.org/news/2018-03-openfermion-tool-quantum-coding.html
+[29]:https://en.wikipedia.org/wiki/Quantum_chemistry
+[30]:https://en.wikipedia.org/wiki/Quantum_mechanics
+[31]:https://ocw.mit.edu/courses/chemical-engineering/10-675j-computational-quantum-mechanics-of-molecular-and-extended-systems-fall-2004/lecture-notes/
+[32]:https://techcrunch.com/2018/03/05/googles-new-bristlecone-processor-brings-it-one-step-closer-to-quantum-supremacy/
+[33]:http://meetings.aps.org/Meeting/MAR18/Content/3475
+[34]:https://en.wikipedia.org/wiki/Superconducting_quantum_computing
+[35]:https://en.wikipedia.org/wiki/Quantum_error_correction
+[36]:https://en.wikipedia.org/wiki/Scalability
+[37]:https://research.googleblog.com/2015/03/a-step-closer-to-quantum-computation.html
+[38]:https://research.googleblog.com/2017/10/announcing-openfermion-open-source.html
+[39]:https://research.googleblog.com/2016/06/quantum-annealing-with-digital-twist.html
+[40]:https://arxiv.org/abs/1802.06002
+[41]:https://www.computerworld.com.au/article/644051/google-launches-quantum-framework-cirq-plans-bristlecone-cloud-move/
+[42]:https://en.wikipedia.org/wiki/Logic_gate
diff --git a/published/20180831 Publishing Markdown to HTML with MDwiki.md b/published/201812/20180831 Publishing Markdown to HTML with MDwiki.md
similarity index 100%
rename from published/20180831 Publishing Markdown to HTML with MDwiki.md
rename to published/201812/20180831 Publishing Markdown to HTML with MDwiki.md
diff --git a/published/20180904 Why schools of the future are open.md b/published/201812/20180904 Why schools of the future are open.md
similarity index 100%
rename from published/20180904 Why schools of the future are open.md
rename to published/201812/20180904 Why schools of the future are open.md
diff --git a/published/201812/20180911 Know Your Storage- Block, File - Object.md b/published/201812/20180911 Know Your Storage- Block, File - Object.md
new file mode 100644
index 0000000000..01f4cb4b15
--- /dev/null
+++ b/published/201812/20180911 Know Your Storage- Block, File - Object.md
@@ -0,0 +1,61 @@
+认识存储:块、文件和对象
+======
+> 今天产生的大量数据带来了新的存储挑战。在本文中了解各种存储类型以及它们的使用方式。
+
+
+
+现在,对于那些创建或消费数据的公司来说,处理数量巨大的生成数据是个非常大的挑战。而对于那些解决存储相关问题的科技公司来说,也是一个挑战。
+
+Red Hat 存储首席产品营销经理 Michael St. Jean 说,“数据每年呈几何级增长,而我们发现数据大量增长的主要原因是由于消费增长和为拓展价值而进行的产业转型,毫无疑问,物联网对数据增长的贡献很大,但对软件定义存储来说最重要的挑战是,如何处理用户场景相关的数据增长。“
+
+任何挑战都意味着机遇。Azure 存储、介质和边缘计算总经理 Tad Brockway 说,“今天,新旧数据源产生的海量数据为我们满足客户在规模、性能、灵活性、治理方面急剧增长的需求提供了一个机遇。”
+
+### 现代软件定义存储的三种类型
+
+这里有三个不同类型的存储解决方案 —— 块、文件、和对象 —— 虽然它们每个都可以与其它的共同工作,但它们每个都有不同的用途。
+
+块存储是数据存储的最古老形式,数据都存储在固定长度的块或多个块中。块存储适用于企业存储环境,并且通常使用光纤通道或 iSCSI 接口。根据 SUSE 的软件定义存储高级产品经理 Larry Morris 的说法,“块存储要求一个应用去映射存储设备上存储数据块的位置。”
+
+块存储在存储区域网和软件定义存储系统中是虚拟的,它是处于一个共享的硬件基础设施上的抽象逻辑设备,其创建和存在于服务器、虚拟服务器、或运行在基于像 SCSI、SATA、SAS、FCP、FCoE、或 iSCSI 这样的协议的系统管理程序上。
+
+St. Jean 说“块存储将单个的存储卷(如一个虚拟或云存储节点、或一个老式硬盘)分割成单独的被称为块的实体。”
+
+每个块独立存在,并且能够用它自己的数据传输协议和操作系统格式化 —— 给用户完全的配置自主权。由于块存储系统并不负责像文件存储系统那样的文件查找职责,所以,块存储是一个非常快的存储系统。由于同时具备速度和配置灵活性,使得块存储非常适合原始服务器存储或富媒体数据库。
+
+块存储适合于宿主机操作系统、应用程序、数据库、完整虚拟机和容器。传统上,块存储仅能够被独立的机器访问,或呈现给集群中的机器访问。
+
+### 基于文件的存储
+
+基于文件的存储使用一个文件系统去映射存储设备上数据的存储位置。这种技术在直连或网络附加存储系统应用领域中处于支配地位。它需要做两件事情:组织数据并呈现给用户。St. Jean 说,”使用文件存储时,数据在服务器侧的存储方式与客户端用户所看到的是完全相同的。这就允许用户通过一些唯一标识符(像文件名、位置、或 URL)去请求一个文件,使用特定的数据传输协议与存储系统沟通。
+
+其结果就是一种能够从上到下进行浏览的分层的文件结构。文件存储处于块存储之上,允许用户去查看和访问文件、文件夹这样的数据,但是被限制访问处于这些文件和文件夹之下的数据块。
+
+Brockway 解释说,“文件存储一般用于像 NFS 和 CIFS/SMB 这种很多服务器基于 IP 网络进行访问的共享文件系统上。访问控制通过用户和组的权限实现在文件、目录和导出级别上。基于文件的存储可用于被多个用户和机器、二进制应用程序、数据库、虚拟机所需要的文件的存储上,以及容器上。“
+
+### 对象存储
+
+对象存储是最新的数据存储形式,它为非结构化数据提供一个仓库,它将内容从索引中分离出来,并允许多个文件连接到一个对象上。一个对象就是与任何相关元数据配对的一个数据块,这些元数据提供对象中包含的字节的上下文(比如数据创建时间和数据大小等)。也就是说这两样东西 —— 数据和元数据 —— 构成了一个对象。
+
+对象存储的一个好处是每个数据块都关联了一个唯一标识符。访问数据需要唯一标识符,并且不需要应用程序或用户知道数据的真实存储位置。对象数据是通过 API 来访问的。
+
+St. Jean 说,“对象中存储的数据是没有压缩和加密的,对象本身被组织在对象存储(一个填满其它对象的中心库)中或容器(包含应用程序运行所需要的所有文件的一个包)中。与文件存储系统的层次结构相比,对象、对象存储和容器在本质上是平面的 —— 这使得它们在存储规模巨大时访问速度很快。”
+
+对象存储可以扩展到很多 PB 字节大小,以适应巨大的数据集,因此它是图像、音频、视频、日志、备份、和分析服务所使用的数据存储的最佳选择。
+
+### 结论
+
+现在你已经知道了各种类型的存储以及它们的用处。后面我们将继续研究这个主题的更多内容,敬请关注。
+
+--------------------------------------------------------------------------------
+
+via: https://www.linux.com/blog/2018/9/know-your-storage-block-file-object
+
+作者:[Swapnil Bhartiya][a]
+选题:[lujun9972](https://github.com/lujun9972)
+译者:[qhwdw](https://github.com/qhwdw)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]: https://www.linux.com/users/arnieswap
+[1]: https://events.linuxfoundation.org/events/elc-openiot-europe-2018/
diff --git a/published/201812/20180912 How to turn on an LED with Fedora IoT.md b/published/201812/20180912 How to turn on an LED with Fedora IoT.md
new file mode 100644
index 0000000000..f72d8cb0bc
--- /dev/null
+++ b/published/201812/20180912 How to turn on an LED with Fedora IoT.md
@@ -0,0 +1,186 @@
+如何使用 Fedora IoT 点亮 LED 灯
+======
+
+
+
+如果你喜欢 Fedora、容器,而且有一块树莓派,那么这三者结合操控 LED 会怎么样?本文介绍的是 Fedora IoT,将展示如何在树莓派上安装预览镜像。还将学习如何与 GPIO 交互以点亮 LED。
+
+### 什么是 Fedora IoT?
+
+Fedora IoT 是当前 Fedora 项目的目标之一,计划成为一个完整的 Fedora 版本。Fedora IoT 将是一个在 ARM(目前仅限 aarch64)设备上(例如树莓派),以及 x86_64 架构上运行的系统。
+
+![][1]
+
+Fedora IoT 基于 OSTree 开发,就像 [Fedora Silverblue][2] 和以往的 [Atomic Host][3]。
+
+### 下载和安装 Fedora IoT
+
+官方 Fedora IoT 镜像将和 Fedora 29 一起发布。但是在此期间你可以下载 [基于 Fedora 28 的镜像][4] 来进行这个实验。(LCTT 译注:截止至本译文发布,[Fedora 29 已经发布了][11],但是 IoT 版本并未随同发布,或许会在 Fedora 30 一同发布?)
+
+你有两种方法来安装这个系统:要么使用 `dd` 命令烧录 SD 卡,或者使用 `fedora-arm-installer` 工具。Fedora 的 Wiki 里面提供了为 IoT [设置物理设备][5] 的更多信息。另外,你可能需要调整第三个分区的大小。
+
+把 SD 卡插入到设备后,你需要创建一个用户来完成安装。这个步骤需要串行连接或一个 HDMI 显示器和键盘来与设备进行交互。
+
+当系统安装完成后,下一步就是要设置网络连接。使用你刚才创建的用户登录系统,可以使用下列方式之一完成网络连接设置:
+
+* 如果你需要手动配置你的网络,可能需要执行类似如下命令,需要保证设置正确的网络地址:
+
+ ```
+ $ nmcli connection add con-name cable ipv4.addresses \
+ 192.168.0.10/24 ipv4.gateway 192.168.0.1 \
+ connection.autoconnect true ipv4.dns "8.8.8.8,1.1.1.1" \
+ type ethernet ifname eth0 ipv4.method manual
+```
+
+* 如果你网络上运行着 DHCP 服务,可能需要类似如下命令:
+
+ ```
+ $ nmcli con add type ethernet con-name cable ifname eth0
+```
+
+### Fedora 中的 GPIO 接口
+
+许多关于 Linux 上 GPIO 的教程都关注传统的 GPIO sysfis 接口。这个接口已经不推荐使用了,并且上游 Linux 内核社区由于安全和其他问题的缘故打算完全删除它。
+
+Fedora 已经不将这个传统的接口编译到内核了,因此在系统上没有 `/sys/class/gpio` 这个文件。此教程使用一个上游内核提供的一个新的字符设备 `/dev/gpiochipN` 。这是目前和 GPIO 交互的方式。
+
+为了和这个新设备进行交互,你需要使用一个库和一系列命令行界面的工具。常用的命令行工具比如说 `echo` 和 `cat` 在此设备上无法正常工作。
+
+你可以通过安装 libgpiod-utils 包来安装命令行界面工具。python3-libgpiod 包提供了相应的 Python 库。
+
+### 使用 Podman 来创建一个容器
+
+[Podman][6] 是一个容器运行环境,其命令行界面类似于 Docker。Podman 的一大优势是它不会在后台运行任何守护进程。这对于资源有限的设备尤其有用。Podman 还允许您使用 systemd 单元文件启动容器化服务。此外,它还有许多其他功能。
+
+我们使用如下两步来创建一个容器:
+
+1. 创建包含所需包的分层镜像。
+2. 使用分层镜像创建一个新容器。
+
+首先创建一个 Dockerfile 文件,内容如下。这些内容告诉 Podman 基于可使用的最新 Fedora 镜像来构建我们的分层镜像。然后就是更新系统和安装一些软件包:
+
+```
+FROM fedora:latest
+RUN dnf -y update
+RUN dnf -y install libgpiod-utils python3-libgpiod
+```
+
+这样你就完成了镜像的生成前的配置工作,这个镜像基于最新的 Fedora,而且包含了和 GPIO 交互的软件包。
+
+现在你就可以运行如下命令来构建你的基本镜像了:
+
+```
+$ sudo podman build --tag fedora:gpiobase -f ./Dockerfile
+```
+
+你已经成功创建了你的自定义镜像。这样以后你就可以不用每次都重新搭建环境了,而是基于你创建的镜像来完成工作。
+
+### 使用 Podman 完成工作
+
+为了确认当前的镜像是否就绪,可以运行如下命令:
+
+```
+$ sudo podman images
+REPOSITORY TAG IMAGE ID CREATED SIZE
+localhost/fedora gpiobase 67a2b2b93b4b 10 minutes ago 488MB
+docker.io/library/fedora latest c18042d7fac6 2 days ago 300MB
+```
+
+现在,启动容器并进行一些实际的实验。容器通常是隔离的,无法访问主机系统,包括 GPIO 接口。因此需要在启动容器时将其挂载在容器内。可以使用以下命令中的 `-device` 选项来解决:
+
+```
+$ sudo podman run -it --name gpioexperiment --device=/dev/gpiochip0 localhost/fedora:gpiobase /bin/bash
+```
+
+运行之后就进入了正在运行的容器中。在继续之前,这里有一些容器命令。输入 `exit` 或者按下 `Ctrl+D` 来退出容器。
+
+显示所有存在的容器可以运行如下命令,这包括当前没有运行的,比如你刚刚创建的那个:
+
+```
+$ sudo podman container ls -a
+CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
+64e661d5d4e8 localhost/fedora:gpiobase /bin/bash 37 seconds ago Exited (0) Less than a second ago gpioexperiment
+```
+
+使用如下命令创建一个新的容器:
+
+```
+$ sudo podman run -it --name newexperiment --device=/dev/gpiochip0 localhost/fedora:gpiobase /bin/bash
+
+```
+
+如果想删除容器可以使用如下命令:
+
+```
+$ sudo podman rm newexperiment
+
+```
+
+### 点亮 LED 灯
+
+现在可以使用已创建的容器。如果已经从容器退出,请使用以下命令再次启动它:
+
+```
+$ sudo podman start -ia gpioexperiment
+```
+
+如前所述,可以使用 Fedora 中 libgpiod-utils 包提供的命令行工具。要列出可用的 GPIO 芯片可以使用如下命令:
+
+```
+$ gpiodetect
+gpiochip0 [pinctrl-bcm2835] (54 lines)
+```
+
+要获取特定芯片的连线列表,请运行:
+
+```
+$ gpioinfo gpiochip0
+```
+
+请注意,物理引脚数与前一个命令所打印的连线数之间没有相关性。重要的是 BCM 编号,如 [pinout.xyz][7] 所示。建议不要使用没有相应 BCM 编号的连线。
+
+现在,将 LED 连接到物理引脚 40,也就是 BCM 21。请记住:LED 的短腿(负极,称为阴极)必须连接到带有 330 欧姆电阻的树莓派的 GND 引脚, 并且长腿(阳极)到物理引脚 40。
+
+运行以下命令点亮 LED,按下 `Ctrl + C` 关闭:
+
+```
+$ gpioset --mode=wait gpiochip0 21=1
+```
+
+要点亮一段时间,请添加 `-b`(在后台运行)和 `-s NUM`(多少秒)参数,如下所示。 例如,要点亮 LED 5 秒钟,运行如下命令:
+
+```
+$ gpioset -b -s 5 --mode=time gpiochip0 21=1
+```
+
+另一个有用的命令是 `gpioget`。 它可以获得引脚的状态(高或低),可用于检测按钮和开关。
+
+![Closeup of LED connection with GPIO][8]
+
+### 总结
+
+你也可以使用 Python 操控 LED —— [这里有一些例子][9]。 也可以在容器内使用 i2c 设备。 此外,Podman 与此 Fedora 版本并不严格相关。你可以在任何现有的 Fedora 版本上安装它,或者在 Fedora 中使用两个基于 OSTree 的新系统进行尝试:[Fedora Silverblue][2] 和 [Fedora CoreOS][10]。
+
+------
+
+via: https://fedoramagazine.org/turnon-led-fedora-iot/
+
+作者:[Alessio Ciregia][a]
+选题:[lujun9972](https://github.com/lujun9972)
+译者:[ScarboroughCoral](https://github.com/ScarboroughCoral)
+校对:[wxy](https://github.com/wxy)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]: http://alciregi.id.fedoraproject.org/
+[1]: https://fedoramagazine.org/wp-content/uploads/2018/08/oled-1024x768.png
+[2]: https://teamsilverblue.org/
+[3]: https://www.projectatomic.io/
+[4]: https://kojipkgs.fedoraproject.org/compose/iot/latest-Fedora-IoT-28/compose/IoT/
+[5]: https://fedoraproject.org/wiki/InternetOfThings/GettingStarted#Setting_up_a_Physical_Device
+[6]: https://github.com/containers/libpod
+[7]: https://pinout.xyz/
+[8]: https://fedoramagazine.org/wp-content/uploads/2018/08/breadboard-1024x768.png
+[9]: https://github.com/brgl/libgpiod/tree/master/bindings/python/examples
+[10]: https://coreos.fedoraproject.org/
+[11]: https://fedoramagazine.org/announcing-fedora-29/
diff --git a/published/20181004 Archiving web sites.md b/published/201812/20181004 Archiving web sites.md
similarity index 100%
rename from published/20181004 Archiving web sites.md
rename to published/201812/20181004 Archiving web sites.md
diff --git a/published/20181004 Lab 3- User Environments.md b/published/201812/20181004 Lab 3- User Environments.md
similarity index 100%
rename from published/20181004 Lab 3- User Environments.md
rename to published/201812/20181004 Lab 3- User Environments.md
diff --git a/translated/tech/20181016 Lab 4- Preemptive Multitasking.md b/published/201812/20181016 Lab 4- Preemptive Multitasking.md
similarity index 55%
rename from translated/tech/20181016 Lab 4- Preemptive Multitasking.md
rename to published/201812/20181016 Lab 4- Preemptive Multitasking.md
index 9302b7288a..4023b0b2e9 100644
--- a/translated/tech/20181016 Lab 4- Preemptive Multitasking.md
+++ b/published/201812/20181016 Lab 4- Preemptive Multitasking.md
@@ -1,10 +1,9 @@
-实验 4:抢占式多任务处理
+Caffeinated 6.828:实验 4:抢占式多任务处理
======
-### 实验 4:抢占式多任务处理
-#### 简介
+### 简介
-在本实验中,你将在多个同时活动的用户模式中的环境之间实现抢占式多任务处理。
+在本实验中,你将在多个同时活动的用户模式环境之间实现抢占式多任务处理。
在 Part A 中,你将在 JOS 中添加对多处理器的支持,以实现循环调度。并且添加基本的环境管理方面的系统调用(创建和销毁环境的系统调用、以及分配/映射内存)。
@@ -12,7 +11,7 @@
最后,在 Part C 中,你将在 JOS 中添加对进程间通讯(IPC)的支持,以允许不同用户模式环境之间进行显式通讯和同步。你也将要去添加对硬件时钟中断和优先权的支持。
-##### 预备知识
+#### 预备知识
使用 git 去提交你的实验 3 的源代码,并获取课程仓库的最新版本,然后创建一个名为 `lab4` 的本地分支,它跟踪我们的名为 `origin/lab4` 的远程 `lab4` 分支:
@@ -31,6 +30,7 @@
```
实验 4 包含了一些新的源文件,在开始之前你应该去浏览一遍:
+
```markdown
kern/cpu.h Kernel-private definitions for multiprocessor support
kern/mpconfig.c Code to read the multiprocessor configuration
@@ -41,19 +41,19 @@ kern/spinlock.c Kernel code implementing spin locks
kern/sched.c Code skeleton of the scheduler that you are about to implement
```
-##### 实验要求
+#### 实验要求
-本实验分为三部分:Part A、Part B、和 Part C。我们计划为每个部分分配一周的时间。
+本实验分为三部分:Part A、Part B 和 Part C。我们计划为每个部分分配一周的时间。
和以前一样,你需要完成实验中出现的、所有常规练习和至少一个挑战问题。(不是每个部分做一个挑战问题,是整个实验做一个挑战问题即可。)另外,你还要写出你实现的挑战问题的详细描述。如果你实现了多个挑战问题,你只需写出其中一个即可,虽然我们的课程欢迎你完成越多的挑战越好。在动手实验之前,请将你的挑战问题的答案写在一个名为 `answers-lab4.txt` 的文件中,并把它放在你的 `lab` 目录的根下。
-#### Part A:多处理器支持和协调多任务处理
+### Part A:多处理器支持和协调多任务处理
在本实验的第一部分,将去扩展你的 JOS 内核,以便于它能够在一个多处理器的系统上运行,并且要在 JOS 内核中实现一些新的系统调用,以便于它允许用户级环境创建附加的新环境。你也要去实现协调的循环调度,在当前的环境自愿放弃 CPU(或退出)时,允许内核将一个环境切换到另一个环境。稍后在 Part C 中,你将要实现抢占调度,它允许内核在环境占有 CPU 一段时间后,从这个环境上重新取回对 CPU 的控制,那怕是在那个环境不配合的情况下。
-##### 多处理器支持
+#### 多处理器支持
-我们继续去让 JOS 支持 “对称多处理器”(SMP),在一个多处理器的模型中,所有 CPU 们都有平等访问系统资源(如内存和 I/O 总线)的权利。虽然在 SMP 中所有 CPU 们都有相同的功能,但是在引导进程的过程中,它们被分成两种类型:引导程序处理器(BSP)负责初始化系统和引导操作系统;而在操作系统启动并正常运行后,应用程序处理器(AP)将被 BSP 激活。哪个处理器做 BSP 是由硬件和 BIOS 来决定的。到目前为止,你所有的已存在的 JOS 代码都是运行在 BSP 上的。
+我们继续去让 JOS 支持 “对称多处理器”(SMP),在一个多处理器的模型中,所有 CPU 们都有平等访问系统资源(如内存和 I/O 总线)的权力。虽然在 SMP 中所有 CPU 们都有相同的功能,但是在引导进程的过程中,它们被分成两种类型:引导程序处理器(BSP)负责初始化系统和引导操作系统;而在操作系统启动并正常运行后,应用程序处理器(AP)将被 BSP 激活。哪个处理器做 BSP 是由硬件和 BIOS 来决定的。到目前为止,你所有的已存在的 JOS 代码都是运行在 BSP 上的。
在一个 SMP 系统上,每个 CPU 都伴有一个本地 APIC(LAPIC)单元。这个 LAPIC 单元负责传递系统中的中断。LAPIC 还为它所连接的 CPU 提供一个唯一的标识符。在本实验中,我们将使用 LAPIC 单元(它在 `kern/lapic.c` 中)中的下列基本功能:
@@ -61,15 +61,11 @@ kern/sched.c Code skeleton of the scheduler that you are about to implement
* 从 BSP 到 AP 之间发送处理器间中断(IPI) `STARTUP`,以启动其它 CPU(查看 `lapic_startap()`)。
* 在 Part C 中,我们设置 LAPIC 的内置定时器去触发时钟中断,以便于支持抢占式多任务处理(查看 `apic_init()`)。
+一个处理器使用内存映射的 I/O(MMIO)来访问它的 LAPIC。在 MMIO 中,一部分物理内存是硬编码到一些 I/O 设备的寄存器中,因此,访问内存时一般可以使用相同的 `load/store` 指令去访问设备的寄存器。正如你所看到的,在物理地址 `0xA0000` 处就是一个 IO 入口(就是我们写入 VGA 缓冲区的入口)。LAPIC 就在那里,它从物理地址 `0xFE000000` 处(4GB 减去 32MB 处)开始,这个地址对于我们在 KERNBASE 处使用直接映射访问来说太高了。JOS 虚拟内存映射在 `MMIOBASE` 处,留下一个 4MB 的空隙,以便于我们有一个地方,能像这样去映射设备。由于在后面的实验中,我们将介绍更多的 MMIO 区域,你将要写一个简单的函数,从这个区域中去分配空间,并将设备的内存映射到那里。
+> **练习 1**、实现 `kern/pmap.c` 中的 `mmio_map_region`。去看一下它是如何使用的,从 `kern/lapic.c` 中的 `lapic_init` 开始看起。在 `mmio_map_region` 的测试运行之前,你还要做下一个练习。
-一个处理器使用内存映射的 I/O(MMIO)来访问它的 LAPIC。在 MMIO 中,一部分物理内存是硬编码到一些 I/O 设备的寄存器中,因此,访问内存时一般可以使用相同的 `load/store` 指令去访问设备的寄存器。正如你所看到的,在物理地址 `0xA0000` 处就是一个 IO 入口(就是我们写入 VGA 缓冲区的入口)。LAPIC 就在那里,它从物理地址 `0xFE000000` 处(4GB 减去 32MB 处)开始,这个地址对于我们在 KERNBASE 处使用直接映射访问来说太高了。JOS 虚拟内存映射在 `MMIOBASE` 处,留下一个 4MB 的空隙,以便于我们有一个地方,能像这样去映射设备。由于在后面的实验中,我们将介绍更多的 MMIO 区域,你将要写一个简单的函数,从这个区域中去分配空间,并将设备的内存映射到那里。
-
-```markdown
-练习 1、实现 `kern/pmap.c` 中的 `mmio_map_region`。去看一下它是如何使用的,从 `kern/lapic.c` 中的 `lapic_init` 开始看起。在 `mmio_map_region` 的测试运行之前,你还要做下一个练习。
-```
-
-###### 引导应用程序处理器
+##### 引导应用程序处理器
在引导应用程序处理器之前,引导程序处理器应该会首先去收集关于多处理器系统的信息,比如总的 CPU 数、它们的 APIC ID 以及 LAPIC 单元的 MMIO 地址。在 `kern/mpconfig.c` 中的 `mp_init()` 函数,通过读取内存中位于 BIOS 区域里的 MP 配置表来获得这些信息。
@@ -77,46 +73,42 @@ kern/sched.c Code skeleton of the scheduler that you are about to implement
在那之后,通过发送 IPI `STARTUP` 到相关 AP 的 LAPIC 单元,以及一个初始的 `CS:IP` 地址(AP 将从那儿开始运行它的入口代码,在我们的案例中是 `MPENTRY_PADDR` ),`boot_aps()` 将一个接一个地激活 AP。在 `kern/mpentry.S` 中的入口代码非常类似于 `boot/boot.S`。在一些简短的设置之后,它启用分页,使 AP 进入保护模式,然后调用 C 设置程序 `mp_main()`(它也在 `kern/init.c` 中)。在继续唤醒下一个 AP 之前, `boot_aps()` 将等待这个 AP 去传递一个 `CPU_STARTED` 标志到它的 `struct CpuInfo` 中的 `cpu_status` 字段中。
-```markdown
-练习 2、阅读 `kern/init.c` 中的 `boot_aps()` 和 `mp_main()`,以及在 `kern/mpentry.S` 中的汇编代码。确保你理解了在 AP 引导过程中的控制流转移。然后修改在 `kern/pmap.c` 中的、你自己的 `page_init()`,实现避免在 `MPENTRY_PADDR` 处添加页到空闲列表上,以便于我们能够在物理地址上安全地复制和运行 AP 引导程序代码。你的代码应该会通过更新后的 `check_page_free_list()` 的测试(但可能会在更新后的 `check_kern_pgdir()` 上测试失败,我们在后面会修复它)。
-```
+> **练习 2**、阅读 `kern/init.c` 中的 `boot_aps()` 和 `mp_main()`,以及在 `kern/mpentry.S` 中的汇编代码。确保你理解了在 AP 引导过程中的控制流转移。然后修改在 `kern/pmap.c` 中的、你自己的 `page_init()`,实现避免在 `MPENTRY_PADDR` 处添加页到空闲列表上,以便于我们能够在物理地址上安全地复制和运行 AP 引导程序代码。你的代码应该会通过更新后的 `check_page_free_list()` 的测试(但可能会在更新后的 `check_kern_pgdir()` 上测试失败,我们在后面会修复它)。
-```markdown
-问题
- 1、比较 `kern/mpentry.S` 和 `boot/boot.S`。记住,那个 `kern/mpentry.S` 是编译和链接后的,运行在 `KERNBASE` 上面的,就像内核中的其它程序一样,宏 `MPBOOTPHYS` 的作用是什么?为什么它需要在 `kern/mpentry.S` 中,而不是在 `boot/boot.S` 中?换句话说,如果在 `kern/mpentry.S` 中删掉它,会发生什么错误?
+.
+
+> **问题 1**、比较 `kern/mpentry.S` 和 `boot/boot.S`。记住,那个 `kern/mpentry.S` 是编译和链接后的,运行在 `KERNBASE` 上面的,就像内核中的其它程序一样,宏 `MPBOOTPHYS` 的作用是什么?为什么它需要在 `kern/mpentry.S` 中,而不是在 `boot/boot.S` 中?换句话说,如果在 `kern/mpentry.S` 中删掉它,会发生什么错误?
提示:回顾链接地址和加载地址的区别,我们在实验 1 中讨论过它们。
-```
-
-###### 每个 CPU 的状态和初始化
+##### 每个 CPU 的状态和初始化
当写一个多处理器操作系统时,区分每个 CPU 的状态是非常重要的,而每个 CPU 的状态对其它处理器是不公开的,而全局状态是整个系统共享的。`kern/cpu.h` 定义了大部分每个 CPU 的状态,包括 `struct CpuInfo`,它保存了每个 CPU 的变量。`cpunum()` 总是返回调用它的那个 CPU 的 ID,它可以被用作是数组的索引,比如 `cpus`。或者,宏 `thiscpu` 是当前 CPU 的 `struct CpuInfo` 缩略表示。
下面是你应该知道的每个 CPU 的状态:
- * **每个 CPU 的内核栈**
-因为内核能够同时捕获多个 CPU,因此,我们需要为每个 CPU 准备一个单独的内核栈,以防止它们运行的程序之间产生相互干扰。数组 `percpu_kstacks[NCPU][KSTKSIZE]` 为 NCPU 的内核栈资产保留了空间。
+* **每个 CPU 的内核栈**
-在实验 2 中,你映射的 `bootstack` 所引用的物理内存,就作为 `KSTACKTOP` 以下的 BSP 的内核栈。同样,在本实验中,你将每个 CPU 的内核栈映射到这个区域,而使用保护页做为它们之间的缓冲区。CPU 0 的栈将从 `KSTACKTOP` 处向下增长;CPU 1 的栈将从 CPU 0 的栈底部的 `KSTKGAP` 字节处开始,依次类推。在 `inc/memlayout.h` 中展示了这个映射布局。
+ 因为内核能够同时捕获多个 CPU,因此,我们需要为每个 CPU 准备一个单独的内核栈,以防止它们运行的程序之间产生相互干扰。数组 `percpu_kstacks[NCPU][KSTKSIZE]` 为 NCPU 的内核栈资产保留了空间。
- * **每个 CPU 的 TSS 和 TSS 描述符**
-为了指定每个 CPU 的内核栈在哪里,也需要有一个每个 CPU 的任务状态描述符(TSS)。CPU _i_ 的任务状态描述符是保存在 `cpus[i].cpu_ts` 中,而对应的 TSS 描述符是定义在 GDT 条目 `gdt[(GD_TSS0 >> 3) + i]` 中。在 `kern/trap.c` 中定义的全局变量 `ts` 将不再被使用。
+ 在实验 2 中,你映射的 `bootstack` 所引用的物理内存,就作为 `KSTACKTOP` 以下的 BSP 的内核栈。同样,在本实验中,你将每个 CPU 的内核栈映射到这个区域,而使用保护页做为它们之间的缓冲区。CPU 0 的栈将从 `KSTACKTOP` 处向下增长;CPU 1 的栈将从 CPU 0 的栈底部的 `KSTKGAP` 字节处开始,依次类推。在 `inc/memlayout.h` 中展示了这个映射布局。
- * **每个 CPU 当前的环境指针**
-由于每个 CPU 都能同时运行不同的用户进程,所以我们重新定义了符号 `curenv`,让它指向到 `cpus[cpunum()].cpu_env`(或 `thiscpu->cpu_env`),它指向到当前 CPU(代码正在运行的那个 CPU)上当前正在运行的环境上。
+* **每个 CPU 的 TSS 和 TSS 描述符**
- * **每个 CPU 的系统寄存器**
-所有的寄存器,包括系统寄存器,都是一个 CPU 私有的。所以,初始化这些寄存器的指令,比如 `lcr3()`、`ltr()`、`lgdt()`、`lidt()`、等待,必须在每个 CPU 上运行一次。函数 `env_init_percpu()` 和 `trap_init_percpu()` 就是为此目的而定义的。
+ 为了指定每个 CPU 的内核栈在哪里,也需要有一个每个 CPU 的任务状态描述符(TSS)。CPU _i_ 的任务状态描述符是保存在 `cpus[i].cpu_ts` 中,而对应的 TSS 描述符是定义在 GDT 条目 `gdt[(GD_TSS0 >> 3) + i]` 中。在 `kern/trap.c` 中定义的全局变量 `ts` 将不再被使用。
+* **每个 CPU 当前的环境指针**
+ 由于每个 CPU 都能同时运行不同的用户进程,所以我们重新定义了符号 `curenv`,让它指向到 `cpus[cpunum()].cpu_env`(或 `thiscpu->cpu_env`),它指向到当前 CPU(代码正在运行的那个 CPU)上当前正在运行的环境上。
-```markdown
-练习 3、修改 `mem_init_mp()`(在 `kern/pmap.c` 中)去映射每个 CPU 的栈从 `KSTACKTOP` 处开始,就像在 `inc/memlayout.h` 中展示的那样。每个栈的大小是 `KSTKSIZE` 字节加上未映射的保护页 `KSTKGAP` 的字节。你的代码应该会通过在 `check_kern_pgdir()` 中的新的检查。
-```
+* **每个 CPU 的系统寄存器**
-```markdown
-练习 4、在 `trap_init_percpu()`(在 `kern/trap.c` 文件中)的代码为 BSP 初始化 TSS 和 TSS 描述符。在实验 3 中它就运行过,但是当它运行在其它的 CPU 上就会出错。修改这些代码以便它能在所有 CPU 上都正常运行。(注意:你的新代码应该还不能使用全局变量 `ts`)
-```
+ 所有的寄存器,包括系统寄存器,都是一个 CPU 私有的。所以,初始化这些寄存器的指令,比如 `lcr3()`、`ltr()`、`lgdt()`、`lidt()`、等待,必须在每个 CPU 上运行一次。函数 `env_init_percpu()` 和 `trap_init_percpu()` 就是为此目的而定义的。
+
+> **练习 3**、修改 `mem_init_mp()`(在 `kern/pmap.c` 中)去映射每个 CPU 的栈从 `KSTACKTOP` 处开始,就像在 `inc/memlayout.h` 中展示的那样。每个栈的大小是 `KSTKSIZE` 字节加上未映射的保护页 `KSTKGAP` 的字节。你的代码应该会通过在 `check_kern_pgdir()` 中的新的检查。
+
+.
+
+> **练习 4**、在 `trap_init_percpu()`(在 `kern/trap.c` 文件中)的代码为 BSP 初始化 TSS 和 TSS 描述符。在实验 3 中它就运行过,但是当它运行在其它的 CPU 上就会出错。修改这些代码以便它能在所有 CPU 上都正常运行。(注意:你的新代码应该还不能使用全局变量 `ts`)
在你完成上述练习后,在 QEMU 中使用 4 个 CPU(使用 `make qemu CPUS=4` 或 `make qemu-nox CPUS=4`)来运行 JOS,你应该看到类似下面的输出:
@@ -134,94 +126,87 @@ kern/sched.c Code skeleton of the scheduler that you are about to implement
SMP: CPU 3 starting
```
-###### 锁定
+##### 锁定
在 `mp_main()` 中初始化 AP 后我们的代码快速运行起来。在你更进一步增强 AP 之前,我们需要首先去处理多个 CPU 同时运行内核代码的争用状况。达到这一目标的最简单的方法是使用大内核锁。大内核锁是一个单个的全局锁,当一个环境进入内核模式时,它将被加锁,而这个环境返回到用户模式时它将释放锁。在这种模型中,在用户模式中运行的环境可以同时运行在任何可用的 CPU 上,但是只有一个环境能够运行在内核模式中;而任何尝试进入内核模式的其它环境都被强制等待。
`kern/spinlock.h` 中声明大内核锁,即 `kernel_lock`。它也提供 `lock_kernel()` 和 `unlock_kernel()`,快捷地去获取/释放锁。你应该在以下的四个位置应用大内核锁:
- * 在 `i386_init()` 时,在 BSP 唤醒其它 CPU 之前获取锁。
- * 在 `mp_main()` 时,在初始化 AP 之后获取锁,然后调用 `sched_yield()` 在这个 AP 上开始运行环境。
- * 在 `trap()` 时,当从用户模式中捕获一个陷阱时获取锁。在检查 `tf_cs` 的低位比特,以确定一个陷阱是发生在用户模式还是内核模式时。
- * 在 `env_run()` 中,在切换到用户模式之前释放锁。不能太早也不能太晚,否则你将可能会产生争用或死锁。
+* 在 `i386_init()` 时,在 BSP 唤醒其它 CPU 之前获取锁。
+* 在 `mp_main()` 时,在初始化 AP 之后获取锁,然后调用 `sched_yield()` 在这个 AP 上开始运行环境。
+* 在 `trap()` 时,当从用户模式中捕获一个陷阱时获取锁。在检查 `tf_cs` 的低位比特,以确定一个陷阱是发生在用户模式还是内核模式时。
+* 在 `env_run()` 中,在切换到用户模式之前释放锁。不能太早也不能太晚,否则你将可能会产生争用或死锁。
+> **练习 5**、在上面所描述的情况中,通过在合适的位置调用 `lock_kernel()` 和 `unlock_kernel()` 应用大内核锁。
-```markdown
-练习 5、在上面所描述的情况中,通过在合适的位置调用 `lock_kernel()` 和 `unlock_kernel()` 应用大内核锁。
-```
+> 如果你的锁定是正确的,如何去测试它?实际上,到目前为止,还无法测试!但是在下一个练习中,你实现了调度之后,就可以测试了。
-如果你的锁定是正确的,如何去测试它?实际上,到目前为止,还无法测试!但是在下一个练习中,你实现了调度之后,就可以测试了。
+.
-```
-问题
- 2、看上去使用一个大内核锁,可以保证在一个时间中只有一个 CPU 能够运行内核代码。为什么每个 CPU 仍然需要单独的内核栈?描述一下使用一个共享内核栈出现错误的场景,即便是在它使用了大内核锁保护的情况下。
-```
+> **问题 2**、看上去使用一个大内核锁,可以保证在一个时间中只有一个 CPU 能够运行内核代码。为什么每个 CPU 仍然需要单独的内核栈?描述一下使用一个共享内核栈出现错误的场景,即便是在它使用了大内核锁保护的情况下。
-```
-小挑战!大内核锁很简单,也易于使用。尽管如此,它消除了内核模式的所有并发。大多数现代操作系统使用不同的锁,一种称之为细粒度锁定的方法,去保护它们的共享的栈的不同部分。细粒度锁能够大幅提升性能,但是实现起来更困难并且易出错。如果你有足够的勇气,在 JOS 中删除大内核锁,去拥抱并发吧!
+> **小挑战!**大内核锁很简单,也易于使用。尽管如此,它消除了内核模式的所有并发。大多数现代操作系统使用不同的锁,一种称之为细粒度锁定的方法,去保护它们的共享的栈的不同部分。细粒度锁能够大幅提升性能,但是实现起来更困难并且易出错。如果你有足够的勇气,在 JOS 中删除大内核锁,去拥抱并发吧!
-由你来决定锁的粒度(一个锁保护的数据量)。给你一个提示,你可以考虑在 JOS 内核中使用一个自旋锁去确保你独占访问这些共享的组件:
+> 由你来决定锁的粒度(一个锁保护的数据量)。给你一个提示,你可以考虑在 JOS 内核中使用一个自旋锁去确保你独占访问这些共享的组件:
- * 页分配器
- * 控制台驱动
- * 调度器
- * 你将在 Part C 中实现的进程间通讯(IPC)的状态
-```
+> * 页分配器
+* 控制台驱动
+* 调度器
+* 你将在 Part C 中实现的进程间通讯(IPC)的状态
-
-##### 循环调度
+#### 循环调度
本实验中,你的下一个任务是去修改 JOS 内核,以使它能够在多个环境之间以“循环”的方式去交替。JOS 中的循环调度工作方式如下:
- * 在新的 `kern/sched.c` 中的 `sched_yield()` 函数负责去选择一个新环境来运行。它按顺序以循环的方式在数组 `envs[]` 中进行搜索,在前一个运行的环境之后开始(或如果之前没有运行的环境,就从数组起点开始),选择状态为 `ENV_RUNNABLE` 的第一个环境(查看 `inc/env.h`),并调用 `env_run()` 去跳转到那个环境。
- * `sched_yield()` 必须做到,同一个时间在两个 CPU 上绝对不能运行相同的环境。它可以判断出一个环境正运行在一些 CPU(可能是当前 CPU)上,因为,那个正在运行的环境的状态将是 `ENV_RUNNING`。
- * 我们已经为你实现了一个新的系统调用 `sys_yield()`,用户环境调用它去调用内核的 `sched_yield()` 函数,并因此将自愿把对 CPU 的控制禅让给另外的一个环境。
+* 在新的 `kern/sched.c` 中的 `sched_yield()` 函数负责去选择一个新环境来运行。它按顺序以循环的方式在数组 `envs[]` 中进行搜索,在前一个运行的环境之后开始(或如果之前没有运行的环境,就从数组起点开始),选择状态为 `ENV_RUNNABLE` 的第一个环境(查看 `inc/env.h`),并调用 `env_run()` 去跳转到那个环境。
+* `sched_yield()` 必须做到,同一个时间在两个 CPU 上绝对不能运行相同的环境。它可以判断出一个环境正运行在一些 CPU(可能是当前 CPU)上,因为,那个正在运行的环境的状态将是 `ENV_RUNNING`。
+* 我们已经为你实现了一个新的系统调用 `sys_yield()`,用户环境调用它去调用内核的 `sched_yield()` 函数,并因此将自愿把对 CPU 的控制禅让给另外的一个环境。
+> **练习 6**、像上面描述的那样,在 `sched_yield()` 中实现循环调度。不要忘了去修改 `syscall()` 以派发 `sys_yield()`。
-```c
-练习 6、像上面描述的那样,在 `sched_yield()` 中实现循环调度。不要忘了去修改 `syscall()` 以派发 `sys_yield()`。
+> 确保在 `mp_main` 中调用了 `sched_yield()`。
-确保在 `mp_main` 中调用了 `sched_yield()`。
+> 修改 `kern/init.c` 去创建三个(或更多个!)运行程序 `user/yield.c`的环境。
-修改 `kern/init.c` 去创建三个(或更多个!)运行程序 `user/yield.c`的环境。
+> 运行 `make qemu`。在它终止之前,你应该会看到像下面这样,在环境之间来回切换了五次。
-运行 `make qemu`。在它终止之前,你应该会看到像下面这样,在环境之间来回切换了五次。
+> 也可以使用几个 CPU 来测试:`make qemu CPUS=2`。
-也可以使用几个 CPU 来测试:make qemu CPUS=2。
-
- ...
- Hello, I am environment 00001000.
- Hello, I am environment 00001001.
- Hello, I am environment 00001002.
- Back in environment 00001000, iteration 0.
- Back in environment 00001001, iteration 0.
- Back in environment 00001002, iteration 0.
- Back in environment 00001000, iteration 1.
- Back in environment 00001001, iteration 1.
- Back in environment 00001002, iteration 1.
- ...
-
-在程序 `yield` 退出之后,系统中将没有可运行的环境,调度器应该会调用 JOS 内核监视器。如果它什么也没有发生,那么你应该在继续之前修复你的代码。
+>```
+...
+Hello, I am environment 00001000.
+Hello, I am environment 00001001.
+Hello, I am environment 00001002.
+Back in environment 00001000, iteration 0.
+Back in environment 00001001, iteration 0.
+Back in environment 00001002, iteration 0.
+Back in environment 00001000, iteration 1.
+Back in environment 00001001, iteration 1.
+Back in environment 00001002, iteration 1.
+...
```
-```c
-问题
- 3、在你实现的 `env_run()` 中,你应该会调用 `lcr3()`。在调用 `lcr3()` 的之前和之后,你的代码引用(至少它应该会)变量 `e`,它是 `env_run` 的参数。在加载 `%cr3` 寄存器时,MMU 使用的地址上下文将马上被改变。但一个虚拟地址(即 `e`)相对一个给定的地址上下文是有意义的 —— 地址上下文指定了物理地址到那个虚拟地址的映射。为什么指针 `e` 在地址切换之前和之后被解除引用?
- 4、无论何时,内核从一个环境切换到另一个环境,它必须要确保旧环境的寄存器内容已经被保存,以便于它们稍后能够正确地还原。为什么?这种事件发生在什么地方?
-```
+> 在程序 `yield` 退出之后,系统中将没有可运行的环境,调度器应该会调用 JOS 内核监视器。如果它什么也没有发生,那么你应该在继续之前修复你的代码。
-```c
-小挑战!给内核添加一个小小的调度策略,比如一个固定优先级的调度器,它将会给每个环境分配一个优先级,并且在执行中,较高优先级的环境总是比低优先级的环境优先被选定。如果你想去冒险一下,尝试实现一个类 Unix 的、优先级可调整的调度器,或者甚至是一个彩票调度器或跨步调度器。(可以在 Google 中查找“彩票调度”和“跨步调度”的相关资料)
-写一个或两个测试程序,去测试你的调度算法是否工作正常(即,正确的算法能够按正确的次序运行)。如果你实现了本实验的 Part B 和 Part C 部分的 `fork()` 和 IPC,写这些测试程序可能会更容易。
-```
+> **问题 3**、在你实现的 `env_run()` 中,你应该会调用 `lcr3()`。在调用 `lcr3()` 的之前和之后,你的代码引用(至少它应该会)变量 `e`,它是 `env_run` 的参数。在加载 `%cr3` 寄存器时,MMU 使用的地址上下文将马上被改变。但一个虚拟地址(即 `e`)相对一个给定的地址上下文是有意义的 —— 地址上下文指定了物理地址到那个虚拟地址的映射。为什么指针 `e` 在地址切换之前和之后被解除引用?
-```markdown
-小挑战!目前的 JOS 内核还不能应用到使用了 x87 协处理器、MMX 指令集、或流式 SIMD 扩展(SSE)的 x86 处理器上。扩展数据结构 `Env` 去提供一个能够保存处理器的浮点状态的地方,并且扩展上下文切换代码,当从一个环境切换到另一个环境时,能够保存和还原正确的状态。`FXSAVE` 和 `FXRSTOR` 指令或许对你有帮助,但是需要注意的是,这些指令在旧的 x86 用户手册上没有,因为它是在较新的处理器上引入的。写一个用户级的测试程序,让它使用浮点做一些很酷的事情。
-```
+.
-##### 创建环境的系统调用
+> **问题 4**、无论何时,内核从一个环境切换到另一个环境,它必须要确保旧环境的寄存器内容已经被保存,以便于它们稍后能够正确地还原。为什么?这种事件发生在什么地方?
+
+.
+
+> 小挑战!给内核添加一个小小的调度策略,比如一个固定优先级的调度器,它将会给每个环境分配一个优先级,并且在执行中,较高优先级的环境总是比低优先级的环境优先被选定。如果你想去冒险一下,尝试实现一个类 Unix 的、优先级可调整的调度器,或者甚至是一个彩票调度器或跨步调度器。(可以在 Google 中查找“彩票调度”和“跨步调度”的相关资料)
+
+> 写一个或两个测试程序,去测试你的调度算法是否工作正常(即,正确的算法能够按正确的次序运行)。如果你实现了本实验的 Part B 和 Part C 部分的 `fork()` 和 IPC,写这些测试程序可能会更容易。
+
+.
+
+> 小挑战!目前的 JOS 内核还不能应用到使用了 x87 协处理器、MMX 指令集、或流式 SIMD 扩展(SSE)的 x86 处理器上。扩展数据结构 `Env` 去提供一个能够保存处理器的浮点状态的地方,并且扩展上下文切换代码,当从一个环境切换到另一个环境时,能够保存和还原正确的状态。`FXSAVE` 和 `FXRSTOR` 指令或许对你有帮助,但是需要注意的是,这些指令在旧的 x86 用户手册上没有,因为它是在较新的处理器上引入的。写一个用户级的测试程序,让它使用浮点做一些很酷的事情。
+
+#### 创建环境的系统调用
虽然你的内核现在已经有了在多个用户级环境之间切换的功能,但是由于内核初始化设置的原因,它在运行环境时仍然是受限的。现在,你需要去实现必需的 JOS 系统调用,以允许用户环境去创建和启动其它的新用户环境。
@@ -229,34 +214,35 @@ Unix 提供了 `fork()` 系统调用作为它的进程创建原语。Unix 的 `f
为创建一个用户模式下的新的环境,你将要提供一个不同的、更原始的 JOS 系统调用集。使用这些系统调用,除了其它类型的环境创建之外,你可以在用户空间中实现一个完整的类 Unix 的 `fork()`。你将要为 JOS 编写的新的系统调用如下:
- * `sys_exofork`:
-这个系统调用创建一个新的空白的环境:在它的地址空间的用户部分什么都没有映射,并且它也不能运行。这个新的环境与 `sys_exofork` 调用时创建它的父环境的寄存器状态完全相同。在父进程中,`sys_exofork` 将返回新创建进程的 `envid_t`(如果环境分配失败的话,返回的是一个负的错误代码)。在子进程中,它将返回 0。(因为子进程从一开始就被标记为不可运行,在子进程中,`sys_exofork` 将并不真的返回,直到它的父进程使用 .... 显式地将子进程标记为可运行之前。)
- * `sys_env_set_status`:
-设置指定的环境状态为 `ENV_RUNNABLE` 或 `ENV_NOT_RUNNABLE`。这个系统调用一般是在,一个新环境的地址空间和寄存器状态已经完全初始化完成之后,用于去标记一个准备去运行的新环境。
- * `sys_page_alloc`:
-分配一个物理内存页,并映射它到一个给定的环境地址空间中、给定的一个虚拟地址上。
- * `sys_page_map`:
-从一个环境的地址空间中复制一个页映射(不是页内容!)到另一个环境的地址空间中,保持一个内存共享,以便于新的和旧的映射共同指向到同一个物理内存页。
- * `sys_page_unmap`:
-在一个给定的环境中,取消映射一个给定的已映射的虚拟地址。
+* `sys_exofork`:
+ 这个系统调用创建一个新的空白的环境:在它的地址空间的用户部分什么都没有映射,并且它也不能运行。这个新的环境与 `sys_exofork` 调用时创建它的父环境的寄存器状态完全相同。在父进程中,`sys_exofork` 将返回新创建进程的 `envid_t`(如果环境分配失败的话,返回的是一个负的错误代码)。在子进程中,它将返回 0。(因为子进程从一开始就被标记为不可运行,在子进程中,`sys_exofork` 将并不真的返回,直到它的父进程使用 .... 显式地将子进程标记为可运行之前。)
+* `sys_env_set_status`:
+ 设置指定的环境状态为 `ENV_RUNNABLE` 或 `ENV_NOT_RUNNABLE`。这个系统调用一般是在,一个新环境的地址空间和寄存器状态已经完全初始化完成之后,用于去标记一个准备去运行的新环境。
+* `sys_page_alloc`:
+
+ 分配一个物理内存页,并映射它到一个给定的环境地址空间中、给定的一个虚拟地址上。
+* `sys_page_map`:
+
+ 从一个环境的地址空间中复制一个页映射(不是页内容!)到另一个环境的地址空间中,保持一个内存共享,以便于新的和旧的映射共同指向到同一个物理内存页。
+* `sys_page_unmap`:
+
+ 在一个给定的环境中,取消映射一个给定的已映射的虚拟地址。
上面所有的系统调用都接受环境 ID 作为参数,JOS 内核支持一个约定,那就是用值 “0” 来表示“当前环境”。这个约定在 `kern/env.c` 中的 `envid2env()` 中实现的。
在我们的 `user/dumbfork.c` 中的测试程序里,提供了一个类 Unix 的 `fork()` 的非常原始的实现。这个测试程序使用了上面的系统调用,去创建和运行一个复制了它自己地址空间的子环境。然后,这两个环境像前面的练习那样使用 `sys_yield` 来回切换,父进程在迭代 10 次后退出,而子进程在迭代 20 次后退出。
-```c
-练习 7、在 `kern/syscall.c` 中实现上面描述的系统调用,并确保 `syscall()` 能调用它们。你将需要使用 `kern/pmap.c` 和 `kern/env.c` 中的多个函数,尤其是要用到 `envid2env()`。目前,每当你调用 `envid2env()` 时,在 `checkperm` 中传递参数 1。你务必要做检查任何无效的系统调用参数,在那个案例中,就返回了 `-E_INVAL`。使用 `user/dumbfork` 测试你的 JOS 内核,并在继续之前确保它运行正常。
-```
+> **练习 7**、在 `kern/syscall.c` 中实现上面描述的系统调用,并确保 `syscall()` 能调用它们。你将需要使用 `kern/pmap.c` 和 `kern/env.c` 中的多个函数,尤其是要用到 `envid2env()`。目前,每当你调用 `envid2env()` 时,在 `checkperm` 中传递参数 1。你务必要做检查任何无效的系统调用参数,在那个案例中,就返回了 `-E_INVAL`。使用 `user/dumbfork` 测试你的 JOS 内核,并在继续之前确保它运行正常。
-```c
-小挑战!添加另外的系统调用,必须能够读取已存在的、所有的、环境的重要状态,以及设置它们。然后实现一个能够 fork 出子环境的用户模式程序,运行它一小会(即,迭代几次 `sys_yield()`),然后取得几张屏幕截图或子环境的检查点,然后运行子环境一段时间,然后还原子环境到检查点时的状态,然后从这里继续开始。这样,你就可以有效地从一个中间状态“回放”了子环境的运行。确保子环境与用户使用 `sys_cgetc()` 或 `readline()` 执行了一些交互,这样,那个用户就能够查看和突变它的内部状态,并且你可以通过给子环境给定一个选择性遗忘的状况,来验证你的检查点/重启动的有效性,使它“遗忘”了在某些点之前发生的事情。
-```
+.
+
+> **小挑战!**添加另外的系统调用,必须能够读取已存在的、所有的、环境的重要状态,以及设置它们。然后实现一个能够 fork 出子环境的用户模式程序,运行它一小会(即,迭代几次 `sys_yield()`),然后取得几张屏幕截图或子环境的检查点,然后运行子环境一段时间,然后还原子环境到检查点时的状态,然后从这里继续开始。这样,你就可以有效地从一个中间状态“回放”了子环境的运行。确保子环境与用户使用 `sys_cgetc()` 或 `readline()` 执行了一些交互,这样,那个用户就能够查看和突变它的内部状态,并且你可以通过给子环境给定一个选择性遗忘的状况,来验证你的检查点/重启动的有效性,使它“遗忘”了在某些点之前发生的事情。
到此为止,已经完成了本实验的 Part A 部分;在你运行 `make grade` 之前确保它通过了所有的 Part A 的测试,并且和以往一样,使用 `make handin` 去提交它。如果你想尝试找出为什么一些特定的测试是失败的,可以运行 `run ./grade-lab4 -v`,它将向你展示内核构建的输出,和测试失败时的 QEMU 运行情况。当测试失败时,这个脚本将停止运行,然后你可以去检查 `jos.out` 的内容,去查看内核真实的输出内容。
-#### Part B:写时复制 Fork
+### Part B:写时复制 Fork
正如在前面提到过的,Unix 提供 `fork()` 系统调用作为它主要的进程创建原语。`fork()` 系统调用通过复制调用进程(父进程)的地址空间来创建一个新进程(子进程)。
@@ -264,11 +250,11 @@ xv6 Unix 的 `fork()` 从父进程的页上复制所有数据,然后将它分
但是,一个对 `fork()` 的调用后,经常是紧接着几乎立即在子进程中有一个到 `exec()` 的调用,它使用一个新程序来替换子进程的内存。这是 shell 默认去做的事,在这种情况下,在复制父进程地址空间上花费的时间是非常浪费的,因为在调用 `exec()` 之前,子进程使用的内存非常少。
-基于这个原因,Unix 的最新版本利用了虚拟内存硬件的优势,允许父进程和子进程去共享映射到它们各自地址空间上的内存,直到其中一个进程真实地修改了它们为止。这个技术就是众所周知的“写时复制”。为实现这一点,在 `fork()` 时,内核将复制从父进程到子进程的地址空间的映射,而不是所映射的页的内容,并且同时设置正在共享中的页为只读。当两个进程中的其中一个尝试去写入到它们共享的页上时,进程将产生一个页故障。在这时,Unix 内核才意识到那个页实际上是“虚拟的”或“写时复制”的副本,然后它生成一个新的、私有的、那个发生页故障的进程可写的、页的副本。在这种方式中,个人的页的内容并不进行真实地复制,直到它们真正进行写入时才进行复制。这种优化使得一个`fork()` 后在子进程中跟随一个 `exec()` 变得代价很低了:子进程在调用 `exec()` 时或许仅需要复制一个页(它的栈的当前页)。
+基于这个原因,Unix 的最新版本利用了虚拟内存硬件的优势,允许父进程和子进程去共享映射到它们各自地址空间上的内存,直到其中一个进程真实地修改了它们为止。这个技术就是众所周知的“写时复制”。为实现这一点,在 `fork()` 时,内核将复制从父进程到子进程的地址空间的映射,而不是所映射的页的内容,并且同时设置正在共享中的页为只读。当两个进程中的其中一个尝试去写入到它们共享的页上时,进程将产生一个页故障。在这时,Unix 内核才意识到那个页实际上是“虚拟的”或“写时复制”的副本,然后它生成一个新的、私有的、那个发生页故障的进程可写的、页的副本。在这种方式中,个人的页的内容并不进行真实地复制,直到它们真正进行写入时才进行复制。这种优化使得一个`fork()` 后在子进程中跟随一个 `exec()` 变得代价很低了:子进程在调用 `exec()` 时或许仅需要复制一个页(它的栈的当前页)。
在本实验的下一段中,你将实现一个带有“写时复制”的“真正的”类 Unix 的 `fork()`,来作为一个常规的用户空间库。在用户空间中实现 `fork()` 和写时复制有一个好处就是,让内核始终保持简单,并且因此更不易出错。它也让个别的用户模式程序在 `fork()` 上定义了它们自己的语义。一个有略微不同实现的程序(例如,代价昂贵的、总是复制的 `dumbfork()` 版本,或父子进程真实共享内存的后面的那一个),它自己可以很容易提供。
-##### 用户级页故障处理
+#### 用户级页故障处理
一个用户级写时复制 `fork()` 需要知道关于在写保护页上的页故障相关的信息,因此,这是你首先需要去实现的东西。对用户级页故障处理来说,写时复制仅是众多可能的用途之一。
@@ -276,15 +262,14 @@ xv6 Unix 的 `fork()` 从父进程的页上复制所有数据,然后将它分
内核跟踪有大量的信息,与传统的 Unix 方法不同,你将决定在每个用户空间中关于每个页故障应该做的事。用户空间中的 bug 危害都较小。这种设计带来了额外的好处,那就是允许程序员在定义它们的内存区域时,会有很好的灵活性;对于映射和访问基于磁盘文件系统上的文件时,你应该使用后面的用户级页故障处理。
-###### 设置页故障服务程序
+##### 设置页故障服务程序
为了处理它自己的页故障,一个用户环境将需要在 JOS 内核上注册一个页故障服务程序入口。用户环境通过新的 `sys_env_set_pgfault_upcall` 系统调用来注册它的页故障入口。我们给结构 `Env` 增加了一个新的成员 `env_pgfault_upcall`,让它去记录这个信息。
-```markdown
-练习 8、实现 `sys_env_set_pgfault_upcall` 系统调用。当查找目标环境的环境 ID 时,一定要确认启用了权限检查,因为这是一个“危险的”系统调用。
+> **练习 8**、实现 `sys_env_set_pgfault_upcall` 系统调用。当查找目标环境的环境 ID 时,一定要确认启用了权限检查,因为这是一个“危险的”系统调用。
```
-###### 在用户环境中的正常和异常栈
+##### 在用户环境中的正常和异常栈
在正常运行期间,JOS 中的一个用户环境运行在正常的用户栈上:它的 `ESP` 寄存器开始指向到 `USTACKTOP`,而它所推送的栈数据将驻留在 `USTACKTOP-PGSIZE` 和 `USTACKTOP-1`(含)之间的页上。但是,当在用户模式中发生页故障时,内核将在一个不同的栈上重新启动用户环境,运行一个用户级页故障指定的服务程序,即用户异常栈。其它,我们将让 JOS 内核为用户环境实现自动的“栈切换”,当从用户模式转换到内核模式时,x86 处理器就以大致相同的方式为 JOS 实现了栈切换。
@@ -292,7 +277,7 @@ JOS 用户异常栈也是一个页的大小,并且它的顶部被定义在虚
每个想去支持用户级页故障处理的用户环境,都需要为它自己的异常栈使用在 Part A 中介绍的 `sys_page_alloc()` 系统调用去分配内存。
-###### 调用用户页故障服务程序
+##### 调用用户页故障服务程序
现在,你需要去修改 `kern/trap.c` 中的页故障处理代码,以能够处理接下来在用户模式中发生的页故障。我们将故障发生时用户环境的状态称之为捕获时状态。
@@ -322,25 +307,20 @@ JOS 用户异常栈也是一个页的大小,并且它的顶部被定义在虚
去测试 `tf->tf_esp` 是否已经在用户异常栈上准备好,可以去检查它是否在 `UXSTACKTOP-PGSIZE` 和 `UXSTACKTOP-1`(含)的范围内。
-```markdown
-练习 9、实现在 `kern/trap.c` 中的 `page_fault_handler` 的代码,要求派发页故障到用户模式故障服务程序上。在写入到异常栈时,一定要采取适当的预防措施。(如果用户环境运行时溢出了异常栈,会发生什么事情?)
-```
+> **练习 9**、实现在 `kern/trap.c` 中的 `page_fault_handler` 的代码,要求派发页故障到用户模式故障服务程序上。在写入到异常栈时,一定要采取适当的预防措施。(如果用户环境运行时溢出了异常栈,会发生什么事情?)
-###### 用户模式页故障入口点
+##### 用户模式页故障入口点
接下来,你需要去实现汇编程序,它将调用 C 页故障服务程序,并在原始的故障指令处恢复程序运行。这个汇编程序是一个故障服务程序,它由内核使用 `sys_env_set_pgfault_upcall()` 来注册。
-```markdown
-练习 10、实现在 `lib/pfentry.S` 中的 `_pgfault_upcall` 程序。最有趣的部分是返回到用户代码中产生页故障的原始位置。你将要直接返回到那里,不能通过内核返回。最难的部分是同时切换栈和重新加载 EIP。
-```
+> **练习 10**、实现在 `lib/pfentry.S` 中的 `_pgfault_upcall` 程序。最有趣的部分是返回到用户代码中产生页故障的原始位置。你将要直接返回到那里,不能通过内核返回。最难的部分是同时切换栈和重新加载 EIP。
最后,你需要去实现用户级页故障处理机制的 C 用户库。
-```c
-练习 11、完成 `lib/pgfault.c` 中的 `set_pgfault_handler()`。
+> **练习 11**、完成 `lib/pgfault.c` 中的 `set_pgfault_handler()`。
```
-###### 测试
+##### 测试
运行 `user/faultread`(make run-faultread)你应该会看到:
@@ -376,7 +356,7 @@ JOS 用户异常栈也是一个页的大小,并且它的顶部被定义在虚
[00001000] free env 00001000
```
-如果你只看到第一个 "this string” 行,意味着你没有正确地处理递归页故障。
+如果你只看到第一个 “this string” 行,意味着你没有正确地处理递归页故障。
运行 `user/faultallocbad` 你应该会看到:
@@ -389,11 +369,9 @@ JOS 用户异常栈也是一个页的大小,并且它的顶部被定义在虚
确保你理解了为什么 `user/faultalloc` 和 `user/faultallocbad` 的行为是不一样的。
-```markdown
-小挑战!扩展你的内核,让它不仅是页故障,而是在用户空间中运行的代码能够产生的所有类型的处理器异常,都能够被重定向到一个用户模式中的异常服务程序上。写出用户模式测试程序,去测试各种各样的用户模式异常处理,比如除零错误、一般保护故障、以及非法操作码。
-```
+> **小挑战!**扩展你的内核,让它不仅是页故障,而是在用户空间中运行的代码能够产生的所有类型的处理器异常,都能够被重定向到一个用户模式中的异常服务程序上。写出用户模式测试程序,去测试各种各样的用户模式异常处理,比如除零错误、一般保护故障、以及非法操作码。
-##### 实现写时复制 Fork
+#### 实现写时复制 Fork
现在,你有个内核功能要去实现,那就是在用户空间中完整地实现写时复制 `fork()`。
@@ -401,38 +379,29 @@ JOS 用户异常栈也是一个页的大小,并且它的顶部被定义在虚
`fork()` 的基本控制流如下:
- 1. 父环境使用你在上面实现的 `set_pgfault_handler()` 函数,安装 `pgfault()` 作为 C 级页故障服务程序。
-
- 2. 父环境调用 `sys_exofork()` 去创建一个子环境。
-
- 3. 在它的地址空间中,低于 UTOP 位置的、每个可写入页、或写时复制页上,父环境调用 `duppage` 后,它应该会映射页写时复制到子环境的地址空间中,然后在它自己的地址空间中重新映射页写时复制。[ 注意:这里的顺序很重要(即,在父环境中标记之前,先在子环境中标记该页为 COW)!你能明白是为什么吗?尝试去想一个具体的案例,将顺序颠倒一下会发生什么样的问题。] `duppage` 把两个 PTE 都设置了,致使那个页不可写入,并且在 "avail” 字段中通过包含 `PTE_COW` 来从真正的只读页中区分写时复制页。
-
-然而异常栈是不能通过这种方式重映射的。对于异常栈,你需要在子环境中分配一个新页。因为页故障服务程序不能做真实的复制,并且页故障服务程序是运行在异常栈上的,异常栈不能进行写时复制:那么谁来复制它呢?
-
-`fork()` 也需要去处理存在的页,但不能写入或写时复制。
-
- 4. 父环境为子环境设置了用户页故障入口点,让它看起来像它自己的一样。
-
- 5. 现在,子环境准备去运行,所以父环境标记它为可运行。
-
+1. 父环境使用你在上面实现的 `set_pgfault_handler()` 函数,安装 `pgfault()` 作为 C 级页故障服务程序。
+2. 父环境调用 `sys_exofork()` 去创建一个子环境。
+3. 在它的地址空间中,低于 UTOP 位置的、每个可写入页、或写时复制页上,父环境调用 `duppage` 后,它应该会映射页写时复制到子环境的地址空间中,然后在它自己的地址空间中重新映射页写时复制。[ 注意:这里的顺序很重要(即,在父环境中标记之前,先在子环境中标记该页为 COW)!你能明白是为什么吗?尝试去想一个具体的案例,将顺序颠倒一下会发生什么样的问题。] `duppage` 把两个 PTE 都设置了,致使那个页不可写入,并且在 "avail” 字段中通过包含 `PTE_COW` 来从真正的只读页中区分写时复制页。
+ 然而异常栈是不能通过这种方式重映射的。对于异常栈,你需要在子环境中分配一个新页。因为页故障服务程序不能做真实的复制,并且页故障服务程序是运行在异常栈上的,异常栈不能进行写时复制:那么谁来复制它呢?
+ `fork()` 也需要去处理存在的页,但不能写入或写时复制。
+4. 父环境为子环境设置了用户页故障入口点,让它看起来像它自己的一样。
+5. 现在,子环境准备去运行,所以父环境标记它为可运行。
每次其中一个环境写一个还没有写入的写时复制页时,它将产生一个页故障。下面是用户页故障服务程序的控制流:
- 1. 内核传递页故障到 `_pgfault_upcall`,它调用 `fork()` 的 `pgfault()` 服务程序。
- 2. `pgfault()` 检测到那个故障是一个写入(在错误代码中检查 `FEC_WR`),然后将那个页的 PTE 标记为 `PTE_COW`。如果不是一个写入,则崩溃。
- 3. `pgfault()` 在一个临时位置分配一个映射的新页,并将故障页的内容复制进去。然后,故障服务程序以读取/写入权限映射新页到合适的地址,替换旧的只读映射。
-
-
+1. 内核传递页故障到 `_pgfault_upcall`,它调用 `fork()` 的 `pgfault()` 服务程序。
+2. `pgfault()` 检测到那个故障是一个写入(在错误代码中检查 `FEC_WR`),然后将那个页的 PTE 标记为 `PTE_COW`。如果不是一个写入,则崩溃。
+3. `pgfault()` 在一个临时位置分配一个映射的新页,并将故障页的内容复制进去。然后,故障服务程序以读取/写入权限映射新页到合适的地址,替换旧的只读映射。
对于上面的几个操作,用户级 `lib/fork.c` 代码必须查询环境的页表(即,那个页的 PTE 是否标记为 `PET_COW`)。为此,内核在 `UVPT` 位置精确地映射环境的页表。它使用一个 [聪明的映射技巧][1] 去标记它,以使用户代码查找 PTE 时更容易。`lib/entry.S` 设置 `uvpt` 和 `uvpd`,以便于你能够在 `lib/fork.c` 中轻松查找页表信息。
-```c
-练习 12、在 `lib/fork.c` 中实现 `fork`、`duppage` 和 `pgfault`。
+> **练习 12**、在 `lib/fork.c` 中实现 `fork`、`duppage` 和 `pgfault`。
-使用 `forktree` 程序测试你的代码。它应该会产生下列的信息,在信息中会有 'new env'、'free env'、和 'exiting gracefully' 这样的字眼。信息可能不是按如下的顺序出现的,并且环境 ID 也可能不一样。
+> 使用 `forktree` 程序测试你的代码。它应该会产生下列的信息,在信息中会有 'new env'、'free env'、和 'exiting gracefully' 这样的字眼。信息可能不是按如下的顺序出现的,并且环境 ID 也可能不一样。
+>```
1000: I am ''
1001: I am '0'
2000: I am '00'
@@ -450,31 +419,32 @@ JOS 用户异常栈也是一个页的大小,并且它的顶部被定义在虚
1006: I am '101'
```
-```c
-小挑战!实现一个名为 `sfork()` 的共享内存的 `fork()`。这个版本的 `sfork()` 中,父子环境共享所有的内存页(因此,一个环境中对内存写入,就会改变另一个环境数据),除了在栈区域中的页以外,它应该使用写时复制来处理这些页。修改 `user/forktree.c` 去使用 `sfork()` 而是不常见的 `fork()`。另外,你在 Part C 中实现了 IPC 之后,使用你的 `sfork()` 去运行 `user/pingpongs`。你将找到提供全局指针 `thisenv` 功能的一个新方式。
-```
+.
-```markdown
-小挑战!你实现的 `fork` 将产生大量的系统调用。在 x86 上,使用中断切换到内核模式将产生较高的代价。增加系统调用接口,以便于它能够一次发送批量的系统调用。然后修改 `fork` 去使用这个接口。
-你的新的 `fork` 有多快?
+> **小挑战!**实现一个名为 `sfork()` 的共享内存的 `fork()`。这个版本的 `sfork()` 中,父子环境共享所有的内存页(因此,一个环境中对内存写入,就会改变另一个环境数据),除了在栈区域中的页以外,它应该使用写时复制来处理这些页。修改 `user/forktree.c` 去使用 `sfork()` 而是不常见的 `fork()`。另外,你在 Part C 中实现了 IPC 之后,使用你的 `sfork()` 去运行 `user/pingpongs`。你将找到提供全局指针 `thisenv` 功能的一个新方式。
-你可以用一个分析来论证,批量提交对你的 `fork` 的性能改变,以它来(粗略地)回答这个问题:使用一个 `int 0x30` 指令的代价有多高?在你的 `fork` 中运行了多少次 `int 0x30` 指令?访问 `TSS` 栈切换的代价高吗?等待 ...
+.
-或者,你可以在真实的硬件上引导你的内核,并且真实地对你的代码做基准测试。查看 `RDTSC`(读取时间戳计数器)指令,它的定义在 IA32 手册中,它计数自上一次处理器重置以来流逝的时钟周期数。QEMU 并不能真实地模拟这个指令(它能够计数运行的虚拟指令数量,或使用主机的 TSC,但是这两种方式都不能反映真实的 CPU 周期数)。
-```
+> **小挑战!**你实现的 `fork` 将产生大量的系统调用。在 x86 上,使用中断切换到内核模式将产生较高的代价。增加系统调用接口,以便于它能够一次发送批量的系统调用。然后修改 `fork` 去使用这个接口。
+
+> 你的新的 `fork` 有多快?
+
+> 你可以用一个分析来论证,批量提交对你的 `fork` 的性能改变,以它来(粗略地)回答这个问题:使用一个 `int 0x30` 指令的代价有多高?在你的 `fork` 中运行了多少次 `int 0x30` 指令?访问 `TSS` 栈切换的代价高吗?等待 ...
+
+> 或者,你可以在真实的硬件上引导你的内核,并且真实地对你的代码做基准测试。查看 `RDTSC`(读取时间戳计数器)指令,它的定义在 IA32 手册中,它计数自上一次处理器重置以来流逝的时钟周期数。QEMU 并不能真实地模拟这个指令(它能够计数运行的虚拟指令数量,或使用主机的 TSC,但是这两种方式都不能反映真实的 CPU 周期数)。
到此为止,Part B 部分结束了。在你运行 `make grade` 之前,确保你通过了所有的 Part B 部分的测试。和以前一样,你可以使用 `make handin` 去提交你的实验。
-#### Part C:抢占式多任务处理和进程间通讯(IPC)
+### Part C:抢占式多任务处理和进程间通讯(IPC)
在实验 4 的最后部分,你将修改内核去抢占不配合的环境,并允许环境之间显式地传递消息。
-##### 时钟中断和抢占
+#### 时钟中断和抢占
运行测试程序 `user/spin`。这个测试程序 fork 出一个子环境,它控制了 CPU 之后,就永不停歇地运转起来。无论是父环境还是内核都不能回收对 CPU 的控制。从用户模式环境中保护系统免受 bug 或恶意代码攻击的角度来看,这显然不是个理想的状态,因为任何用户模式环境都能够通过简单的无限循环,并永不归还 CPU 控制权的方式,让整个系统处于暂停状态。为了允许内核去抢占一个运行中的环境,从其中夺回对 CPU 的控制权,我们必须去扩展 JOS 内核,以支持来自硬件时钟的外部硬件中断。
-###### 中断规则
+##### 中断规则
外部中断(即:设备中断)被称为 IRQ。现在有 16 个可能出现的 IRQ,编号 0 到 15。从 IRQ 号到 IDT 条目的映射是不固定的。在 `picirq.c` 中的 `pic_init` 映射 IRQ 0 - 15 到 IDT 条目 `IRQ_OFFSET` 到 `IRQ_OFFSET+15`。
@@ -484,31 +454,27 @@ JOS 用户异常栈也是一个页的大小,并且它的顶部被定义在虚
处于用户环境中时,你将要确保 `FL_IF` 标志被设置,以便于出现一个中断时,它能够通过处理器来传递,让你的中断代码来处理。否则,中断将被屏蔽或忽略,直到中断被重新打开后。我们使用引导加载程序的第一个指令去屏蔽中断,并且到目前为止,还没有去重新打开它们。
-```markdown
-练习 13、修改 `kern/trapentry.S` 和 `kern/trap.c` 去初始化 IDT 中的相关条目,并为 IRQ 0 到 15 提供服务程序。然后修改 `kern/env.c` 中的 `env_alloc()` 的代码,以确保在用户环境中,中断总是打开的。
+> **练习 13**、修改 `kern/trapentry.S` 和 `kern/trap.c` 去初始化 IDT 中的相关条目,并为 IRQ 0 到 15 提供服务程序。然后修改 `kern/env.c` 中的 `env_alloc()` 的代码,以确保在用户环境中,中断总是打开的。
-另外,在 `sched_halt()` 中取消注释 `sti` 指令,以便于空闲的 CPU 取消屏蔽中断。
+> 另外,在 `sched_halt()` 中取消注释 `sti` 指令,以便于空闲的 CPU 取消屏蔽中断。
-当调用一个硬件中断服务程序时,处理器不会推送一个错误代码。在这个时候,你可能需要重新阅读 [80386 参考手册][2] 的 9.2 节,或 [IA-32 Intel 架构软件开发者手册 卷 3][3] 的 5.8 节。
+> 当调用一个硬件中断服务程序时,处理器不会推送一个错误代码。在这个时候,你可能需要重新阅读 [80386 参考手册][2] 的 9.2 节,或 [IA-32 Intel 架构软件开发者手册 卷 3][3] 的 5.8 节。
-在完成这个练习后,如果你在你的内核上使用任意的测试程序去持续运行(即:`spin`),你应该会看到内核输出中捕获的硬件中断的捕获帧。虽然在处理器上已经打开了中断,但是 JOS 并不能处理它们,因此,你应该会看到在当前运行的用户环境中每个中断的错误属性并被销毁,最终环境会被销毁并进入到监视器中。
-```
+> 在完成这个练习后,如果你在你的内核上使用任意的测试程序去持续运行(即:`spin`),你应该会看到内核输出中捕获的硬件中断的捕获帧。虽然在处理器上已经打开了中断,但是 JOS 并不能处理它们,因此,你应该会看到在当前运行的用户环境中每个中断的错误属性并被销毁,最终环境会被销毁并进入到监视器中。
-###### 处理时钟中断
+##### 处理时钟中断
在 `user/spin` 程序中,子环境首先运行之后,它只是进入一个高速循环中,并且内核再无法取得 CPU 控制权。我们需要对硬件编程,定期产生时钟中断,它将强制将 CPU 控制权返还给内核,在内核中,我们就能够将控制权切换到另外的用户环境中。
我们已经为你写好了对 `lapic_init` 和 `pic_init`(来自 `init.c` 中的 `i386_init`)的调用,它将设置时钟和中断控制器去产生中断。现在,你需要去写代码来处理这些中断。
-```markdown
-练习 14、修改内核的 `trap_dispatch()` 函数,以便于在时钟中断发生时,它能够调用 `sched_yield()` 去查找和运行一个另外的环境。
+> **练习 14**、修改内核的 `trap_dispatch()` 函数,以便于在时钟中断发生时,它能够调用 `sched_yield()` 去查找和运行一个另外的环境。
-现在,你应该能够用 `user/spin` 去做测试了:父环境应该会 fork 出子环境,`sys_yield()` 到它许多次,但每次切换之后,将重新获得对 CPU 的控制权,最后杀死子环境后优雅地终止。
-```
+> 现在,你应该能够用 `user/spin` 去做测试了:父环境应该会 fork 出子环境,`sys_yield()` 到它许多次,但每次切换之后,将重新获得对 CPU 的控制权,最后杀死子环境后优雅地终止。
这是做回归测试的好机会。确保你没有弄坏本实验的前面部分,确保打开中断能够正常工作(即: `forktree`)。另外,尝试使用 ` make CPUS=2 target` 在多个 CPU 上运行它。现在,你应该能够通过 `stresssched` 测试。可以运行 `make grade` 去确认。现在,你的得分应该是 65 分了(总分为 80)。
-##### 进程间通讯(IPC)
+#### 进程间通讯(IPC)
(严格来说,在 JOS 中这是“环境间通讯” 或 “IEC”,但所有人都称它为 IPC,因此我们使用标准的术语。)
@@ -516,13 +482,13 @@ JOS 用户异常栈也是一个页的大小,并且它的顶部被定义在虚
进程间通讯有许多模型。关于哪个模型最好的争论从来没有停止过。我们不去参与这种争论。相反,我们将要实现一个简单的 IPC 机制,然后尝试使用它。
-###### JOS 中的 IPC
+##### JOS 中的 IPC
你将要去实现另外几个 JOS 内核的系统调用,由它们共同来提供一个简单的进程间通讯机制。你将要实现两个系统调用,`sys_ipc_recv` 和 `sys_ipc_try_send`。然后你将要实现两个库去封装 `ipc_recv` 和 `ipc_send`。
用户环境可以使用 JOS 的 IPC 机制相互之间发送 “消息” 到每个其它环境,这些消息有两部分组成:一个单个的 32 位值,和可选的一个单个页映射。允许环境在消息中传递页映射,提供了一个高效的方式,传输比一个仅适合单个的 32 位整数更多的数据,并且也允许环境去轻松地设置安排共享内存。
-###### 发送和接收消息
+##### 发送和接收消息
一个环境通过调用 `sys_ipc_recv` 去接收消息。这个系统调用将取消对当前环境的调度,并且不会再次去运行它,直到消息被接收为止。当一个环境正在等待接收一个消息时,任何其它环境都能够给它发送一个消息 — 而不仅是一个特定的环境,而且不仅是与接收环境有父子关系的环境。换句话说,你在 Part A 中实现的权限检查将不会应用到 IPC 上,因为 IPC 系统调用是经过慎重设计的,因此可以认为它是“安全的”:一个环境并不能通过给它发送消息导致另一个环境发生故障(除非目标环境也存在 Bug)。
@@ -532,7 +498,7 @@ JOS 用户异常栈也是一个页的大小,并且它的顶部被定义在虚
同样,一个库函数 `ipc_send` 将去不停地调用 `sys_ipc_try_send` 来发送消息,直到发送成功为止。
-###### 转移页
+##### 转移页
当一个环境使用一个有效的 `dstva` 参数(低于 `UTOP`)去调用 `sys_ipc_recv` 时,环境将声明愿意去接收一个页映射。如果发送方发送一个页,那么那个页应该会被映射到接收者地址空间的 `dstva` 处。如果接收者在 `dstva` 已经有了一个页映射,那么已存在的那个页映射将被取消映射。
@@ -540,31 +506,30 @@ JOS 用户异常栈也是一个页的大小,并且它的顶部被定义在虚
如果发送方和接收方都没有表示要转移这个页,那么就不会有页被转移。在任何 IPC 之后,内核将在接收方的 `Env` 结构上设置新的 `env_ipc_perm` 字段,以允许接收页,或者将它设置为 0,表示不再接收。
-###### 实现 IPC
+##### 实现 IPC
-```markdown
-练习 15、实现 `kern/syscall.c` 中的 `sys_ipc_recv` 和 `sys_ipc_try_send`。在实现它们之前一起阅读它们的注释信息,因为它们要一起工作。当你在这些程序中调用 `envid2env` 时,你应该去设置 `checkperm` 的标志为 0,这意味着允许任何环境去发送 IPC 消息到另外的环境,并且内核除了验证目标 envid 是否有效外,不做特别的权限检查。
+> **练习 15**、实现 `kern/syscall.c` 中的 `sys_ipc_recv` 和 `sys_ipc_try_send`。在实现它们之前一起阅读它们的注释信息,因为它们要一起工作。当你在这些程序中调用 `envid2env` 时,你应该去设置 `checkperm` 的标志为 0,这意味着允许任何环境去发送 IPC 消息到另外的环境,并且内核除了验证目标 envid 是否有效外,不做特别的权限检查。
-接着实现 `lib/ipc.c` 中的 `ipc_recv` 和 `ipc_send` 函数。
+> 接着实现 `lib/ipc.c` 中的 `ipc_recv` 和 `ipc_send` 函数。
-使用 `user/pingpong` 和 `user/primes` 函数去测试你的 IPC 机制。`user/primes` 将为每个质数生成一个新环境,直到 JOS 耗尽环境为止。你可能会发现,阅读 `user/primes.c` 非常有趣,你将看到所有的 fork 和 IPC 都是在幕后进行。
-```
+> 使用 `user/pingpong` 和 `user/primes` 函数去测试你的 IPC 机制。`user/primes` 将为每个质数生成一个新环境,直到 JOS 耗尽环境为止。你可能会发现,阅读 `user/primes.c` 非常有趣,你将看到所有的 fork 和 IPC 都是在幕后进行。
-```
-小挑战!为什么 `ipc_send` 要循环调用?修改系统调用接口,让它不去循环。确保你能处理多个环境尝试同时发送消息到一个环境上的情况。
-```
+.
-```markdown
-小挑战!质数筛选是在大规模并发程序中传递消息的一个很巧妙的用法。阅读 C. A. R. Hoare 写的 《Communicating Sequential Processes》,Communications of the ACM_ 21(8) (August 1978), 666-667,并去实现矩阵乘法示例。
-```
-```markdown
-小挑战!控制消息传递的最令人印象深刻的一个例子是,Doug McIlroy 的幂序列计算器,它在 [M. Douglas McIlroy,《Squinting at Power Series》,Software--Practice and Experience, 20(7) (July 1990),661-683][4] 中做了详细描述。实现了它的幂序列计算器,并且计算了 _sin_ ( _x_ + _x_ ^3) 的幂序列。
-```
+> **小挑战!**为什么 `ipc_send` 要循环调用?修改系统调用接口,让它不去循环。确保你能处理多个环境尝试同时发送消息到一个环境上的情况。
-```markdown
-小挑战!通过应用 Liedtke 的论文([通过内核设计改善 IPC 性能][5])中的一些技术、或你可以想到的其它技巧,来让 JOS 的 IPC 机制更高效。为此,你可以随意修改内核的系统调用 API,只要你的代码向后兼容我们的评级脚本就行。
-```
+.
+
+> **小挑战!**质数筛选是在大规模并发程序中传递消息的一个很巧妙的用法。阅读 C. A. R. Hoare 写的 《Communicating Sequential Processes》,Communications of the ACM_ 21(8) (August 1978), 666-667,并去实现矩阵乘法示例。
+
+.
+
+> **小挑战!**控制消息传递的最令人印象深刻的一个例子是,Doug McIlroy 的幂序列计算器,它在 [M. Douglas McIlroy,《Squinting at Power Series》,Software--Practice and Experience, 20(7) (July 1990),661-683][4] 中做了详细描述。实现了它的幂序列计算器,并且计算了 _sin_ ( _x_ + _x_ ^3) 的幂序列。
+
+.
+
+> **小挑战!**通过应用 Liedtke 的论文([通过内核设计改善 IPC 性能][5])中的一些技术、或你可以想到的其它技巧,来让 JOS 的 IPC 机制更高效。为此,你可以随意修改内核的系统调用 API,只要你的代码向后兼容我们的评级脚本就行。
**Part C 到此结束了。**确保你通过了所有的评级测试,并且不要忘了将你的小挑战的答案写入到 `answers-lab4.txt` 中。
@@ -577,7 +542,7 @@ via: https://pdos.csail.mit.edu/6.828/2018/labs/lab4/
作者:[csail.mit][a]
选题:[lujun9972][b]
译者:[qhwdw](https://github.com/qhwdw)
-校对:[校对者ID](https://github.com/校对者ID)
+校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
@@ -587,4 +552,4 @@ via: https://pdos.csail.mit.edu/6.828/2018/labs/lab4/
[2]: https://pdos.csail.mit.edu/6.828/2018/labs/readings/i386/toc.htm
[3]: https://pdos.csail.mit.edu/6.828/2018/labs/readings/ia32/IA32-3A.pdf
[4]: https://swtch.com/~rsc/thread/squint.pdf
-[5]: http://dl.acm.org/citation.cfm?id=168633
\ No newline at end of file
+[5]: http://dl.acm.org/citation.cfm?id=168633
diff --git a/translated/tech/20181016 Lab 5- File system, Spawn and Shell.md b/published/201812/20181016 Lab 5- File system, Spawn and Shell.md
similarity index 71%
rename from translated/tech/20181016 Lab 5- File system, Spawn and Shell.md
rename to published/201812/20181016 Lab 5- File system, Spawn and Shell.md
index 769b90bd20..dbd9a3b490 100644
--- a/translated/tech/20181016 Lab 5- File system, Spawn and Shell.md
+++ b/published/201812/20181016 Lab 5- File system, Spawn and Shell.md
@@ -1,4 +1,4 @@
-实验 5:文件系统、Spawn 和 Shell
+Caffeinated 6.828:实验 5:文件系统、Spawn 和 Shell
======
### 简介
@@ -10,31 +10,31 @@
使用 Git 去获取最新版的课程仓库,然后创建一个命名为 `lab5` 的本地分支,去跟踪远程的 `origin/lab5` 分支:
```
- athena% cd ~/6.828/lab
- athena% add git
- athena% git pull
- Already up-to-date.
- athena% git checkout -b lab5 origin/lab5
- Branch lab5 set up to track remote branch refs/remotes/origin/lab5.
- Switched to a new branch "lab5"
- athena% git merge lab4
- Merge made by recursive.
- .....
- athena%
+athena% cd ~/6.828/lab
+athena% add git
+athena% git pull
+Already up-to-date.
+athena% git checkout -b lab5 origin/lab5
+Branch lab5 set up to track remote branch refs/remotes/origin/lab5.
+Switched to a new branch "lab5"
+athena% git merge lab4
+Merge made by recursive.
+.....
+athena%
```
在实验中这一部分的主要新组件是文件系统环境,它位于新的 `fs` 目录下。通过检查这个目录中的所有文件,我们来看一下新的文件都有什么。另外,在 `user` 和 `lib` 目录下还有一些文件系统相关的源文件。
-fs/fs.c 维护文件系统在磁盘上结构的代码
-fs/bc.c 构建在我们的用户级页故障处理功能之上的一个简单的块缓存
-fs/ide.c 极简的基于 PIO(非中断驱动的)IDE 驱动程序代码
-fs/serv.c 使用文件系统 IPC 与客户端环境交互的文件系统服务器
-lib/fd.c 实现一个常见的类 UNIX 的文件描述符接口的代码
-lib/file.c 磁盘上文件类型的驱动,实现为一个文件系统 IPC 客户端
-lib/console.c 控制台输入/输出文件类型的驱动
-lib/spawn.c spawn 库调用的框架代码
+- `fs/fs.c` 维护文件系统在磁盘上结构的代码
+- `fs/bc.c` 构建在我们的用户级页故障处理功能之上的一个简单的块缓存
+- `fs/ide.c` 极简的基于 PIO(非中断驱动的)IDE 驱动程序代码
+- `fs/serv.c` 使用文件系统 IPC 与客户端环境交互的文件系统服务器
+- `lib/fd.c` 实现一个常见的类 UNIX 的文件描述符接口的代码
+- `lib/file.c` 磁盘上文件类型的驱动,实现为一个文件系统 IPC 客户端
+- `lib/console.c` 控制台输入/输出文件类型的驱动
+- `lib/spawn.c` spawn 库调用的框架代码
-你应该再次去运行 `pingpong`、`primes`、和 `forktree`,测试实验 4 完成后合并到新的实验 5 中的代码能否正确运行。你还需要在 `kern/init.c` 中注释掉 `ENV_CREATE(fs_fs)` 行,因为 `fs/fs.c` 将尝试去做一些 I/O,而 JOS 到目前为止还不具备该功能。同样,在 `lib/exit.c` 中临时注释掉对 `close_all()` 的调用;这个函数将调用你在本实验后面部分去实现的子程序,如果现在去调用,它将导致 JOS 内核崩溃。如果你的实验 4 的代码没有任何 bug,将很完美地通过这个测试。在它们都能正常工作之前是不能继续后续实验的。在你开始做练习 1 时,不要忘记去取消这些行上的注释。
+你应该再次去运行 `pingpong`、`primes` 和 `forktree`,测试实验 4 完成后合并到新的实验 5 中的代码能否正确运行。你还需要在 `kern/init.c` 中注释掉 `ENV_CREATE(fs_fs)` 行,因为 `fs/fs.c` 将尝试去做一些 I/O,而 JOS 到目前为止还不具备该功能。同样,在 `lib/exit.c` 中临时注释掉对 `close_all()` 的调用;这个函数将调用你在本实验后面部分去实现的子程序,如果现在去调用,它将导致 JOS 内核崩溃。如果你的实验 4 的代码没有任何 bug,将很完美地通过这个测试。在它们都能正常工作之前是不能继续后续实验的。在你开始做练习 1 时,不要忘记去取消这些行上的注释。
如果它们不能正常工作,使用 `git diff lab4` 去重新评估所有的变更,确保你在实验 4(及以前)所写的代码在本实验中没有丢失。确保实验 4 仍然能正常工作。
@@ -44,11 +44,11 @@ lib/spawn.c spawn 库调用的框架代码
### 文件系统的雏形
-你将要使用的文件系统比起大多数“真正的”文件系统(包括 xv6 UNIX 的文件系统)要简单的多,但它也是很强大的,足够去提供基本的特性:创建、读取、写入、和删除组织在层次目录结构中的文件。
+你将要使用的文件系统比起大多数“真正的”文件系统(包括 xv6 UNIX 的文件系统)要简单的多,但它也是很强大的,足够去提供基本的特性:创建、读取、写入和删除组织在层次目录结构中的文件。
到目前为止,我们开发的是一个单用户操作系统,它提供足够的保护并能去捕获 bug,但它还不能在多个不可信用户之间提供保护。因此,我们的文件系统还不支持 UNIX 的所有者或权限的概念。我们的文件系统目前也不支持硬链接、时间戳、或像大多数 UNIX 文件系统实现的那些特殊的设备文件。
-### 磁盘上文件系统结构
+### 磁盘上的文件系统结构
主流的 UNIX 文件系统将可用磁盘空间分为两种主要的区域类型:节点区域和数据区域。UNIX 文件系统在文件系统中为每个文件分配一个节点;一个文件的节点保存了这个文件重要的元数据,比如它的 `stat` 属性和指向数据块的指针。数据区域被分为更大的(一般是 8 KB 或更大)数据块,它在文件系统中存储文件数据和目录元数据。目录条目包含文件名字和指向到节点的指针;如果文件系统中的多个目录条目指向到那个文件的节点上,则称该文件是硬链接的。由于我们的文件系统不支持硬链接,所以我们不需要这种间接的级别,并且因此可以更方便简化:我们的文件系统将压根就不使用节点,而是简单地将文件的(或子目录的)所有元数据保存在描述那个文件的(唯一的)目录条目中。
@@ -71,6 +71,7 @@ UNIX xv6 文件系统使用 512 字节大小的块,与它底层磁盘的扇区
#### 文件元数据
![File structure][2]
+
元数据的布局是描述在我们的文件系统中的一个文件中,这个文件就是 `inc/fs.h` 中的 `struct File`。元数据包含文件的名字、大小、类型(普通文件还是目录)、指向构成这个文件的块的指针。正如前面所提到的,我们的文件系统中并没有节点,因此元数据是保存在磁盘上的一个目录条目中,而不是像大多数“真正的”文件系统那样保存在节点中。为简单起见,我们将使用 `File` 这一个结构去表示文件元数据,因为它要同时出现在磁盘上和内存中。
在 `struct File` 中的数组 `f_direct` 包含一个保存文件的前 10 个块(`NDIRECT`)的块编号的空间,我们称之为文件的直接块。对于最大 `10*4096 = 40KB` 的小文件,这意味着这个文件的所有块的块编号将全部直接保存在结构 `File` 中,但是,对于超过 40 KB 大小的文件,我们需要一个地方去保存文件剩余的块编号。所以我们分配一个额外的磁盘块,我们称之为文件的间接块,由它去保存最多 4096/4 = 1024 个额外的块编号。因此,我们的文件系统最多允许有 1034 个块,或者说不能超过 4MB 大小。为支持大文件,“真正的”文件系统一般都支持两个或三个间接块。
@@ -91,33 +92,28 @@ UNIX xv6 文件系统使用 512 字节大小的块,与它底层磁盘的扇区
只要我们依赖轮询、基于 “编程的 I/O”(PIO)的磁盘访问,并且不使用磁盘中断,那么在用户空间中实现磁盘访问还是很容易的。也可以去实现由中断驱动的设备驱动程序(比如像 L3 和 L4 内核就是这么做的),但这样做的话,内核必须接收设备中断并将它派发到相应的用户模式环境上,这样实现的难度会更大。
-x86 处理器在 EFLAGS 寄存器中使用 IOPL 位去确定保护模式中的代码是否允许执行特定的设备 I/O 指令,比如 `IN` 和 `OUT` 指令。由于我们需要的所有 IDE 磁盘寄存器都位于 x86 的 I/O 空间中而不是映射在内存中,所以,为了允许文件系统去访问这些寄存器,我们需要做的唯一的事情便是授予文件系统环境“I/O 权限”。实际上,在 EFLAGS 寄存器的 IOPL 位上规定,内核使用一个简单的“要么全都能访问、要么全都不能访问”的方法来控制用户模式中的代码能否访问 I/O 空间。在我们的案例中,我们希望文件系统环境能够去访问 I/O 空间,但我们又希望任何其它的环境完全不能访问 I/O 空间。
+x86 处理器在 EFLAGS 寄存器中使用 IOPL 位去确定保护模式中的代码是否允许执行特定的设备 I/O 指令,比如 `IN` 和 `OUT` 指令。由于我们需要的所有 IDE 磁盘寄存器都位于 x86 的 I/O 空间中而不是映射在内存中,所以,为了允许文件系统去访问这些寄存器,我们需要做的唯一的事情便是授予文件系统环境“I/O 权限”。实际上,在 EFLAGS 寄存器的 IOPL 位上规定,内核使用一个简单的“要么全都能访问、要么全都不能访问”的方法来控制用户模式中的代码能否访问 I/O 空间。在我们的案例中,我们希望文件系统环境能够去访问 I/O 空间,但我们又希望任何其它的环境完全不能访问 I/O 空间。
-```markdown
-练习 1、`i386_init` 通过将类型 `ENV_TYPE_FS` 传递给你的环境创建函数 `env_create` 来识别文件系统。修改 `env.c` 中的 `env_create` ,以便于它只授予文件系统环境 I/O 的权限,而不授予任何其它环境 I/O 的权限。
+> **练习 1**、`i386_init` 通过将类型 `ENV_TYPE_FS` 传递给你的环境创建函数 `env_create` 来识别文件系统。修改 `env.c` 中的 `env_create` ,以便于它只授予文件系统环境 I/O 的权限,而不授予任何其它环境 I/O 的权限。
-确保你能启动这个文件系统环境,而不会产生一般保护故障。你应该要通过在 `make grade` 中的 "fs i/o" 测试。
-```
+> 确保你能启动这个文件系统环境,而不会产生一般保护故障。你应该要通过在 `make grade` 中的 "fs i/o" 测试。
-```markdown
-问题
-
- 1、当你从一个环境切换到另一个环境时,你是否需要做一些操作来确保 I/O 权限设置能被保存和正确地恢复?为什么?
-```
+.
+> **问题 1**、当你从一个环境切换到另一个环境时,你是否需要做一些操作来确保 I/O 权限设置能被保存和正确地恢复?为什么?
注意本实验中的 `GNUmakefile` 文件,它用于设置 QEMU 去使用文件 `obj/kern/kernel.img` 作为磁盘 0 的镜像(一般情况下表示 DOS 或 Windows 中的 “C 盘”),以及使用(新)文件 `obj/fs/fs.img` 作为磁盘 1 的镜像(”D 盘“)。在本实验中,我们的文件系统应该仅与磁盘 1 有交互;而磁盘 0 仅用于去引导内核。如果你想去恢复其中一个有某些错误的磁盘镜像,你可以通过输入如下的命令,去重置它们到最初的、”崭新的“版本:
```
- $ rm obj/kern/kernel.img obj/fs/fs.img
- $ make
+$ rm obj/kern/kernel.img obj/fs/fs.img
+$ make
```
或者:
```
- $ make clean
- $ make
+$ make clean
+$ make
```
小挑战!实现中断驱动的 IDE 磁盘访问,既可以使用也可以不使用 DMA 模式。由你来决定是否将设备驱动移植进内核中、还是与文件系统一样保留在用户空间中、甚至是将它移植到一个它自己的的单独的环境中(如果你真的想了解微内核的本质的话)。
@@ -132,45 +128,39 @@ x86 处理器在 EFLAGS 寄存器中使用 IOPL 位去确定保护模式中的
当然,将整个磁盘读入到内存中需要很长时间,因此,我们将它实现成”按需“分页的形式,那样我们只在磁盘映射区域中分配页,并且当在这个区域中产生页故障时,从磁盘读取相关的块去响应这个页故障。通过这种方式,我们能够假装将整个磁盘装进了内存中。
-```markdown
-练习 2、在 `fs/bc.c` 中实现 `bc_pgfault` 和 `flush_block` 函数。`bc_pgfault` 函数是一个页故障服务程序,就像你在前一个实验中编写的写时复制 fork 一样,只不过它的任务是从磁盘中加载页去响应一个页故障。在你编写它时,记住: (1) `addr` 可能并不会做边界对齐,并且 (2) 在扇区中的 `ide_read` 操作并不是以块为单位的。
+> **练习 2**、在 `fs/bc.c` 中实现 `bc_pgfault` 和 `flush_block` 函数。`bc_pgfault` 函数是一个页故障服务程序,就像你在前一个实验中编写的写时复制 fork 一样,只不过它的任务是从磁盘中加载页去响应一个页故障。在你编写它时,记住: (1) `addr` 可能并不会做边界对齐,并且 (2) 在扇区中的 `ide_read` 操作并不是以块为单位的。
-(如果需要的话)函数 `flush_block` 应该会将一个块写入到磁盘上。如果在块缓存中没有块(也就是说,页没有映射)或者它不是一个脏块,那么 `flush_block` 将什么都不做。我们将使用虚拟内存硬件去跟踪,磁盘块自最后一次从磁盘读取或写入到磁盘之后是否被修改过。查看一个块是否需要写入时,我们只需要去查看 `uvpt` 条目中的 `PTE_D` 的 ”dirty“ 位即可。(`PTE_D` 位由处理器设置,用于表示那个页被写入;具体细节可以查看 x386 参考手册的 [第 5 章][3] 的 5.2.4.3 节)块被写入到磁盘上之后,`flush_block` 函数将使用 `sys_page_map` 去清除 `PTE_D` 位。
+>(如果需要的话)函数 `flush_block` 应该会将一个块写入到磁盘上。如果在块缓存中没有块(也就是说,页没有映射)或者它不是一个脏块,那么 `flush_block` 将什么都不做。我们将使用虚拟内存硬件去跟踪,磁盘块自最后一次从磁盘读取或写入到磁盘之后是否被修改过。查看一个块是否需要写入时,我们只需要去查看 `uvpt` 条目中的 `PTE_D` 的 ”dirty“ 位即可。(`PTE_D` 位由处理器设置,用于表示那个页被写入;具体细节可以查看 x386 参考手册的 [第 5 章][3] 的 5.2.4.3 节)块被写入到磁盘上之后,`flush_block` 函数将使用 `sys_page_map` 去清除 `PTE_D` 位。
-使用 `make grade` 去测试你的代码。你的代码应该能够通过 "check_bc"、"check_super"、和 "check_bitmap" 的测试。
-```
+> 使用 `make grade` 去测试你的代码。你的代码应该能够通过 "check_bc"、"check_super"、和 "check_bitmap" 的测试。
在 `fs/fs.c` 中的函数 `fs_init` 是块缓存使用的一个很好的示例。在初始化块缓存之后,它简单地在全局变量 `super` 中保存指针到磁盘映射区。在这之后,如果块在内存中,或我们的页故障服务程序按需将它们从磁盘上读入后,我们就能够简单地从 `super` 结构中读取块了。
-```markdown
-小挑战!到现在为止,块缓存还没有清除策略。一旦某个块因为页故障被读入到缓存中之后,它将一直不会被清除,并且永远保留在内存中。给块缓存增加一个清除策略。在页表中使用 `PTE_A` 的 "accessed" 位来实现,任何环境访问一个页时,硬件就会设置这个位,你可以通过它来跟踪磁盘块的大致使用情况,而不需要修改访问磁盘映射区域的任何代码。使用脏块要小心。
-```
+.
+
+> **小挑战!**到现在为止,块缓存还没有清除策略。一旦某个块因为页故障被读入到缓存中之后,它将一直不会被清除,并且永远保留在内存中。给块缓存增加一个清除策略。在页表中使用 `PTE_A` 的 "accessed" 位来实现,任何环境访问一个页时,硬件就会设置这个位,你可以通过它来跟踪磁盘块的大致使用情况,而不需要修改访问磁盘映射区域的任何代码。使用脏块要小心。
### 块位图
在 `fs_init` 设置了 `bitmap` 指针之后,我们可以认为 `bitmap` 是一个装满比特位的数组,磁盘上的每个块就是数组中的其中一个比特位。比如 `block_is_free`,它只是简单地在位图中检查给定的块是否被标记为空闲。
-```markdown
-练习 3、使用 `free_block` 作为实现 `fs/fs.c` 中的 `alloc_block` 的一个模型,它将在位图中去查找一个空闲的磁盘块,并将它标记为已使用,然后返回块编号。当你分配一个块时,你应该立即使用 `flush_block` 将已改变的位图块刷新到磁盘上,以确保文件系统的一致性。
+> **练习 3**、使用 `free_block` 作为实现 `fs/fs.c` 中的 `alloc_block` 的一个模型,它将在位图中去查找一个空闲的磁盘块,并将它标记为已使用,然后返回块编号。当你分配一个块时,你应该立即使用 `flush_block` 将已改变的位图块刷新到磁盘上,以确保文件系统的一致性。
-使用 `make grade` 去测试你的代码。现在,你的代码应该要通过 "alloc_block" 的测试。
-```
+> 使用 `make grade` 去测试你的代码。现在,你的代码应该要通过 "alloc_block" 的测试。
### 文件操作
在 `fs/fs.c` 中,我们提供一系列的函数去实现基本的功能,比如,你将需要去理解和管理结构 `File`、扫描和管理目录”文件“的条目、 以及从根目录开始遍历文件系统以解析一个绝对路径名。阅读 `fs/fs.c` 中的所有代码,并在你开始实验之前,确保你理解了每个函数的功能。
-```markdown
-练习 4、实现 `file_block_walk` 和 `file_get_block`。`file_block_walk` 从一个文件中的块偏移量映射到 `struct File` 中那个块的指针上或间接块上,它非常类似于 `pgdir_walk` 在页表上所做的事。`file_get_block` 将更进一步,将去映射一个真实的磁盘块,如果需要的话,去分配一个新的磁盘块。
+> **练习 4**、实现 `file_block_walk` 和 `file_get_block`。`file_block_walk` 从一个文件中的块偏移量映射到 `struct File` 中那个块的指针上或间接块上,它非常类似于 `pgdir_walk` 在页表上所做的事。`file_get_block` 将更进一步,将去映射一个真实的磁盘块,如果需要的话,去分配一个新的磁盘块。
-使用 `make grade` 去测试你的代码。你的代码应该要通过 "file_open"、"file_get_block"、以及 "file_flush/file_truncated/file rewrite"、和 "testfile" 的测试。
-```
+> 使用 `make grade` 去测试你的代码。你的代码应该要通过 "file_open"、"file_get_block"、以及 "file_flush/file_truncated/file rewrite"、和 "testfile" 的测试。
`file_block_walk` 和 `file_get_block` 是文件系统中的”劳动模范“。比如,`file_read` 和 `file_write` 或多或少都在 `file_get_block` 上做必需的登记工作,然后在分散的块和连续的缓存之间复制字节。
-```
-小挑战!如果操作在中途实然被打断(比如,突然崩溃或重启),文件系统很可能会产生错误。实现软件更新或日志处理的方式让文件系统的”崩溃可靠性“更好,并且演示一下旧的文件系统可能会崩溃,而你的更新后的文件系统不会崩溃的情况。
-```
+.
+
+> **小挑战!**如果操作在中途实然被打断(比如,突然崩溃或重启),文件系统很可能会产生错误。实现软件更新或日志处理的方式让文件系统的”崩溃可靠性“更好,并且演示一下旧的文件系统可能会崩溃,而你的更新后的文件系统不会崩溃的情况。
### 文件系统接口
@@ -207,19 +197,17 @@ x86 处理器在 EFLAGS 寄存器中使用 IOPL 位去确定保护模式中的
服务器也通过 IPC 来发送响应。我们为函数的返回代码使用 32 位的数字。对于大多数 RPC,这已经涵盖了它们全部的返回代码。`FSREQ_READ` 和 `FSREQ_STAT` 也返回数据,它们只是被简单地写入到客户端发送它的请求时的页上。在 IPC 的响应中并不需要去发送这个页,因为这个页是文件系统服务器和客户端从一开始就共享的页。另外,在它的响应中,`FSREQ_OPEN` 与客户端共享一个新的 "Fd page”。我们将快捷地返回到文件描述符页上。
-```markdown
-练习 5、实现 `fs/serv.c` 中的 `serve_read`。
+> **练习 5**、实现 `fs/serv.c` 中的 `serve_read`。
-`serve_read` 的重任将由已经在 `fs/fs.c` 中实现的 `file_read` 来承担(它实际上不过是对 `file_get_block` 的一连串调用)。对于文件读取,`serve_read` 只能提供 RPC 接口。查看 `serve_set_size` 中的注释和代码,去大体上了解服务器函数的结构。
+> `serve_read` 的重任将由已经在 `fs/fs.c` 中实现的 `file_read` 来承担(它实际上不过是对 `file_get_block` 的一连串调用)。对于文件读取,`serve_read` 只能提供 RPC 接口。查看 `serve_set_size` 中的注释和代码,去大体上了解服务器函数的结构。
-使用 `make grade` 去测试你的代码。你的代码通过 "serve_open/file_stat/file_close" 和 "file_read" 的测试后,你得分应该是 70(总分为 150)。
-```
+> 使用 `make grade` 去测试你的代码。你的代码通过 "serve_open/file_stat/file_close" 和 "file_read" 的测试后,你得分应该是 70(总分为 150)。
-```markdown
-练习 6、实现 `fs/serv.c` 中的 `serve_write` 和 `lib/file.c` 中的 `devfile_write`。
+.
-使用 `make grade` 去测试你的代码。你的代码通过 "file_write"、"file_read after file_write"、"open"、和 "large file" 的测试后,得分应该是 90(总分为150)。
-```
+> **练习 6**、实现 `fs/serv.c` 中的 `serve_write` 和 `lib/file.c` 中的 `devfile_write`。
+
+> 使用 `make grade` 去测试你的代码。你的代码通过 "file_write"、"file_read after file_write"、"open"、和 "large file" 的测试后,得分应该是 90(总分为150)。
### 进程增殖
@@ -227,21 +215,19 @@ x86 处理器在 EFLAGS 寄存器中使用 IOPL 位去确定保护模式中的
我们实现的是 `spawn`,而不是一个类 UNIX 的 `exec`,因为 `spawn` 是很容易从用户空间中、以”外内核式“ 实现的,它无需来自内核的特别帮助。为了在用户空间中实现 `exec`,想一想你应该做什么?确保你理解了它为什么很难。
-```markdown
-练习 7、`spawn` 依赖新的系统调用 `sys_env_set_trapframe` 去初始化新创建的环境的状态。实现 `kern/syscall.c` 中的 `sys_env_set_trapframe`。(不要忘记在 `syscall()` 中派发新系统调用)
+> **练习 7**、`spawn` 依赖新的系统调用 `sys_env_set_trapframe` 去初始化新创建的环境的状态。实现 `kern/syscall.c` 中的 `sys_env_set_trapframe`。(不要忘记在 `syscall()` 中派发新系统调用)
-运行来自 `kern/init.c` 中的 `user/spawnhello` 程序来测试你的代码`kern/init.c` ,它将尝试从文件系统中增殖 `/hello`。
+> 运行来自 `kern/init.c` 中的 `user/spawnhello` 程序来测试你的代码`kern/init.c` ,它将尝试从文件系统中增殖 `/hello`。
-使用 `make grade` 去测试你的代码。
-```
+> 使用 `make grade` 去测试你的代码。
-```markdown
-小挑战!实现 Unix 式的 `exec`。
-```
+.
-```markdown
-小挑战!实现 `mmap` 式的文件内存映射,并如果可能的话,修改 `spawn` 从 ELF 中直接映射页。
-```
+> **小挑战!**实现 Unix 式的 `exec`。
+
+.
+
+> **小挑战!**实现 `mmap` 式的文件内存映射,并如果可能的话,修改 `spawn` 从 ELF 中直接映射页。
### 跨 fork 和 spawn 共享库状态
@@ -255,11 +241,9 @@ UNIX 文件描述符是一个通称的概念,它还包括管道、控制台 I/
我们在 `inc/lib.h` 中定义了一个新的 `PTE_SHARE` 位,在 Intel 和 AMD 的手册中,这个位是被标记为”软件可使用的“的三个 PTE 位之一。我们将创建一个约定,如果一个页表条目中这个位被设置,那么在 `fork` 和 `spawn` 中应该直接从父环境中复制 PTE 到子环境中。注意它与标记为写时复制的差别:正如在第一段中所描述的,我们希望确保能共享页更新。
-```markdown
-练习 8、修改 `lib/fork.c` 中的 `duppage`,以遵循最新约定。如果页表条目设置了 `PTE_SHARE` 位,仅直接复制映射。(你应该去使用 `PTE_SYSCALL`,而不是 `0xfff`,去从页表条目中掩掉有关的位。`0xfff` 仅选出可访问的位和脏位。)
+> **练习 8**、修改 `lib/fork.c` 中的 `duppage`,以遵循最新约定。如果页表条目设置了 `PTE_SHARE` 位,仅直接复制映射。(你应该去使用 `PTE_SYSCALL`,而不是 `0xfff`,去从页表条目中掩掉有关的位。`0xfff` 仅选出可访问的位和脏位。)
-同样的,在 `lib/spawn.c` 中实现 `copy_shared_pages`。它应该循环遍历当前进程中所有的页表条目(就像 `fork` 那样),复制任何设置了 `PTE_SHARE` 位的页映射到子进程中。
-```
+> 同样的,在 `lib/spawn.c` 中实现 `copy_shared_pages`。它应该循环遍历当前进程中所有的页表条目(就像 `fork` 那样),复制任何设置了 `PTE_SHARE` 位的页映射到子进程中。
使用 `make run-testpteshare` 去检查你的代码行为是否正确。正确的情况下,你应该会看到像 "`fork handles PTE_SHARE right`" 和 "`spawn handles PTE_SHARE right`” 这样的输出行。
@@ -269,9 +253,7 @@ UNIX 文件描述符是一个通称的概念,它还包括管道、控制台 I/
为了能让 shell 工作,我们需要一些方式去输入。QEMU 可以显示输出,我们将它的输出写入到 CGA 显示器上和串行端口上,但到目前为止,我们仅能够在内核监视器中接收输入。在 QEMU 中,我们从图形化窗口中的输入作为从键盘到 JOS 的输入,虽然键入到控制台的输入作为出现在串行端口上的字符的方式显现。在 `kern/console.c` 中已经包含了由我们自实验 1 以来的内核监视器所使用的键盘和串行端口的驱动程序,但现在你需要去把这些增加到系统中。
-```markdown
-练习 9、在你的 `kern/trap.c` 中,调用 `kbd_intr` 去处理捕获 `IRQ_OFFSET+IRQ_KBD` 和 `serial_intr`,用它们去处理捕获 `IRQ_OFFSET+IRQ_SERIAL`。
-```
+> **练习 9**、在你的 `kern/trap.c` 中,调用 `kbd_intr` 去处理捕获 `IRQ_OFFSET+IRQ_KBD` 和 `serial_intr`,用它们去处理捕获 `IRQ_OFFSET+IRQ_SERIAL`。
在 `lib/console.c` 中,我们为你实现了文件的控制台输入/输出。`kbd_intr` 和 `serial_intr` 将使用从最新读取到的输入来填充缓冲区,而控制台文件类型去排空缓冲区(默认情况下,控制台文件类型为 stdin/stdout,除非用户重定向它们)。
@@ -282,40 +264,38 @@ UNIX 文件描述符是一个通称的概念,它还包括管道、控制台 I/
运行 `make run-icode` 或 `make run-icode-nox` 将运行你的内核并启动 `user/icode`。`icode` 又运行 `init`,它将设置控制台作为文件描述符 0 和 1(即:标准输入 stdin 和标准输出 stdout),然后增殖出环境 `sh`,就是 shell。之后你应该能够运行如下的命令了:
```
- echo hello world | cat
- cat lorem |cat
- cat lorem |num
- cat lorem |num |num |num |num |num
- lsfd
+echo hello world | cat
+cat lorem |cat
+cat lorem |num
+cat lorem |num |num |num |num |num
+lsfd
```
注意用户库常规程序 `cprintf` 将直接输出到控制台,而不会使用文件描述符代码。这对调试非常有用,但是对管道连接其它程序却很不利。为将输出打印到特定的文件描述符(比如 1,它是标准输出 stdout),需要使用 `fprintf(1, "...", ...)`。`printf("...", ...)` 是将输出打印到文件描述符 1(标准输出 stdout) 的快捷方式。查看 `user/lsfd.c` 了解更多示例。
-```markdown
-练习 10、
-这个 shell 不支持 I/O 重定向。如果能够运行 `run sh