diff --git a/published/201703/20170223 How to install Arch Linux on VirtualBox.md b/published/201703/20170223 How to install Arch Linux on VirtualBox.md
index 58a094b048..cdd68a0642 100644
--- a/published/201703/20170223 How to install Arch Linux on VirtualBox.md
+++ b/published/201703/20170223 How to install Arch Linux on VirtualBox.md
@@ -104,10 +104,10 @@ Arch Linux 也因其丰富的 Wiki 帮助文档而大受推崇。该系统基于
][23]
输入下面的命令来检查网络连接。
-
+
```
ping google.com
-```
+```
这个单词 ping 表示网路封包搜寻。你将会看到下面的返回信息,表明 Arch Linux 已经连接到外网了。这是执行安装过程中的很关键的一点。(LCTT 译注:或许你 ping 不到那个不存在的网站,你选个存在的吧。)
@@ -117,8 +117,8 @@ ping google.com
输入如下命令清屏:
-```
-clear
+```
+clear
```
在开始安装之前,你得先为硬盘分区。输入 `fdisk -l` ,你将会看到当前系统的磁盘分区情况。注意一开始你给 Arch Linux 系统分配的 20 GB 存储空间。
@@ -137,8 +137,8 @@ clear
输入下面的命令:
-```
-cfdisk
+```
+cfdisk
```
你将看到 `gpt`、`dos`、`sgi` 和 `sun` 类型,选择 `dos` 选项,然后按回车。
@@ -185,8 +185,8 @@ cfdisk
以同样的方式创建逻辑分区。在“退出(quit)”选项按回车键,然后输入下面的命令来清屏:
-```
-clear
+```
+clear
```
[
@@ -195,21 +195,21 @@ clear
输入下面的命令来格式化新建的分区:
-```
+```
mkfs.ext4 /dev/sda1
-```
+```
这里的 `sda1` 是分区名。使用同样的命令来格式化第二个分区 `sda3` :
-```
+```
mkfs.ext4 /dev/sda3
-```
+```
格式化 swap 分区:
-```
+```
mkswap /dev/sda2
-```
+```
[
![Format the swap partition with mkswap](https://www.howtoforge.com/images/install_arch_linux_on_virtual_box/121224.png)
@@ -217,14 +217,14 @@ mkswap /dev/sda2
使用下面的命令来激活 swap 分区:
-```
-swapon /dev/sda2
+```
+swapon /dev/sda2
```
输入 clear 命令清屏:
-```
-clear
+```
+clear
```
[
@@ -233,9 +233,9 @@ clear
输入下面的命令来挂载主分区以开始系统安装:
-```
-mount /dev/sda1 / mnt
-```
+```
+mount /dev/sda1 /mnt
+```
[
![Mount the partitions](https://www.howtoforge.com/images/install_arch_linux_on_virtual_box/121226.png)
@@ -245,9 +245,9 @@ mount /dev/sda1 / mnt
输入下面的命令来引导系统启动:
-```
+```
pacstrap /mnt base base-devel
-```
+```
可以看到系统正在同步数据包。
@@ -263,9 +263,9 @@ pacstrap /mnt base base-devel
系统基本软件安装完成后,输入下面的命令来创建 fstab 文件:
-```
+```
genfstab /mnt>> /mnt/etc/fstab
-```
+```
[
![Generating /etc/fstab](https://www.howtoforge.com/images/install_arch_linux_on_virtual_box/121229.png)
@@ -275,14 +275,14 @@ genfstab /mnt>> /mnt/etc/fstab
输入下面的命令来更改系统的根目录为 Arch Linux 的安装目录:
-```
+```
arch-chroot /mnt /bin/bash
-```
+```
现在来更改语言配置:
-```
-nano /etc/local.gen
+```
+nano /etc/locale.gen
```
[
@@ -297,9 +297,9 @@ nano /etc/local.gen
输入下面的命令来激活它:
-```
+```
locale-gen
-```
+```
按回车。
@@ -309,8 +309,8 @@ locale-gen
使用下面的命令来创建 `/etc/locale.conf` 配置文件:
-```
-nano /etc/locale.conf
+```
+nano /etc/locale.conf
```
然后按回车。现在你就可以在配置文件中输入下面一行内容来为系统添加语言:
@@ -326,9 +326,9 @@ LANG=en_US.UTF-8
][44]
输入下面的命令来同步时区:
-
+
```
-ls user/share/zoneinfo
+ls /usr/share/zoneinfo
```
下面你将看到整个世界的时区列表。
@@ -339,9 +339,9 @@ ls user/share/zoneinfo
输入下面的命令来选择你所在的时区:
-```
+```
ln –s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
-```
+```
或者你可以从下面的列表中选择其它名称。
@@ -351,8 +351,8 @@ ln –s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
使用下面的命令来设置标准时间:
-```
-hwclock --systohc –utc
+```
+hwclock --systohc --utc
```
硬件时钟已同步。
@@ -363,8 +363,8 @@ hwclock --systohc –utc
设置 root 帐号密码:
-```
-passwd
+```
+passwd
```
按回车。 然而输入你想设置的密码,按回车确认。
@@ -377,9 +377,9 @@ passwd
使用下面的命令来设置主机名:
-```
+```
nano /etc/hostname
-```
+```
然后按回车。输入你想设置的主机名称,按 `control + x` ,按 `y` ,再按回车 。
@@ -389,9 +389,9 @@ nano /etc/hostname
启用 dhcpcd :
-```
+```
systemctl enable dhcpcd
-```
+```
这样在下一次系统启动时, dhcpcd 将会自动启动,并自动获取一个 IP 地址:
@@ -403,9 +403,9 @@ systemctl enable dhcpcd
最后一步,输入以下命令来初始化 grub 安装。输入以下命令:
-```
+```
pacman –S grub os-rober
-```
+```
然后按 `y` ,将会下载相关程序。
@@ -415,14 +415,14 @@ pacman –S grub os-rober
使用下面的命令来将启动加载程序安装到硬盘上:
-```
+```
grub-install /dev/sda
-```
+```
然后进行配置:
-```
-grub-mkconfig -o /boot/grub/grub.cfg
+```
+grub-mkconfig -o /boot/grub/grub.cfg
```
[
@@ -431,9 +431,9 @@ grub-mkconfig -o /boot/grub/grub.cfg
最后重启系统:
-```
+```
reboot
-```
+```
然后按回车 。
@@ -459,7 +459,7 @@ reboot
via: https://www.howtoforge.com/tutorial/install-arch-linux-on-virtualbox/
-译者简介:
+译者简介:
rusking:春城初春/春水初生/春林初盛/春風十裏不如妳
diff --git a/published/20180628 Blockchain evolution- A quick guide and why open source is at the heart of it.md b/published/20180628 Blockchain evolution- A quick guide and why open source is at the heart of it.md
new file mode 100644
index 0000000000..a91a1d4cda
--- /dev/null
+++ b/published/20180628 Blockchain evolution- A quick guide and why open source is at the heart of it.md
@@ -0,0 +1,100 @@
+区块链进化简史:为什么开源是其核心所在
+======
+
+> 从比特币到下一代区块链。
+
+![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/block-quilt-chain.png?itok=mECoDbrc)
+
+当开源项目开发下一个新版本时,用后缀 “-ng” 表示 “下一代”的情况并不鲜见。幸运的是,到目前为止,快速演进的区块链成功地避开了这个命名陷阱。但是在这个开源生态系统的演进过程中,改变是不断发生的,而好的创意以典型的开源方式在许多不同的项目中被采用、交融和演进。
+
+在本文中,我将审视不同代次的区块链,并且看一看在处理这个生态系统遇到的问题时出现什么创意。当然,任何对生态系统进行分类的尝试都有其局限性的 —— 和不同意见者的 —— 但是这也将为混乱的区块链项目提供了一个粗略的指南。
+
+### 始作俑者:比特币
+
+第一代的区块链起源于 [比特币][1] 区块链,这是以去中心化、点对点加密货币为基础的总帐,它从 [Slashdot][2] 网站上的杂谈变成了一个主流话题。
+
+这个区块链是一个分布式总帐,它对所有用户的交易保持跟踪,以避免他们双重支付(双花)货币(在历史上,这个任务是委托给第三方—— 银行 ——来做的)。为防范攻击者在系统上捣乱,总帐被复制到每个参与到比特币网络的计算机上,并且每次只允许一台计算机去更新总帐。为决定哪台计算机能够获得更新总帐的权力,系统安排在比特币网络上的计算机之间每 10 分钟进行一场竞赛,这将消耗它们的(许多)能源才能参与竞赛。赢家将获得将前 10 分钟发生的交易写入到总帐(区块链中的“区块”)的权力,并且为赢家写入区块链的工作给予一些比特币奖励。这种方式被称为工作量证明(PoW)共识机制。
+
+这就是区块链最有趣的地方。比特币以[开源项目][3]的方式发布于 2009 年 1 月 。在 2010 年,由于意识到这些元素中的许多是可以调整的,围绕比特币聚集起了一个社区 —— [bitcointalk 论坛][4],来开始各种实验。
+
+起初,看到的比特币区块链是一个分布式数据库的形式, [Namecoin][5] 项目出现后,建议去保存任意数据到它的事务数据库中。如果区块链能够记录金钱的转移,那么它也应该能够记录其它资产的转移,比如域名。这正是 Namecoin 的主要使用场景,它上线于 2011 年 4 月 —— 也就是比特币出现两年后。
+
+Namecoin 调整的地方是区块链的内容,[莱特币][6] 调整的是两个技术部分:一是将两个区块的时间间隔从 10 分钟减少到 2.5 分钟,二是改变了竞赛方式(用 [scrypt][7] 来替换了 SHA-256 安全哈希算法)。这是能够做到的,因为比特币是以开源软件的方式来发布的,而莱特币本质上与比特币在其它部分是完全相同的。莱特币是修改了比特币共识机制的第一个分叉,这也为其它的更多“币”铺平了道路。
+
+沿着这条道路,基于比特币代码库的各种变种越来越多。其中一些扩展了比特币的用途,比如 [Zerocash][8] 协议,它专注于提供交易的匿名性和可替换性,但它最终分拆为它自己的货币 —— [Zcash][9]。
+
+虽然 Zcash 带来了它自己的创新,使用了最近被称为“零知识证明”的加密技术,但它维持着与大多数主要的比特币代码库的兼容性,这意味着它能够从上游的比特币创新中获益。
+
+另外的项目 —— [CryptoNote][10],它萌芽于相同的社区,但是并没有使用相同的代码,它以比特币为背景来构建的,但又与之不同。它发布于 2012 年 12 月,由于它的出现,导致了几种加密货币的诞生,最著名的 [门罗币][11] (2014)就是其中之一。门罗币与 Zcash 使用了不同的方法,但解决了相同的问题:隐私性和可替换性。
+
+就像在开源世界中经常出现的案例一样,做同样的工作有不止一个的工具可用。
+
+### 下一代:“Blockchain-ng”
+
+但是,到目前为止,所有的这些变体只是改进加密货币或者扩展它们去支持其它类型的事务。因此,这就引出了第二代区块链。
+
+一旦社区开始去修改区块链的用法和调整技术部分时,对于一些想去扩展和重新思考它们未来的人来说,这种调整花费不了多长时间的。比特币的长期追随者 —— [Vitalik Buterin][12] 在 2013 年底建议,区域链的事务应该能够表示一个状态机的状态变化,将区域链视为能够运行应用程序(“智能合约”)的分布式计算机。这个项目 —— [以太坊][13],上线于 2015 年 4 月。它在运行分布式应用程序方面取得了巨大的成功,它的一些非常流行的分布式应用程序([加密猫][14])甚至导致以太坊区块链变慢。
+
+这证明了目前的区块链存在一个很大的局限性:速度和容量。(速度通常用每秒事务数来测量,简称 TPS)有几个提议都建议去解决这个速度问题,从分片到侧链,以及一个被称为“第二层”的解决方案。这里需要更多的创新。
+
+随着“智能合约”这个词开始流行起来,并且用已经被证实仍然很慢的技术去运行它们,那么就需要实现其它的思路:许可区块链。到目前为止,我们所介绍的所有区块链网络有两个没有明说的特征:一是它们是公开的(任何人都可以看到它们的功能),二是它们不需要许可(任何人都可以加入它们)。这两个部分是运行一个分布式的、非基于第三方的货币应该具有的和必需具有的条件。
+
+随着区块链被认为出现与加密货币越来越明显的分离趋势,开始去考虑一些隐私、许可场景是很有意义的。一个有业务关系但不需要彼此完全信任的财团类型的参与者,能够从这些区块链类型中获益 —— 比如,物流链上的参与者,定期进行双边结算或者使用一个清算中心的金融、保险、或医疗保健机构。
+
+一旦你将设置从“任何人都可以加入”变为“仅邀请者方可加入”,进一步对区块链构建区块的方式进行改变和调整将变得可能,那么对一些人来说,结果将变得非常有趣。
+
+首先,设计用来保护网络不受恶意或者垃圾参与者的影响的工作量证明(PoW)可以被替换为更简单的和更少资源消耗的一些东西,比如,基于 [Raft][15] 的共识协议。在更高级别的安全性和更快的速度之间进行权衡,采用更简单的共识算法。对于更多群体来说这样更理想,因为他们可以用基于加密技术的担保来取代其它的基于法律关系的担保,例如为避免由于竞争而产生的大量能源消耗,而工作量证明就是这种情况。另外一个创新的地方是,使用 [股权证明][16](PoS),它是公共网络共识机制的一个重量级的竞争者。它将可能像许可链网络一样找到它自己的实现方式。
+
+有几个项目可以让创建许可区块链变得更简单,包括 [Quorum][17] (以太坊的一个分叉)和 [Hyperledger][18] 的 [Fabric][19] 和 [Sawtooth][20],这是基于新代码的两个开源项目。
+
+许可区块链可以避免公共的、非许可方式的区块链中某些错综复杂的问题,但是它自己也存在一些问题。正确地管理参与者是其中的一个问题:谁可以加入?如何辨别他们?如何将他们从网络上移除?网络上的一个实体是否去管理一个中央公共密钥基础设施(PKI)?
+
+### 区块链的开放本质
+
+到目前为止的所有案例中,有一件事情是很明确的:使用一个区块链的目标是去提升网络中的参与者和它产生的数据的信任水平,理想情况下,不需要做进一步的工作即可足以使用它。
+
+只有为这个网络提供动力的软件是自由和开源的,才能达到这种信任水平。即便是一个正确的、专用的、分布式区块链,它的本质仍然是运行着相同的第三方代码的私有代理的集合。从本质上来说,区块链的源代码必须是开源的,但仅是开源还不够。随着生态系统持续成长,这既是最低限度的担保也是进一步创新的源头。
+
+最后,值得一提的是,虽然区块链的开放本质被认为是创新和变化的源头,它也被认为是一种治理形式:代码治理,用户期望运行的任何一个特定版本,都应该包含他们认为的整个网络应该包含的功能和方法。在这方面,需要说明的一点是,一些区块链的开放本质正在“变味”。但是这一问题正在解决。
+
+### 第三和第四代:治理
+
+接下来,我正在考虑第三代和第四代区块链:区块链将内置治理工具,并且项目将去解决棘手的大量不同区块链之间互连互通的问题,以便于它们之间可以交换信息和价值。
+
+---
+关于作者
+
+axel simon: 长期的自由及开源软件爱好者,就职于 Red Hat ,关注安全和区块链技术,以及分布式系统和协议。致力于保护互联网及其成就(知识分享、信息访问、去中心化和网络中立)。
+
+--------------------------------------------------------------------------------
+
+via: https://opensource.com/article/18/6/blockchain-guide-next-generation
+
+作者:[Axel Simon][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://opensource.com/users/axel
+[1]:https://bitcoin.org
+[2]:https://slashdot.org/
+[3]:https://github.com/bitcoin/bitcoin
+[4]:https://bitcointalk.org/
+[5]:https://www.namecoin.org/
+[6]:https://litecoin.org/
+[7]:https://en.wikipedia.org/wiki/Scrypt
+[8]:http://zerocash-project.org/index
+[9]:https://z.cash
+[10]:https://cryptonote.org/
+[11]:https://en.wikipedia.org/wiki/Monero_(cryptocurrency)
+[12]:https://en.wikipedia.org/wiki/Vitalik_Buterin
+[13]:https://ethereum.org
+[14]:http://cryptokitties.co/
+[15]:https://en.wikipedia.org/wiki/Raft_(computer_science)
+[16]:https://www.investopedia.com/terms/p/proof-stake-pos.asp
+[17]:https://www.jpmorgan.com/global/Quorum
+[18]:https://hyperledger.org/
+[19]:https://www.hyperledger.org/projects/fabric
+[20]:https://www.hyperledger.org/projects/sawtooth
diff --git a/published/20180704 Install an NVIDIA GPU on almost any machine.md b/published/20180704 Install an NVIDIA GPU on almost any machine.md
new file mode 100644
index 0000000000..4731d0ae8f
--- /dev/null
+++ b/published/20180704 Install an NVIDIA GPU on almost any machine.md
@@ -0,0 +1,147 @@
+如何在绝大部分类型的机器上安装 NVIDIA 显卡驱动
+======
+
+![](https://fedoramagazine.org/wp-content/uploads/2018/06/nvidia-816x345.jpg)
+
+无论是研究还是娱乐,安装一个最新的显卡驱动都能提升你的计算机性能,并且使你能全方位地实现新功能。本安装指南使用 Fedora 28 的新的第三方仓库来安装 NVIDIA 驱动。它将引导您完成硬件和软件两方面的安装,并且涵盖需要让你的 NVIDIA 显卡启动和运行起来的一切知识。这个流程适用于任何支持 UEFI 的计算机和任意新的 NVIDIA 显卡。
+
+### 准备
+
+本指南依赖于下面这些材料:
+
+ * 一台使用 [UEFI][1] 的计算机,如果你不确定你的电脑是否有这种固件,请运行 `sudo dmidecode -t 0`。如果输出中出现了 “UEFI is supported”,你的安装过程就可以继续了。不然的话,虽然可以在技术上更新某些电脑来支持 UEFI,但是这个过程的要求很苛刻,我们通常不建议你这么使用。
+ * 一个现代的、支持 UEFI 的 NVIDIA 的显卡
+ * 一个满足你的 NVIDIA 显卡的功率和接线要求的电源(有关详细信息,请参考“硬件和修改”的章节)
+ * 网络连接
+ * Fedora 28 系统
+
+### 安装实例
+
+这个安装示例使用的是:
+
+ * 一台 Optiplex 9010 的主机(一台相当老的机器)
+ * [NVIDIA GeForce GTX 1050 Ti XLR8 游戏超频版 4 GB GDDR5 PCI Express 3.0 显卡][2]
+ * 为了满足新显卡的电源要求,电源升级为 [EVGA – 80 PLUS 600 W ATX 12V/EPS 12V][3],这个最新的电源(PSU)比推荐的最低要求高了 300 W,但在大部分情况下,满足推荐的最低要求就足够了。
+ * 然后,当然的,Fedora 28 也别忘了.
+
+### 硬件和修改
+
+#### 电源(PSU)
+
+打开你的台式机的机箱,检查印刷在电源上的最大输出功率。然后,查看你的 NVIDIA 显卡的文档,确定推荐的最小电源功率要求(以瓦特为单位)。除此之外,检查你的显卡,看它是否需要额外的接线,例如 6 针连接器,大多数的入门级显卡只从主板获取电力,但是有一些显卡需要额外的电力,如果出现以下情况,你需要升级你的电源:
+
+ 1. 你的电源的最大输出功率低于显卡建议的最小电源功率。注意:根据一些显卡厂家的说法,比起推荐的功率,预先构建的系统可能会需要更多或更少的功率,而这取决于系统的配置。如果你使用的是一个特别耗电或者特别节能的配置,请灵活决定你的电源需求。
+ 2. 你的电源没有提供必须的接线口来为你的显卡供电。
+
+电源的更换很容易,但是在你拆除你当前正在使用的电源之前,请务必注意你的接线布局。除此之外,请确保你选择的电源适合你的机箱。
+
+#### CPU
+
+虽然在大多数老机器上安装高性能的 NVIDIA 显卡是可能的,但是一个缓慢或受损的 CPU 会阻碍显卡性能的发挥,如果要计算在你的机器上瓶颈效果的影响,请点击[这里][4]。了解你的 CPU 性能来避免高性能的显卡和 CPU 无法保持匹配是很重要的。升级你的 CPU 是一个潜在的考虑因素。
+
+#### 主板
+
+在继续进行之前,请确认你的主板和你选择的显卡是兼容的。你的显卡应该插在最靠近散热器的 PCI-E x16 插槽中。确保你的设置为显卡预留了足够的空间。此外,请注意,现在大部分的显卡使用的都是 PCI-E 3.0 技术。虽然这些显卡如果插在 PCI-E 3.0 插槽上会运行地最好,但如果插在一个旧版的插槽上的话,性能也不会受到太大的影响。
+
+### 安装
+
+1、 首先,打开终端更新你的包管理器(如果没有更新的话):
+
+```
+sudo dnf update
+```
+
+2、 然后,使用这条简单的命令进行重启:
+
+```
+reboot
+```
+
+3、 在重启之后,安装 Fedora 28 的工作站的仓库:
+
+```
+sudo dnf install fedora-workstation-repositories
+```
+
+4、 接着,设置 NVIDIA 驱动的仓库:
+
+```
+sudo dnf config-manager --set-enabled rpmfusion-nonfree-nvidia-driver
+```
+
+5、 然后,再次重启。
+
+6、 在这次重启之后,通过下面这条命令验证是否添加了仓库:
+
+```
+sudo dnf repository-packages rpmfusion-nonfree-nvidia-driver info
+```
+
+如果加载了多个 NVIDIA 工具和它们各自的 spec 文件,请继续进行下一步。如果没有,你可能在添加新仓库的时候遇到了一个错误。你应该再试一次。
+
+7、 登录,连接到互联网,然后打开“软件”应用程序。点击“加载项>硬件驱动> NVIDIA Linux 图形驱动>安装”。
+
+如果你使用更老的显卡或者想使用多个显卡,请进一步查看 [RPMFusion 指南][8]。最后,要确保启动成功,设置 `/etc/gdm/custom.conf` 中的 `WaylandEnable=false`,确认避免使用安全启动。
+接着,再一次重启。
+
+8、这个过程完成后,关闭所有的应用并**关机**。拔下电源插头,然后按下电源按钮以释放余电,避免你被电击。如果你对电源有开关,关闭它。
+
+9、 最后,安装显卡,拔掉老的显卡并将新的显卡插入到正确的 PCI-E x16 插槽中。成功安装新的显卡之后,关闭你的机箱,插入电源 ,然后打开计算机,它应该会成功启动。
+
+**注意:** 要禁用此安装中使用的 NVIDIA 驱动仓库,或者要禁用所有的 Fedora 工作站仓库,请参考这个 [Fedora Wiki 页面][6]。
+
+### 验证
+
+1、 如果你新安装的 NVIDIA 显卡已连接到你的显示器并显示正确,则表明你的 NVIDIA 驱动程序已成功和显卡建立连接。
+
+如果你想去查看你的设置,或者验证驱动是否在正常工作(这里,主板上安装了两块显卡),再次打开 “NVIDIA X 服务器设置应用程序”。这次,你应该不会得到错误信息提示,并且系统会给出有关 X 的设置文件和你的 NVIDIA 显卡的信息。(请参考下面的屏幕截图)
+
+![NVIDIA X Server Settings][7]
+
+通过这个应用程序,你可以根据你的需要需改 X 配置文件,并可以监控显卡的性能,时钟速度和温度信息。
+
+2、 为确保新显卡以满功率运行,显卡性能测试是非常必要的。GL Mark 2,是一个提供后台处理、构建、照明、纹理等等有关信息的标准工具。它提供了一个优秀的解决方案。GL Mark 2 记录了各种各样的图形测试的帧速率,然后输出一个总体的性能评分(这被称为 glmark2 分数)。
+
+**注意:** glxgears 只会测试你的屏幕或显示器的性能,不会测试显卡本身,请使用 GL Mark 2。
+
+要运行 GLMark2:
+
+ 1. 打开终端并关闭其他所有的应用程序
+ 2. 运行 `sudo dnf install glmark2` 命令
+ 3. 运行 `glmark2` 命令
+ 4. 允许运行完整的测试来得到最好的结果。检查帧速率是否符合你对这块显卡的预期。如果你想要额外的验证,你可以查阅网站来确认是否已有你这块显卡的 glmark2 测试评分被公布到网上,你可以比较这个分数来评估你这块显卡的性能。
+ 5. 如果你的帧速率或者 glmark2 评分低于预期,请思考潜在的因素。CPU 造成的瓶颈?其他问题导致?
+
+
+如果诊断的结果很好,就开始享受你的新显卡吧。
+
+### 参考链接
+
+- [How to benchmark your GPU on Linux][9]
+- [How to install a graphics card][10]
+- [The Fedora Wiki Page][6]
+- [The Bottlenecker][4]
+- [What Is Unified Extensible Firmware Interface (UEFI)][1]
+
+--------------------------------------------------------------------------------
+
+via: https://fedoramagazine.org/install-nvidia-gpu/
+
+作者:[Justice del Castillo][a]
+选题:[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/) 荣誉推出
+
+[a]:https://fedoramagazine.org/author/justice/
+[1]:https://whatis.techtarget.com/definition/Unified-Extensible-Firmware-Interface-UEFI
+[2]:https://www.cnet.com/products/pny-geforce-gtx-xlr8-gaming-1050-ti-overclocked-edition-graphics-card-gf-gtx-1050-ti-4-gb/specs/
+[3]:https://www.evga.com/products/product.aspx?pn=100-B1-0600-KR
+[4]:http://thebottlenecker.com (Home: The Bottle Necker)
+[5]:https://bytebucket.org/kenneym/fedora-28-nvidia-gpu-installation/raw/7bee7dc6effe191f1f54b0589fa818960a8fa18b/nvidia_xserver_error.jpg?token=c6a7effe35f1c592a155a4a46a068a19fd060a91 (NVIDIA X Sever Prompt)
+[6]:https://fedoraproject.org/wiki/Workstation/Third_Party_Software_Repositories
+[7]:https://bytebucket.org/kenneym/fedora-28-nvidia-gpu-installation/raw/7bee7dc6effe191f1f54b0589fa818960a8fa18b/NVIDIA_XCONFIG.png?token=64e1a7be21e5e9ba157f029b65e24e4eef54d88f (NVIDIA X Server Settings)
+[8]:https://rpmfusion.org/Howto/NVIDIA?highlight=%28CategoryHowto%29
+[9]: https://www.howtoforge.com/tutorial/linux-gpu-benchmark/
+[10]: https://www.pcworld.com/article/2913370/components-graphics/how-to-install-a-graphics-card.html
\ No newline at end of file
diff --git a/sources/tech/20170709 The Extensive Guide to Creating Streams in RxJS.md b/sources/tech/20170709 The Extensive Guide to Creating Streams in RxJS.md
new file mode 100644
index 0000000000..04a25a5cc1
--- /dev/null
+++ b/sources/tech/20170709 The Extensive Guide to Creating Streams in RxJS.md
@@ -0,0 +1,1031 @@
+BriFuture is translating
+
+The Extensive Guide to Creating Streams in RxJS
+============================================================
+
+![](https://cdn-images-1.medium.com/max/900/1*hj8mGnl5tM_lAlx5_vqS-Q.jpeg)
+
+For most developers the first contact with RxJS is established by libraries, like Angular. Some functions return streams and to make use of them the focus naturally is on operators.
+
+At some point mixing reactive and some of the non-reactive code seems practical. Then people get interested in creating streams themselves. Whenever you are dealing with asynchronous code or data processing, chances are that streams are a good option.
+
+RxJS offers numerous ways to create streams. Whatever situation you are facing, there is one perfect way for you to create a stream. You may not need them all, but knowing them can save you time and some code.
+
+I have put all possible options into four categories, based on their main purpose:
+
+* Stream existing data
+
+* Generate data
+
+* Interoperate with existing APIs
+
+* Combine and select from existing streams
+
+Note: The examples use RxJS 6 and can be different from older versions. Something that’s different for sure is the way you import the functions.
+
+RxJS 6
+
+```
+import {of, from} from 'rxjs';
+```
+
+```
+of(...);
+from(...);
+```
+
+RxJS < 6
+
+```
+import { Observable } from 'rxjs/Observable';
+import 'rxjs/add/observable/of';
+import 'rxjs/add/observable/from';
+```
+
+```
+Observable.of(...);
+Observable.from(...);
+```
+
+```
+//or
+```
+
+```
+import { of } from 'rxjs/observable/of';
+import { from } from 'rxjs/observable/from';
+```
+
+```
+of(...);
+from(...);
+```
+
+A note on the stream diagrams:
+
+* | means the stream completes
+
+* X means the stream terminates with an error
+
+* … means the stream goes on indefinitely
+
+* * *
+
+### Stream Existing Data
+
+You have some data and want to feed them into a stream. There are three flavors, all of which also allow you to provide a scheduler as the last argument (If you want to know more about schedulers you can take a look at my [previous article][5]). All resulting streams will be cold.
+
+#### of
+
+Use _of_ if you have only one element or a few separate ones.
+
+```
+of(1,2,3)
+ .subscribe();
+```
+
+```
+// Produces
+// 1 2 3 |
+```
+
+#### from
+
+Use _from_ if you have an array or _Iterable_ and want all elements in it emitted to the stream. You can also use it to convert a promise to an observable.
+
+```
+const foo = [1,2,3];
+```
+
+```
+from(foo)
+ .subscribe();
+```
+
+```
+// Produces
+// 1 2 3 |
+```
+
+#### pairs
+
+Streams key/value pairs of an object. Particularly useful if the object represents a dictionary.
+
+```
+const foo = { a: 1, b: 2};
+```
+
+```
+pairs(foo)
+ .subscribe();
+```
+
+```
+// Produces
+// [a,1] [b,2] |
+```
+
+#### What about other data structures?
+
+Maybe your data is stored in a custom structure that does not implement the _Iterable_ protocol or you have a recursive, tree-like structure. In those cases one of following options might be suitable:
+
+* Extract data to an array first
+
+* Use the _generate_ function from the next section to iterate over the data
+
+* Create a custom stream (see that section)
+
+* Create an iterator
+
+Options 2 and 3 are explained later, so I focus on creating an iterator here. We can create a stream from an _iterable_ by calling _from_ . An _iterable_ is an object that can deliver an iterator (see [this mdn article][6] if you are interested in the details).
+
+One simple way to create an iterator is a [generator function][7]. When you invoke a generator function, it returns an object that conforms to both the _iterable_ protocol and the _iterator_ protocol.
+
+```
+//Our custom data structure
+class List {
+ add(element) ...
+ get(index) ...
+ get size() ...
+ ...
+}
+```
+
+```
+function* listIterator(list) {
+ for (let i = 0; i console.log("foo");
+//prints foo after 5 seconds
+```
+
+Most of the time interval will be used to process data periodically:
+
+```
+interval(10000).pipe(
+ flatMap(i => fetch("https://server/stockTicker")
+).subscribe(updateChart)
+```
+
+This will get new data every 10 seconds and update the screen.
+
+#### generate
+
+A more complex function that allows you to emit a sequence of any type. It has some overloads and I show you the most interesting one(s):
+
+```
+generate(
+ 0, // start with this value
+ x => x < 10, // condition: emit as long as a value is less than 10
+ x => x*2 // iteration: double the previous value
+).subscribe();
+```
+
+```
+// Produces
+// 1 2 4 8 |
+```
+
+You can also use it to iterate over values, if a structure does not implement the _Iterable_ interface. Let’s try that with our list example from before:
+
+```
+const myList = new List();
+myList.add(1);
+myList.add(3);
+```
+
+```
+generate(
+ 0, // start with this value
+ i => i < list.size, // condition: emit until we have processed the whole list
+ i => ++i, // iteration: get next index
+ i => list.get(i) // selection: get value from list
+).subscribe();
+```
+
+```
+// Produces
+// 1 3 |
+```
+
+As you can see I have added another argument: The selector. It works like the _map_ operator and converts the generated value to something more useful.
+
+* * *
+
+### Empty Streams
+
+Sometimes you need to pass or return a stream that does not emit any data. There are three functions, one for every possible situation. You can pass a scheduler to all functions. _empty_ and _throwError_ accept a scheduler as argument.
+
+#### empty
+
+Creates a stream that completes without emitting a value.
+
+```
+empty()
+ .subscribe();
+```
+
+```
+// Produces
+// |
+```
+
+#### never
+
+Creates a stream that never completes, but also never emits anything.
+
+```
+never()
+ .subscribe();
+```
+
+```
+// Produces
+// ...
+```
+
+#### throwError
+
+Creates a stream that fails without emitting a value.
+
+```
+throwError('error')
+ .subscribe();
+```
+
+```
+// Produces
+// X
+```
+
+* * *
+
+### Hook into existing APIs
+
+Not all libraries and all of your legacy code use or support streams. Luckily RxJS provides functions to bridge non-reactive and reactive code. This section discusses only patterns provided by RxJS for exactly that purpose.
+
+You may also be interested in this [extensive article][8] from [Ben Lesh][9] covering probably every possible way to interoperate with promises.
+
+#### from
+
+We already had that and I list it here too because it can be used to wrap a promise into an observable.
+
+```
+from(new Promise(resolve => resolve(1)))
+ .subscribe();
+```
+
+```
+// Produces
+// 1 |
+```
+
+#### fromEvent
+
+Adds an event listener to a DOM element and I am pretty sure you know that. What you may not know is that you can also use it with other types, e.g. a jQuery object.
+
+```
+const element = $('#fooButton'); // creates a jQuery object for a DOM element
+```
+
+```
+from(element, 'click')
+ .subscribe();
+```
+
+```
+// Produces
+// clickEvent ...
+```
+
+#### fromEventPattern
+
+In order to understand why we need this one if we already have fromEvent, we need to understand how fromEvent works. Take this code:
+
+```
+from(document, 'click')
+ .subscribe();
+```
+
+It tells RxJS that we want to listen to click events from the document. During subscription RxJS finds out that document is an _EventTarget_ type, hence it can call _addEventListener_ on it. If we pass a jQuery object instead of document, then RxJS knows that it has to call _on_ instead.
+
+This example using _fromEventPattern_ basically does the same as _fromEvent_ :
+
+```
+function addClickHandler(handler) {
+ document.addEventListener('click', handler);
+}
+```
+
+```
+function removeClickHandler(handler) {
+ document.removeEventListener('click', handler);
+}
+```
+
+```
+fromEventPattern(
+ addClickHandler,
+ removeClickHandler,
+)
+.subscribe(console.log);
+```
+
+```
+//is equivalent to
+fromEvent(document, 'click')
+```
+
+RxJS itself creates the actual listener ( _handler_ ) and your job is to add and remove it. The purpose of _fromEventPattern_ is basically to tell RxJS how to register and remove event listeners.
+
+Now imagine you use a library where you have to call a method named _registerListener_ . We no longer can use _fromEvent_ because it doesn’t know how to deal with it.
+
+```
+const listeners = [];
+```
+
+```
+class Foo {
+ registerListener(listener) {
+ listeners.push(listener);
+ }
+```
+
+```
+ emit(value) {
+ listeners.forEach(listener => listener(value));
+ }
+}
+```
+
+```
+const foo = new Foo();
+```
+
+```
+fromEventPattern(listener => foo.registerListener(listener))
+ .subscribe();
+```
+
+```
+foo.emit(1);
+```
+
+```
+// Produces
+// 1 ...
+```
+
+When we call foo.emit(1) the listener from RxJS is called and it can emit the value to the stream.
+
+You could also use it to listen to more than one event type or connect with any API that communicates via callbacks, e.g. the WebWorker API:
+
+```
+const myWorker = new Worker('worker.js');
+```
+
+```
+fromEventPattern(
+ handler => { myWorker.onmessage = handler },
+ handler => { myWorker.onmessage = undefined }
+)
+.subscribe();
+```
+
+```
+// Produces
+// workerMessage ...
+```
+
+#### bindCallback
+
+This is similar to fromEventPattern, but it’s only meant for single values. That is the stream completes after the callback has been invoked . The usage is different as well – You wrap the function with bindCallback, then it magically returns a stream when it‘s called:
+
+```
+function foo(value, callback) {
+ callback(value);
+}
+```
+
+```
+// without streams
+foo(1, console.log); //prints 1 in the console
+```
+
+```
+// with streams
+const reactiveFoo = bindCallback(foo);
+//when we call reactiveFoo it returns an observable
+```
+
+```
+reactiveFoo(1)
+ .subscribe(console.log); //prints 1 in the console
+```
+
+```
+// Produces
+// 1 |
+```
+
+#### websocket
+
+Yes, you can actually create a websocket connection and expose it as stream:
+
+```
+import { webSocket } from 'rxjs/webSocket';
+```
+
+```
+let socket$ = webSocket('ws://localhost:8081');
+```
+
+```
+//receive messages
+socket$.subscribe(
+ (msg) => console.log('message received: ' + msg),
+ (err) => console.log(err),
+ () => console.log('complete') * );
+```
+
+```
+//send message
+socket$.next(JSON.stringify({ op: 'hello' }));
+```
+
+It’s really that easy to add websocket support to your application. _websocket_ creates a subject. That means you can both subscribe to it in order to receive messages and send messages through it by calling _next_ .
+
+#### ajax
+
+Just so you know it: Similar to websocket and offers support for AJAX requests. You probably use a library or framework with built-in AJAX support anyway. And if you don’t then I recommend using fetch (and a polyfill if necessary) instead and wrap the returned promise into an observable (see also the _defer_ function below).
+
+* * *
+
+### Custom Streams
+
+Sometimes the already presented functions are not flexible enough. Or you need more control over subscriptions.
+
+#### Subject
+
+A subject is a special object that allows you to emit data to the stream and control it. The subject itself is also an observable, but if you want to expose the stream to other code it’s recommended to use the _asObservable_ method. That way you cannot accidentally call the source methods.
+
+```
+const subject = new Subject();
+const observable = subject.asObservable();
+```
+
+```
+observable.subscribe();
+```
+
+```
+subject.next(1);
+subject.next(2);
+subject.complete();
+```
+
+```
+// Produces
+// 1 2 |
+```
+
+Note that values emitted before subscriptions are “lost”:
+
+```
+const subject = new Subject();
+const observable = subject.asObservable();
+```
+
+```
+subject.next(1);
+```
+
+```
+observable.subscribe(console.log);
+```
+
+```
+subject.next(2);
+subject.complete();
+```
+
+```
+// Prints
+// 2
+```
+
+In addition to the regular subject RxJS provides three specialized versions.
+
+The _AsyncSubject_ emits only the last value after completion.
+
+```
+const subject = new AsyncSubject();
+const observable = subject.asObservable();
+```
+
+```
+observable.subscribe(console.log);
+```
+
+```
+subject.next(1);
+subject.next(2);
+subject.complete();
+```
+
+```
+// Prints
+// 2
+```
+
+The _BehaviorSubject_ allows you to provide a (default) value that will be emitted to every subscriber if no other value has been emitted so far. Otherwise subscribers receive the last emitted value.
+
+```
+const subject = new BehaviorSubject(1);
+const observable = subject.asObservable();
+```
+
+```
+const subscription1 = observable.subscribe(console.log);
+```
+
+```
+subject.next(2);
+subscription1.unsubscribe();
+```
+
+```
+// Prints
+// 1
+// 2
+```
+
+```
+const subscription2 = observable.subscribe(console.log);
+```
+
+```
+// Prints
+// 2
+```
+
+The _ReplaySubject_ stores all emitted values up to a certain number, time or infinitely. All new subscribers will then get all stored values.
+
+```
+const subject = new ReplaySubject();
+const observable = subject.asObservable();
+```
+
+```
+subject.next(1);
+```
+
+```
+observable.subscribe(console.log);
+```
+
+```
+subject.next(2);
+subject.complete();
+```
+
+```
+// Prints
+// 1
+// 2
+```
+
+You can find more information on subjects in the [ReactiveX documentation][10](that also offers additional links). [Ben Lesh][11] offers some insights on subjects in [On The Subject Of Subjects][12], as does [Nicholas Jamieson][13] [in RxJS: Understanding Subjects][14].
+
+#### Observable
+
+You can create an observable by simply using the the new operator. With the function you pass in you can control the stream. That function is called whenever someone subscribe and it receives an observer that you can use like a subject, i.e. call next, complete and error.
+
+Let’s revisit our list example:
+
+```
+const myList = new List();
+myList.add(1);
+myList.add(3);
+```
+
+```
+new Observable(observer => {
+ for (let i = 0; i {
+ //stream it, baby!
+```
+
+```
+ return () => {
+ //clean up
+ };
+})
+.subscribe();
+```
+
+#### Subclass Observable
+
+Before the advent of lettable operators this was a way to implement custom operators. RxJS extends _Observable_ internally. One example is _Subject_ , another is the _publish_ operator. It returns a _ConnectableObservable_ that provides the additional method _connect_ .
+
+#### Implement Subscribable
+
+Sometimes you already have an object that holds state and can emit values. You can turn it into an observable if you implement the Subscribable interface that consists of only a subscribe method.
+
+```
+interface Subscribable { subscribe(observerOrNext?: PartialObserver | ((value: T) => void), error?: (error: any) => void, complete?: () => void): Unsubscribable}
+```
+
+* * *
+
+### Combine and Select Existing Streams
+
+Knowing how to create individual streams is not enough. Sometimes you are confronted with several streams but you only need one. Some of the functions are also available as operators, that’s why I won’t go too deep here. I can recommend an [article][15] from [Max NgWizard K][16] that even contains some fancy animations.
+
+One more recommendation: You can interactively play with combination operators on [RxMarbles][17] by dragging around elements.
+
+#### The ObservableInput type
+
+Operators and functions that expect a stream (or an array of streams) usually do not only work with observables. Instead they actually expect the argument to be of the type ObservableInput that is defined as follows:
+
+```
+type ObservableInput = SubscribableOrPromise | ArrayLike | Iterable;
+```
+
+That means you can e.g. pass promises or arrays without needing to convert them to observables first!
+
+#### defer
+
+The main purpose is to defer the creation of an observable to the time when someone wants to subscribe. This is useful if
+
+* the creation of the observable is computationally expensive
+
+* you want a new observable for each subscriber
+
+* you want to choose between different observables at subscription time
+
+* some code must not be executed before subscription
+
+The last point includes one not so obvious use case: Promises (defer can also return a promise). Take this example using the fetch API:
+
+```
+function getUser(id) {
+ console.log("fetching data");
+ return fetch(`https://server/user/${id}`);
+}
+```
+
+```
+const userPromise = getUser(1);
+console.log("I don't want that request now");
+```
+
+```
+//somewhere else
+userPromise.then(response => console.log("done");
+```
+
+```
+// Prints
+// fetching data
+// I don't want that request now
+// done
+```
+
+Promises are executed immediately, whereas streams are executed when you subscribe. The very moment we call getUser, a request is sent even if we did not want that at that point. Sure, we can use from to convert a promise to an observable, but the promise we pass has already been created / executed. defer allows us to wait until subscription:
+
+```
+const user$ = defer(() => getUser(1));
+```
+
+```
+console.log("I don't want that request now");
+```
+
+```
+//somewhere else
+user$.subscribe(response => console.log("done");
+```
+
+```
+// Prints
+// I don't want that request now
+// fetching data
+// done
+```
+
+#### iif
+
+ _iif_ covers a special use case of _defer_ : Deciding between two streams at subscription time:
+
+```
+iif(
+ () => new Date().getHours() < 12,
+ of("AM"),
+ of("PM")
+)
+.subscribe();
+```
+
+```
+// Produces
+// AM before noon, PM afterwards
+```
+
+To quote the documentation:
+
+> Actually `[iif][3]` can be easily implemented with `[defer][4]`and exists only for convenience and readability reasons.
+
+#### onErrorResumeNext
+
+Starts the first stream and if it fails continues with the next stream. The error is ignored.
+
+```
+const stream1$ = of(1, 2).pipe(
+ tap(i => { if(i>1) throw 'error'}) //fail after first element
+);
+```
+
+```
+const stream2$ = of(3,4);
+```
+
+```
+onErrorResumeNext(stream1$, stream2$)
+ .subscribe(console.log);
+```
+
+```
+// Produces
+// 1 3 4 |
+```
+
+This can be useful if you have more than one web service. In case the main one fails the backup service can be called automatically.
+
+#### forkJoin
+
+Lets streams run concurrently and emits their last values in an array when they are completed. Since only the last values of each streams are emitted it’s typically used for streams that only emit a single element, like HTTP requests. You want the requests run in parallel and do something when all have responses.
+
+```
+function handleResponses([user, account]) {
+ // do something
+}
+```
+
+```
+forkJoin(
+ fetch("https://server/user/1"),
+ fetch("https://server/account/1")
+)
+.subscribe(handleResponses);
+```
+
+#### merge / concat
+
+Emits every value that is emitted by one of the source observables.
+
+ _merge_ supports a parameter that let’s you define how many source streams are subscribed to concurrently. The default is unlimited. A value of 1 would mean listen to one source stream and when it’s completed subscribe to the next one. Since that is a very common scenario you RxJS provides an explicit function: _concat_ .
+
+```
+merge(
+ interval(1000).pipe(mapTo("Stream 1"), take(2)),
+ interval(1200).pipe(mapTo("Stream 2"), take(2)),
+ timer(0, 1000).pipe(mapTo("Stream 3"), take(2)),
+ 2 //two concurrent streams
+)
+.subscribe();
+```
+
+```
+// Subscribes to stream 1 and 2 only
+```
+
+```
+// prints
+// Stream 1 -> after 1000ms
+// Stream 2 -> after 1200ms
+// Stream 1 -> after 2000ms
+```
+
+```
+// Stream 1 has completed, now subscribe to stream 3
+```
+
+```
+// prints
+// Stream 3 -> after 0 ms
+// Stream 2 -> after 400 ms (2400ms from beginning)
+// Stream 3 -> after 1000ms
+```
+
+```
+
+merge(
+ interval(1000).pipe(mapTo("Stream 1"), take(2)),
+ interval(1200).pipe(mapTo("Stream 2"), take(2))
+ 1
+)
+// is equal to
+concat(
+ interval(1000).pipe(mapTo("Stream 1"), take(2)),
+ interval(1200).pipe(mapTo("Stream 2"), take(2))
+)
+```
+
+```
+// prints
+// Stream 1 -> after 1000ms
+// Stream 1 -> after 2000ms
+// Stream 2 -> after 3200ms
+// Stream 2 -> after 4400ms
+```
+
+#### zip / combineLatest
+
+While _merge_ and _concat_ emit all values from the source streams individually, zip and combineLatest combine one value of each source stream and emit them together. _zip_ combines the first values emitted by all(!) source streams, the second values and so on. This is useful if the contents of the streams are related.
+
+```
+zip(
+ interval(1000),
+ interval(1200),
+)
+.subscribe();
+```
+
+```
+// Produces
+// [0, 0] [1, 1] [2, 2] ...
+```
+
+ _combineLatest_ is similar but combines the latest values emitted by the source streams. Nothing happens until all source streams have emitted at least one value. From then on every time a source stream emits a value, it is combined with the last values of the other streams.
+
+```
+combineLatest(
+ interval(1000),
+ interval(1200),
+)
+.subscribe();
+```
+
+```
+// Produces
+// [0, 0] [1, 0] [1, 1] [2, 1] ...
+```
+
+Both functions allow you to pass a selector function that can combine the elements to something else than an array:
+
+```
+zip(
+ interval(1000),
+ interval(1200),
+ (e1, e2) -> e1 + e2
+)
+.subscribe();
+```
+
+```
+// Produces
+// 0 2 4 6 ...
+```
+
+#### race
+
+The first stream that emits a value is selected. So the resulting stream is essentially the fastest stream.
+
+```
+race(
+ interval(1000),
+ of("foo")
+)
+.subscribe();
+```
+
+```
+// Produces
+// foo |
+```
+
+Since _of_ produces a value immediately it’s the faster stream and the stream that gets selected.
+
+* * *
+
+### Conclusion
+
+That have been a lot of ways to create observables. Knowing them is essential if you want to create reactive APIs or want to combine legacy APIs with reactive ones.
+
+I have presented you all options but much more could be said about all of them. If you want to dive deeper I highly recommend consulting the [documentation][20] or reading the suggested articles.
+
+Another interesting way to get insight is [RxViz][21]. You write RxJS code and the resulting streams are then displayed graphically and animated.
+
+--------------------------------------------------------------------------------
+
+via: https://blog.angularindepth.com/the-extensive-guide-to-creating-streams-in-rxjs-aaa02baaff9a
+
+作者:[Oliver Flaggl][a]
+译者:[译者ID](https://github.com/译者ID)
+校对:[校对者ID](https://github.com/校对者ID)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://blog.angularindepth.com/@abetteroliver
+[1]:https://rxjs-dev.firebaseapp.com/api/index/Subscribable
+[2]:https://rxjs-dev.firebaseapp.com/api/index/Subscribable#subscribe
+[3]:https://rxjs-dev.firebaseapp.com/api/index/iif
+[4]:https://rxjs-dev.firebaseapp.com/api/index/defer
+[5]:https://itnext.io/concurrency-and-asynchronous-behavior-with-rxjs-11b0c4b22597
+[6]:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
+[7]:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
+[8]:https://medium.com/@benlesh/rxjs-observable-interop-with-promises-and-async-await-bebb05306875
+[9]:https://medium.com/@benlesh
+[10]:http://reactivex.io/documentation/subject.html
+[11]:https://medium.com/@benlesh
+[12]:https://medium.com/@benlesh/on-the-subject-of-subjects-in-rxjs-2b08b7198b93
+[13]:https://medium.com/@cartant
+[14]:https://blog.angularindepth.com/rxjs-understanding-subjects-5c585188c3e1
+[15]:https://blog.angularindepth.com/learn-to-combine-rxjs-sequences-with-super-intuitive-interactive-diagrams-20fce8e6511
+[16]:https://medium.com/@maximus.koretskyi
+[17]:http://rxmarbles.com/#merge
+[18]:https://rxjs-dev.firebaseapp.com/api/index/ObservableInput
+[19]:https://rxjs-dev.firebaseapp.com/api/index/SubscribableOrPromise
+[20]:http://reactivex.io/documentation/operators.html#creating
+[21]:https://rxviz.com/
diff --git a/sources/tech/20180430 3 practical Python tools- magic methods, iterators and generators, and method magic.md b/sources/tech/20180430 3 practical Python tools- magic methods, iterators and generators, and method magic.md
deleted file mode 100644
index ef3099218e..0000000000
--- a/sources/tech/20180430 3 practical Python tools- magic methods, iterators and generators, and method magic.md
+++ /dev/null
@@ -1,636 +0,0 @@
-Translating by MjSeven
-
-
-3 practical Python tools: magic methods, iterators and generators, and method magic
-======
-
-![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/serving-bowl-forks-dinner.png?itok=a3YqPwr5)
-Python offers a unique set of tools and language features that help make your code more elegant, readable, and intuitive. By selecting the right tool for the right problem, your code will be easier to maintain. In this article, we'll examine three of those tools: magic methods, iterators and generators, and method magic.
-
-### Magic methods
-
-
-Magic methods can be considered the plumbing of Python. They're the methods that are called "under the hood" for certain built-in methods, symbols, and operations. A common magic method you may be familiar with is, `__init__()`,which is called when we want to initialize a new instance of a class.
-
-You may have seen other common magic methods, like `__str__` and `__repr__`. There is a whole world of magic methods, and by implementing a few of them, we can greatly modify the behavior of an object or even make it behave like a built-in datatype, such as a number, list, or dictionary.
-
-Let's take this `Money` class for example:
-```
-class Money:
-
-
-
- currency_rates = {
-
- '$': 1,
-
- '€': 0.88,
-
- }
-
-
-
- def __init__(self, symbol, amount):
-
- self.symbol = symbol
-
- self.amount = amount
-
-
-
- def __repr__(self):
-
- return '%s%.2f' % (self.symbol, self.amount)
-
-
-
- def convert(self, other):
-
- """ Convert other amount to our currency """
-
- new_amount = (
-
- other.amount / self.currency_rates[other.symbol]
-
- * self.currency_rates[self.symbol])
-
-
-
- return Money(self.symbol, new_amount)
-
-```
-
-The class defines a currency rate for a given symbol and exchange rate, specifies an initializer (also known as a constructor), and implements `__repr__`, so when we print out the class, we see a nice representation such as `$2.00` for an instance `Money('$', 2.00)` with the currency symbol and amount. Most importantly, it defines a method that allows you to convert between different currencies with different exchange rates.
-
-Using a Python shell, let's say we've defined the costs for two food items in different currencies, like so:
-```
->>> soda_cost = Money('$', 5.25)
-
->>> soda_cost
-
- $5.25
-
-
-
->>> pizza_cost = Money('€', 7.99)
-
->>> pizza_cost
-
- €7.99
-
-```
-
-We could use magic methods to help instances of this class interact with each other. Let's say we wanted to be able to add two instances of this class together, even if they were in different currencies. To make that a reality, we could implement the `__add__` magic method on our `Money` class:
-```
-class Money:
-
-
-
- # ... previously defined methods ...
-
-
-
- def __add__(self, other):
-
- """ Add 2 Money instances using '+' """
-
- new_amount = self.amount + self.convert(other).amount
-
- return Money(self.symbol, new_amount)
-
-```
-
-Now we can use this class in a very intuitive way:
-```
->>> soda_cost = Money('$', 5.25)
-
-
-
->>> pizza_cost = Money('€', 7.99)
-
-
-
->>> soda_cost + pizza_cost
-
- $14.33
-
-
-
->>> pizza_cost + soda_cost
-
- €12.61
-
-```
-
-When we add two instances together, we get a result in the first defined currency. All the conversion is done seamlessly under the hood. If we wanted to, we could also implement `__sub__` for subtraction, `__mul__` for multiplication, and many more. Read about [emulating numeric types][1], or read this [guide to magic methods][2] for others.
-
-We learned that `__add__` maps to the built-in operator `+`. Other magic methods can map to symbols like `[]`. For example, to access an item by index or key (in the case of a dictionary), use the `__getitem__` method:
-```
->>> d = {'one': 1, 'two': 2}
-
-
-
->>> d['two']
-
-2
-
->>> d.__getitem__('two')
-
-2
-
-```
-
-Some magic methods even map to built-in functions, such as `__len__()`, which maps to `len()`.
-```
-class Alphabet:
-
- letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-
-
-
- def __len__(self):
-
- return len(self.letters)
-
-
-
-
-
->>> my_alphabet = Alphabet()
-
->>> len(my_alphabet)
-
- 26
-
-```
-
-### Custom iterators
-
-Custom iterators are an incredibly powerful but unfortunately confusing topic to new and seasoned Pythonistas alike.
-
-Many built-in types, such as lists, sets, and dictionaries, already implement the protocol that allows them to be iterated over under the hood. This allows us to easily loop over them.
-```
->>> for food in ['Pizza', 'Fries']:
-
- print(food + '. Yum!')
-
-
-
-Pizza. Yum!
-
-Fries. Yum!
-
-```
-
-How can we iterate over our own custom classes? First, let's clear up some terminology.
-
- * To be iterable, a class needs to implement `__iter__()`
- * The `__iter__()` method needs to return an iterator
- * To be an iterator, a class needs to implement `__next__()` (or `next()` [in Python 2][3]), which must raise a `StopIteration` exception when there are no more items to iterate over.
-
-
-
-Whew! It sounds complicated, but once you remember these fundamental concepts, you'll be able to iterate in your sleep.
-
-When might we want to use a custom iterator? Let's imagine a scenario where we have a `Server` instance running different services such as `http` and `ssh` on different ports. Some of these services have an `active` state while others are `inactive`.
-```
-class Server:
-
-
-
- services = [
-
- {'active': False, 'protocol': 'ftp', 'port': 21},
-
- {'active': True, 'protocol': 'ssh', 'port': 22},
-
- {'active': True, 'protocol': 'http', 'port': 80},
-
- ]
-
-```
-
-When we loop over our `Server` instance, we only want to loop over `active` services. Let's create a new class, an `IterableServer`:
-```
-class IterableServer:
-
-
-
- def __init__(self):
-
- self.current_pos = 0
-
-
-
- def __next__(self):
-
- pass # TODO: Implement and remember to raise StopIteration
-
-```
-
-First, we initialize our current position to `0`. Then, we define a `__next__()` method, which will return the next item. We'll also ensure that we raise `StopIteration` when there are no more items to return. So far so good! Now, let's implement this `__next__()` method.
-```
-class IterableServer:
-
-
-
- def __init__(self):
-
- self.current_pos = 0. # we initialize our current position to zero
-
-
-
- def __iter__(self): # we can return self here, because __next__ is implemented
-
- return self
-
-
-
- def __next__(self):
-
- while self.current_pos < len(self.services):
-
- service = self.services[self.current_pos]
-
- self.current_pos += 1
-
- if service['active']:
-
- return service['protocol'], service['port']
-
- raise StopIteration
-
-
-
- next = __next__ # optional python2 compatibility
-
-```
-
-We keep looping over the services in our list while our current position is less than the length of the services but only returning if the service is active. Once we run out of services to iterate over, we raise a `StopIteration` exception.
-
-Because we implement a `__next__()` method that raises `StopIteration` when it is exhausted, we can return `self` from `__iter__()` because the `IterableServer` class adheres to the `iterable` protocol.
-
-Now we can loop over an instance of `IterableServer`, which will allow us to look at each active service, like so:
-```
->>> for protocol, port in IterableServer():
-
- print('service %s is running on port %d' % (protocol, port))
-
-
-
-service ssh is running on port 22
-
-service http is running on port 21
-
-```
-
-That's pretty great, but we can do better! In an instance like this, where our iterator doesn't need to maintain a lot of state, we can simplify our code and use a [generator][4] instead.
-```
-class Server:
-
-
-
- services = [
-
- {'active': False, 'protocol': 'ftp', 'port': 21},
-
- {'active': True, 'protocol': 'ssh', 'port': 22},
-
- {'active': True, 'protocol': 'http', 'port': 21},
-
- ]
-
-
-
- def __iter__(self):
-
- for service in self.services:
-
- if service['active']:
-
- yield service['protocol'], service['port']
-
-```
-
-What exactly is the `yield` keyword? Yield is used when defining a generator function. It's sort of like a `return`. While a `return` exits the function after returning the value, `yield` suspends execution until the next time it's called. This allows your generator function to maintain state until it resumes. Check out [yield's documentation][5] to learn more. With a generator, we don't have to manually maintain state by remembering our position. A generator knows only two things: what it needs to do right now and what it needs to do to calculate the next item. Once we reach a point of execution where `yield` isn't called again, we know to stop iterating.
-
-This works because of some built-in Python magic. In the [Python documentation for `__iter__()`][6] we can see that if `__iter__()` is implemented as a generator, it will automatically return an iterator object that supplies the `__iter__()` and `__next__()` methods. Read this great article for a deeper dive of [iterators, iterables, and generators][7].
-
-### Method magic
-
-Due to its unique aspects, Python provides some interesting method magic as part of the language.
-
-One example of this is aliasing functions. Since functions are just objects, we can assign them to multiple variables. For example:
-```
->>> def foo():
-
- return 'foo'
-
-
-
->>> foo()
-
-'foo'
-
-
-
->>> bar = foo
-
-
-
->>> bar()
-
-'foo'
-
-```
-
-We'll see later on how this can be useful.
-
-Python provides a handy built-in, [called `getattr()`][8], that takes the `object, name, default` parameters and returns the attribute `name` on `object`. This programmatically allows us to access instance variables and methods. For example:
-```
->>> class Dog:
-
- sound = 'Bark'
-
- def speak(self):
-
- print(self.sound + '!', self.sound + '!')
-
-
-
->>> fido = Dog()
-
-
-
->>> fido.sound
-
-'Bark'
-
->>> getattr(fido, 'sound')
-
-'Bark'
-
-
-
->>> fido.speak
-
->
-
->>> getattr(fido, 'speak')
-
->
-
-
-
-
-
->>> fido.speak()
-
-Bark! Bark!
-
->>> speak_method = getattr(fido, 'speak')
-
->>> speak_method()
-
-Bark! Bark!
-
-```
-
-Cool trick, but how could we practically use `getattr`? Let's look at an example that allows us to write a tiny command-line tool to dynamically process commands.
-```
-class Operations:
-
- def say_hi(self, name):
-
- print('Hello,', name)
-
-
-
- def say_bye(self, name):
-
- print ('Goodbye,', name)
-
-
-
- def default(self, arg):
-
- print ('This operation is not supported.')
-
-
-
-if __name__ == '__main__':
-
- operations = Operations()
-
-
-
- # let's assume we do error handling
-
- command, argument = input('> ').split()
-
- func_to_call = getattr(operations, command, operations.default)
-
- func_to_call(argument)
-
-```
-
-The output of our script is:
-```
-$ python getattr.py
-
-
-
-> say_hi Nina
-
-Hello, Nina
-
-
-
-> blah blah
-
-This operation is not supported.
-
-```
-
-Next, we'll look at `partial`. For example, **`functool.partial(func, *args, **kwargs)`** allows you to return a new [partial object][9] that behaves like `func` called with `args` and `kwargs`. If more `args` are passed in, they're appended to `args`. If more `kwargs` are passed in, they extend and override `kwargs`. Let's see it in action with a brief example:
-```
->>> from functools import partial
-
->>> basetwo = partial(int, base=2)
-
->>> basetwo
-
-
-
-
-
->>> basetwo('10010')
-
-18
-
-
-
-# This is the same as
-
->>> int('10010', base=2)
-
-```
-
-Let's see how this method magic ties together in some sample code from a library I enjoy using [called][10]`agithub`, which is a (poorly named) REST API client with transparent syntax that allows you to rapidly prototype any REST API (not just GitHub) with minimal configuration. I find this project interesting because it's incredibly powerful yet only about 400 lines of Python. You can add support for any REST API in about 30 lines of configuration code. `agithub` knows everything it needs to about protocol (`REST`, `HTTP`, `TCP`), but it assumes nothing about the upstream API. Let's dive into the implementation.
-
-Here's a simplified version of how we'd define an endpoint URL for the GitHub API and any other relevant connection properties. View the [full code][11] instead.
-```
-class GitHub(API):
-
-
-
- def __init__(self, token=None, *args, **kwargs):
-
- props = ConnectionProperties(api_url = kwargs.pop('api_url', 'api.github.com'))
-
- self.setClient(Client(*args, **kwargs))
-
- self.setConnectionProperties(props)
-
-```
-
-Then, once your [access token][12] is configured, you can start using the [GitHub API][13].
-```
->>> gh = GitHub('token')
-
->>> status, data = gh.user.repos.get(visibility='public', sort='created')
-
->>> # ^ Maps to GET /user/repos
-
->>> data
-
-... ['tweeter', 'snipey', '...']
-
-```
-
-Note that it's up to you to spell things correctly. There's no validation of the URL. If the URL doesn't exist or anything else goes wrong, the error thrown by the API will be returned. So, how does this all work? Let's figure it out. First, we'll check out a simplified example of the [`API` class][14]:
-```
-class API:
-
-
-
- # ... other methods ...
-
-
-
- def __getattr__(self, key):
-
- return IncompleteRequest(self.client).__getattr__(key)
-
- __getitem__ = __getattr__
-
-```
-
-Each call on the `API` class ferries the call to the [`IncompleteRequest` class][15] for the specified `key`.
-```
-class IncompleteRequest:
-
-
-
- # ... other methods ...
-
-
-
- def __getattr__(self, key):
-
- if key in self.client.http_methods:
-
- htmlMethod = getattr(self.client, key)
-
- return partial(htmlMethod, url=self.url)
-
- else:
-
- self.url += '/' + str(key)
-
- return self
-
- __getitem__ = __getattr__
-
-
-
-
-
-class Client:
-
- http_methods = ('get') # ... and post, put, patch, etc.
-
-
-
- def get(self, url, headers={}, **params):
-
- return self.request('GET', url, None, headers)
-
-```
-
-If the last call is not an HTTP method (like 'get', 'post', etc.), it returns an `IncompleteRequest` with an appended path. Otherwise, it gets the right function for the specified HTTP method from the [`Client` class][16] and returns a `partial` .
-
-What happens if we give a non-existent path?
-```
->>> status, data = this.path.doesnt.exist.get()
-
->>> status
-
-... 404
-
-```
-
-And because `__getitem__` is aliased to `__getattr__`:
-```
->>> owner, repo = 'nnja', 'tweeter'
-
->>> status, data = gh.repos[owner][repo].pulls.get()
-
->>> # ^ Maps to GET /repos/nnja/tweeter/pulls
-
->>> data
-
-.... # {....}
-
-```
-
-Now that's some serious method magic!
-
-### Learn more
-
-Python provides plenty of tools that allow you to make your code more elegant and easier to read and understand. The challenge is finding the right tool for the job, but I hope this article added some new ones to your toolbox. And, if you'd like to take this a step further, you can read about decorators, context managers, context generators, and `NamedTuple`s on my blog [nnja.io][17]. As you become a better Python developer, I encourage you to get out there and read some source code for well-architected projects. [Requests][18] and [Flask][19] are two great codebases to start with.
-
-
---------------------------------------------------------------------------------
-
-via: https://opensource.com/article/18/4/elegant-solutions-everyday-python-problems
-
-作者:[Nina Zakharenko][a]
-选题:[lujun9972](https://github.com/lujun9972)
-译者:[译者ID](https://github.com/译者ID)
-校对:[校对者ID](https://github.com/校对者ID)
-
-本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
-
-[a]:https://opensource.com/users/nnja
-[1]:https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types
-[2]:https://rszalski.github.io/magicmethods/
-[3]:https://docs.python.org/2/library/stdtypes.html#iterator.next
-[4]:https://docs.python.org/3/library/stdtypes.html#generator-types
-[5]:https://docs.python.org/3/reference/expressions.html#yieldexpr
-[6]:https://docs.python.org/3/reference/datamodel.html#object.__iter__
-[7]:http://nvie.com/posts/iterators-vs-generators/
-[8]:https://docs.python.org/3/library/functions.html#getattr
-[9]:https://docs.python.org/3/library/functools.html#functools.partial
-[10]:https://github.com/mozilla/agithub
-[11]:https://github.com/mozilla/agithub/blob/master/agithub/GitHub.py
-[12]:https://github.com/settings/tokens
-[13]:https://developer.github.com/v3/repos/#list-your-repositories
-[14]:https://github.com/mozilla/agithub/blob/dbf7014e2504333c58a39153aa11bbbdd080f6ac/agithub/base.py#L30-L58
-[15]:https://github.com/mozilla/agithub/blob/dbf7014e2504333c58a39153aa11bbbdd080f6ac/agithub/base.py#L60-L100
-[16]:https://github.com/mozilla/agithub/blob/dbf7014e2504333c58a39153aa11bbbdd080f6ac/agithub/base.py#L102-L231
-[17]:http://nnja.io
-[18]:https://github.com/requests/requests
-[19]:https://github.com/pallets/flask
-[20]:https://us.pycon.org/2018/schedule/presentation/164/
-[21]:https://us.pycon.org/2018/
diff --git a/sources/tech/20180703 Understanding Python Dataclasses — Part 1.md b/sources/tech/20180703 Understanding Python Dataclasses — Part 1.md
new file mode 100644
index 0000000000..b8f9ece782
--- /dev/null
+++ b/sources/tech/20180703 Understanding Python Dataclasses — Part 1.md
@@ -0,0 +1,614 @@
+MjSeven is translating
+
+Understanding Python Dataclasses — Part 1
+============================================================
+
+![](https://cdn-images-1.medium.com/max/900/1*7pr8EL8EDsP296pxL7Wz_g.png)
+
+If you’re reading this, then you are already aware of Python 3.7 and the new features that come packed with it. Personally, I am most excited about `Dataclasses`. I have been waiting for them to arrive for a while.
+
+This is a two part post:
+1\. Dataclass features overview in this post
+2\. Dataclass `fields` overview in the [next post][1]
+
+### Introduction
+
+`Dataclasses` are python classes but are suited for storing data objects. What are data objects, you ask? Here is a non-exhaustive list of features that define data objects:
+
+* They store data and represent a certain data type. Ex: A number. For people familiar with ORMs, a model instance is a data object. It represents a specific kind of entity. It holds attributes that define or represent the entity.
+
+* They can be compared to other objects of the same type. Ex: A number can be `greater than`, `less than`, or `equal to` another number
+
+There are certainly more features, but this list is sufficient to help you understand the crux.
+
+To understand `Dataclasses`, we shall be implementing a simple class that holds a number, and allows us to perform the above mentioned operations.
+First, we shall be using normal classes, and then we shall use `Dataclasses` to achieve the same result.
+
+But before we begin, a word on the usage of `Dataclasses`
+
+Python 3.7 provides a decorator [dataclass][2] that is used to convert a class into a dataclass.
+
+All you have to do is wrap the class in the decorator:
+
+```
+from dataclasses import dataclass
+```
+
+```
+@dataclass
+class A:
+ …
+```
+
+Now, lets dive into the usage of how and what `dataclass` changes for us.
+
+### Initialization
+
+Usual
+
+```
+class Number:
+```
+
+```
+ __init__(self, val):
+ self.val = val
+
+>>> one = Number(1)
+>>> one.val
+>>> 1
+```
+
+With `dataclass`
+
+```
+@dataclass
+class Number:
+ val:int
+
+>>> one = Number(1)
+>>> one.val
+>>> 1
+```
+
+Here’s what’s changed with the dataclass decorator:
+
+1\. No need of defining `__init__`and then assigning values to `self`, `d` takes care of it
+2\. We defined the member attributes in advance in a much more readable fashion, along with [type hinting][3]. We now know instantly that `val` is of type `int`. This is definitely more readable than the usual way of defining class members.
+
+> Zen of Python: Readability counts
+
+It is also possible to define default values:
+
+```
+@dataclass
+class Number:
+ val:int = 0
+```
+
+### Representation
+
+Object representation is a meaningful string representation of the object that is very useful in debugging.
+
+Default python objects representation is not very meaningful:
+
+```
+class Number:
+ def __init__(self, val = 0):
+ self.val = val
+
+>>> a = Number(1)
+>>> a
+>>> <__main__.Number object at 0x7ff395b2ccc0>
+```
+
+This gives us no insight as to the utility of the object, and will result in horrible a debugging experience.
+
+A meaningful representation could be implemented by defining a `__repr__`method in the class definition.
+
+```
+def __repr__(self):
+ return self.val
+```
+
+Now we get a meaningful representation of the object:
+
+```
+>>> a = Number(1)
+>>> a
+>>> 1
+```
+
+`dataclass` automatically add a `__repr__ `function, so that we don’t have to manually implement it.
+
+```
+@dataclass
+class Number:
+ val: int = 0
+```
+
+```
+>>> a = Number(1)
+>>> a
+>>> Number(val = 1)
+```
+
+### Data Comparison
+
+Generally, data objects come with a need to be compared with each other.
+
+Comparison between two objects `a` and `b` generally consists of the following operations:
+
+* a < b
+
+* a > b
+
+* a == b
+
+* a >= b
+
+* a <= b
+
+In python, it is possible to define [methods][4] in classes that can do the above operations. For the sake of simplicity and to not let this post run amuck, I shall be only demonstrating implementation of `==` and `<`.
+
+Usual
+
+```
+class Number:
+ def __init__( self, val = 0):
+ self.val = val
+
+ def __eq__(self, other):
+ return self.val == other.val
+
+ def __lt__(self, other):
+ return self.val < other.val
+```
+
+With `dataclass`
+
+```
+@dataclass(order = True)
+class Number:
+ val: int = 0
+```
+
+Yup, that’s it.
+
+We dont need to define the `__eq__`and `__lt__` methods, because `dataclass`decorator automatically adds them to the class definition for us when called with `order = True`
+
+Well, how does it do that?
+
+When you use `dataclass,` it adds a functions `__eq__` and `__lt__` to the class definition. We already know that. So, how do these functions know how to check equality and do comparison?
+
+A dataclass generated `__eq__` function will compare a tuple of its attributes with a tuple of attributes of the other instance of the same class. In our case here’s what the `automatically` generated `__eq__` function would be equivalent to:
+
+```
+def __eq__(self, other):
+ return (self.val,) == (other.val,)
+```
+
+Let’s look at a more elaborate example:
+
+We shall write a dataclass `Person `to hold their `name` and `age`.
+
+```
+@dataclass(order = True)
+class Person:
+ name: str
+ age:int = 0
+```
+
+The automatically generated `__eq__` method will be equivalent of:
+
+```
+def __eq__(self, other):
+ return (self.name, self.age) == ( other.name, other.age)
+```
+
+Pay attention to the order of the attributes. They will always be generated in the order you defined them in the dataclass definition.
+
+Similarly, the equivalent `__le__` function would be akin to:
+
+```
+def __le__(self, other):
+ return (self.name, self.age) <= (other.name, other.age)
+```
+
+A need for defining a function like `__le__` generally arises, when you have to sort a list of your data objects. Python’s built-in [sorted][5] function relies on comparing two objects.
+
+```
+
+>>> import random
+```
+
+```
+>>> a = [Number(random.randint(1,10)) for _ in range(10)] #generate list of random numbers
+```
+
+```
+>>> a
+```
+
+```
+>>> [Number(val=2), Number(val=7), Number(val=6), Number(val=5), Number(val=10), Number(val=9), Number(val=1), Number(val=10), Number(val=1), Number(val=7)]
+```
+
+```
+>>> sorted_a = sorted(a) #Sort Numbers in ascending order
+```
+
+```
+>>> [Number(val=1), Number(val=1), Number(val=2), Number(val=5), Number(val=6), Number(val=7), Number(val=7), Number(val=9), Number(val=10), Number(val=10)]
+```
+
+```
+>>> reverse_sorted_a = sorted(a, reverse = True) #Sort Numbers in descending order
+```
+
+```
+>>> reverse_sorted_a
+```
+
+```
+>>> [Number(val=10), Number(val=10), Number(val=9), Number(val=7), Number(val=7), Number(val=6), Number(val=5), Number(val=2), Number(val=1), Number(val=1)]
+
+```
+
+### `dataclass` as a callable decorator
+
+It is not always desirable to have all the `dunder` methods defined. Your use case might only consist of storing the values and checking equality. Thus, you only need the `__init__` and `__eq__` methods defined. If we could tell the decorator to not generate the other methods, it would reduce some overhead and we shall have correct operations available on the data object.
+
+Fortunately, this can be achieved by using `dataclass` decorator as a callable.
+
+From the official [docs][6], the decorator can be used as a callable with the following arguments:
+
+```
+@dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False)
+class C:
+ …
+```
+
+1. `init` : By default an `__init__` method will be generated. If passed as `False`, the class will not have an `__init__` method.
+
+2. `repr` : `__repr__` method is generated by default. If passed as `False`, the class will not have an `__repr__` method.
+
+3. `eq`: By default the `__eq__` method will be generated. If passed as `False`, the `__eq__` method will not be added by `dataclass`, but will default to the `object.__eq__`.
+
+4. `order` : By default `__gt__` , `__ge__`, `__lt__`, `__le__` methods will be generated. If passed as `False`, they are omitted.
+
+We shall discuss `frozen` in a while. The `unsafe_hash` argument deserves a separate post because of its complicated use cases.
+
+Now, back to our use case, here’s what we need:
+
+1. `__init__`
+2. `__eq__`
+
+These functions are generated by default, so what we need is to not have the other functions generated. How do we do that? Simply pass the relevant arguments as false to the generator.
+
+```
+@dataclass(repr = False) # order, unsafe_hash and frozen are False
+class Number:
+ val: int = 0
+```
+
+```
+>>> a = Number(1)
+```
+
+```
+>>> a
+```
+
+```
+>>> <__main__.Number object at 0x7ff395afe898>
+```
+
+```
+>>> b = Number(2)
+```
+
+```
+>>> c = Number(1)
+```
+
+```
+>>> a == b
+```
+
+```
+>>> False
+```
+
+```
+>>> a < b
+```
+
+```
+>>> Traceback (most recent call last):
+ File “”, line 1, in
+TypeError: ‘<’ not supported between instances of ‘Number’ and ‘Number’
+```
+
+### Frozen Instances
+
+Frozen Instances are objects whose attributes cannot be modified after the object has been initialized.
+
+> It is not possible to create truly immutable Python objects
+
+To create immutable attributes on an object in Python is an arduous task, and something that I won’t dive into in this post.
+
+Here’s what we expect from an immutable object:
+
+```
+>>> a = Number(10) #Assuming Number class is immutable
+```
+
+```
+>>> a.val = 10 # Raises Error
+```
+
+With Dataclasses it is possible to define a frozen object by using `dataclass`decorator as a callable with argument `frozen=True` .
+
+When a frozen dataclass object is instantiated, any attempt to modify the attributes of the object raises `FrozenInstanceError`.
+
+```
+@dataclass(frozen = True)
+class Number:
+ val: int = 0
+```
+
+```
+>>> a = Number(1)
+```
+
+```
+>>> a.val
+```
+
+```
+>>> 1
+```
+
+```
+>>> a.val = 2
+```
+
+```
+>>> Traceback (most recent call last):
+ File “”, line 1, in
+ File “”, line 3, in __setattr__
+dataclasses.FrozenInstanceError: cannot assign to field ‘val’
+```
+
+So a frozen instance is a great way of storing
+
+* constants
+
+* settings
+
+These generally do not change over the lifetime of the application and any attempt to modify them should generally be warded off.
+
+### Post init processing
+
+With Dataclasses the requirement of defining an `__init__` method to assign variables to `self` has been taken care of. But now we lose the flexibility of making function-calls/processing that might be required immediately after the variables have been assigned.
+
+Let us discuss a use case where we define a class `Float` to contain float numbers, and we calculate the integer and decimal parts immediately after initialization.
+
+Usual
+
+```
+import math
+```
+
+```
+class Float:
+ def __init__(self, val = 0):
+ self.val = val
+ self.process()
+
+ def process(self):
+ self.decimal, self.integer = math.modf(self.val)
+
+>>> a = Float( 2.2)
+```
+
+```
+>>> a.decimal
+```
+
+```
+>>> 0.2000
+```
+
+```
+>>> a.integer
+```
+
+```
+>>> 2.0
+```
+
+Fortunately, post initialization processing is already taken care of with [__post_init__][9] method.
+
+The generated `__init__` method calls the `__post_init__` method before returning. So, any processing can be made in this functions.
+
+```
+import math
+```
+
+```
+@dataclass
+class FloatNumber:
+ val: float = 0.0
+
+ def __post_init__(self):
+ self.decimal, self.integer = math.modf(self.val)
+
+>>> a = Number(2.2)
+```
+
+```
+>>> a.val
+```
+
+```
+>>> 2.2
+```
+
+```
+>>> a.integer
+```
+
+```
+>>> 2.0
+```
+
+```
+>>> a.decimal
+```
+
+```
+>>> 0.2
+```
+
+Neat!
+
+
+### Inheritance
+
+`Dataclasses` support inheritance like normal python classes.
+
+So, the attributes defined in the parent class will be available in the child class.
+
+```
+@dataclass
+class Person:
+ age: int = 0
+ name: str
+```
+
+```
+@dataclass
+class Student(Person):
+ grade: int
+```
+
+```
+>>> s = Student(20, "John Doe", 12)
+```
+
+```
+>>> s.age
+```
+
+```
+>>> 20
+```
+
+```
+>>> s.name
+```
+
+```
+>>> "John Doe"
+```
+
+```
+>>> s.grade
+```
+
+```
+>>> 12
+```
+
+Pay attention to the fact that the arguments to `Student` are in the order of fields defined in the class definition.
+
+What about the behavior of `__post_init__` during inheritance?
+
+Since `__post_init__` is just another function, it has to be invoked in the conventional form:
+
+```
+@dataclass
+class A:
+ a: int
+
+ def __post_init__(self):
+ print("A")
+```
+
+```
+@dataclass
+class B(A):
+ b: int
+
+ def __post_init__(self):
+ print("B")
+```
+
+```
+>>> a = B(1,2)
+```
+
+```
+>>> B
+```
+
+In the above example, only `B's` `__post_init__` is called. How do we invoke `A's` `__post_init__` ?
+
+Since it is a function of the parent class, it can be invoked using `super.`
+
+```
+@dataclass
+class B(A):
+ b: int
+
+ def __post_init__(self):
+ super().__post_init__() #Call post init of A
+ print("B")
+```
+
+```
+>>> a = B(1,2)
+```
+
+```
+>>> A
+ B
+```
+
+### Conclusion
+
+So, above are a few ways in which Dataclasses make life easier for Python developers.
+I have tried to be thorough and cover most of the use cases, yet, no man is perfect. Reach out if you find mistakes, or want me to pay attention to relevant use cases.
+
+I shall cover [dataclasses.field][10] and `unsafe_hash` in different posts.
+
+Follow me on [Github][11], [Twitter][12].
+
+Update: Post for `dataclasses.field` can be found [here][13].
+
+--------------------------------------------------------------------------------
+
+via: https://medium.com/mindorks/understanding-python-dataclasses-part-1-c3ccd4355c34
+
+作者:[Shikhar Chauhan][a]
+译者:[译者ID](https://github.com/译者ID)
+校对:[校对者ID](https://github.com/校对者ID)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://medium.com/@xsschauhan?source=post_header_lockup
+[1]:https://medium.com/@xsschauhan/understanding-python-dataclasses-part-2-660ecc11c9b8
+[2]:https://docs.python.org/3.7/library/dataclasses.html#dataclasses.dataclass
+[3]:https://stackoverflow.com/q/32557920/4333721
+[4]:https://docs.python.org/3/reference/datamodel.html#object.__lt__
+[5]:https://docs.python.org/3.7/library/functions.html#sorted
+[6]:https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass
+[7]:http://twitter.com/dataclass
+[8]:http://twitter.com/dataclass
+[9]:https://docs.python.org/3/library/dataclasses.html#post-init-processing
+[10]:https://docs.python.org/3/library/dataclasses.html#dataclasses.field
+[11]:http://github.com/xssChauhan/
+[12]:https://twitter.com/xssChauhan
+[13]:https://medium.com/@xsschauhan/understanding-python-dataclasses-part-2-660ecc11c9b8
diff --git a/sources/tech/20180706 6 RFCs for understanding how the internet works.md b/sources/tech/20180706 6 RFCs for understanding how the internet works.md
deleted file mode 100644
index aefdad8882..0000000000
--- a/sources/tech/20180706 6 RFCs for understanding how the internet works.md
+++ /dev/null
@@ -1,77 +0,0 @@
-translating---geekpi
-
-6 RFCs for understanding how the internet works
-======
-
-![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/LAW-Internet_construction_9401467_520x292_0512_dc.png?itok=RPkPPtDe)
-
-Reading the source is an important part of open source software. It means users have the ability to look at the code and see what it does.
-
-But "read the source" doesn't apply only to code. Understanding the standards the code implements can be just as important. These standards are codified in documents called "Requests for Comments" (RFCs) published by the [Internet Engineering Task Force][1] (IETF). Thousands of RFCs have been published over the years, so we collected a few that our contributors consider must-reads.
-
-### 6 must-read RFCs
-
-#### RFC 2119—Key words for use in RFCs to indicate requirement levels
-
-This is a quick read, but it's important to understanding other RFCs. [RFC 2119][2] defines the requirement levels used in subsequent RFCs. What does "MAY" really mean? If the standard says "SHOULD," do you really have to do it? By giving the requirements a well-defined taxonomy, RFC 2119 helps avoid ambiguity.
-
-Time is the bane of programmers the world over. [RFC 3339][3] defines how timestamps are to be formatted. Based on the [ISO 8601][4] standard, 3339 gives us a common way to represent time and its relentless march. For example, redundant information like the day of the week should not be included in a stored timestamp since it is easy to compute.
-
-#### RFC 1918—Address allocation for private internets
-
-There's the internet that's everyone's and then there's the internet that's just yours. Private networks are used all the time, and [RFC 1918][5] defines those networks. Sure, you could set up your router to route public spaces internally, but that's a bad idea. Alternately, you could take your unused public IP addresses and treat them as an internal network. In either case, you're making it clear you've never read RFC 1918.
-
-#### RFC 1912—Common DNS operational and configuration errors
-
-Everything is a #@%@ DNS problem, right? [RFC 1912][6] lays out mistakes that admins make when they're just trying to keep the internet running. Although it was published in 1996, DNS (and the mistakes people make with it) hasn't really changed all that much. To understand why we need DNS in the first place, consider what [RFC 289—What we hope is an official list of host names][7] would look like today.
-
-#### RFC 2822—Internet message format
-
-Think you know what a valid email address looks like? If the number of sites that won't accept a "+" in my address is any indication, you don't. [RFC 2822][8] defines what a valid email address looks like. It also goes into detail about the rest of an email message.
-
-#### RFC 7231—Hypertext Transfer Protocol (HTTP/1.1): Semantics and content
-
-When you stop to think about it, almost everything we do online relies on HTTP. [RFC 7231][9] is among the most recent updates to that protocol. Weighing in at just over 100 pages, it defines methods, headers, and status codes.
-
-### 3 should-read RFCs
-
-Okay, not every RFC is serious business.
-
-#### RFC 1149—A standard for the transmission of IP datagrams on avian carriers
-
-Networks pass packets in many different ways. [RFC 1149][10] describes the use of carrier pigeons. They can't be any less reliable than my mobile provider when I'm more than a mile away from an interstate highway.
-
-#### RFC 2324—Hypertext coffee pot control protocol (HTCPCP/1.0)
-
-Coffee is very important to getting work done, so of course, we need a programmatic interface for managing our coffee pots. [RFC 2324][11] defines a protocol for interacting with coffee pots and adds HTTP 418 ("I am a teapot").
-
-#### RFC 69—Distribution list change for M.I.T.
-
-Is [RFC 69][12] the first published example of a misdirected unsubscribe request?
-
-What are your must-read RFCs (whether they're serious or not)? Share your list in the comments.
-
---------------------------------------------------------------------------------
-
-via: https://opensource.com/article/18/7/requests-for-comments-to-know
-
-作者:[Ben Cotton][a]
-选题:[lujun9972](https://github.com/lujun9972)
-译者:[译者ID](https://github.com/译者ID)
-校对:[校对者ID](https://github.com/校对者ID)
-
-本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
-
-[a]:https://opensource.com/users/bcotton
-[1]:https://www.ietf.org
-[2]:https://www.rfc-editor.org/rfc/rfc2119.txt
-[3]:https://www.rfc-editor.org/rfc/rfc3339.txt
-[4]:https://www.iso.org/iso-8601-date-and-time-format.html
-[5]:https://www.rfc-editor.org/rfc/rfc1918.txt
-[6]:https://www.rfc-editor.org/rfc/rfc1912.txt
-[7]:https://www.rfc-editor.org/rfc/rfc289.txt
-[8]:https://www.rfc-editor.org/rfc/rfc2822.txt
-[9]:https://www.rfc-editor.org/rfc/rfc7231.txt
-[10]:https://www.rfc-editor.org/rfc/rfc1149.txt
-[11]:https://www.rfc-editor.org/rfc/rfc2324.txt
-[12]:https://www.rfc-editor.org/rfc/rfc69.txt
diff --git a/sources/tech/20180710 How To View Detailed Information About A Package In Linux.md b/sources/tech/20180710 How To View Detailed Information About A Package In Linux.md
new file mode 100644
index 0000000000..60c929b789
--- /dev/null
+++ b/sources/tech/20180710 How To View Detailed Information About A Package In Linux.md
@@ -0,0 +1,404 @@
+How To View Detailed Information About A Package In Linux
+======
+This is know topic and we can write so many articles because most of the time we would stick with package managers for many reasons.
+
+Each distribution clones has their own package manager, each has comes with their unique features that allow users to perform many actions such as installing new software packages, removing unnecessary software packages, updating the existing software packages, searching for specific software packages, and updating the system to latest available version, etc.
+
+Whoever is sticking with command-line most of the time they would preferring the CLI based package managers. The major CLI package managers for Linux are Yum, Dnf, Rpm,Apt, Apt-Get, Deb, pacman and zypper.
+
+**Suggested Read :**
+**(#)** [List of Command line Package Managers For Linux & Usage][1]
+**(#)** [A Graphical frontend tool for Linux Package Manager][2]
+**(#)** [How To Search If A Package Is Available On Your Linux Distribution Or Not][3]
+**(#)** [How To Add, Enable And Disable A Repository By Using The DNF/YUM Config Manager Command On Linux][4]
+
+As a system administrator you should aware of from where packages are coming, which repository, version of the package, size of the package, release, package source url, license info, etc,.
+
+This will help you to understand the package usage in simple way since it’s coming with package summary & Description. Run the below commands based on your distribution to get detailed information about given package.
+
+### [YUM Command][5] : View Package Information On RHEL & CentOS Systems
+
+YUM stands for Yellowdog Updater, Modified is an open-source command-line front-end package-management utility for RPM based systems such as Red Hat Enterprise Linux (RHEL) and CentOS.
+
+Yum is the primary tool for getting, installing, deleting, querying, and managing RPM packages from distribution repositories, as well as other third-party repositories.
+```
+# yum info python
+Loaded plugins: fastestmirror, security
+Loading mirror speeds from cached hostfile
+ * epel: epel.mirror.constant.com
+Installed Packages
+Name : python
+Arch : x86_64
+Version : 2.6.6
+Release : 66.el6_8
+Size : 78 k
+Repo : installed
+From repo : updates
+Summary : An interpreted, interactive, object-oriented programming language
+URL : http://www.python.org/
+License : Python
+Description : Python is an interpreted, interactive, object-oriented programming
+ : language often compared to Tcl, Perl, Scheme or Java. Python includes
+ : modules, classes, exceptions, very high level dynamic data types and
+ : dynamic typing. Python supports interfaces to many system calls and
+ : libraries, as well as to various windowing systems (X11, Motif, Tk,
+ : Mac and MFC).
+ :
+ : Programmers can write new built-in modules for Python in C or C++.
+ : Python can be used as an extension language for applications that need
+ : a programmable interface.
+ :
+ : Note that documentation for Python is provided in the python-docs
+ : package.
+ :
+ : This package provides the "python" executable; most of the actual
+ : implementation is within the "python-libs" package.
+
+```
+
+### YUMDB Command : View Package Information On RHEL & CentOS Systems
+
+Yumdb info provides information similar to yum info but additionally it provides package checksum data, type, user info (who installed the package). Since yum 3.2.26 yum has started storing additional information outside of the rpmdatabase (where user indicates it was installed by the user, and dep means it was brought in as a dependency).
+```
+# yumdb info python
+Loaded plugins: fastestmirror
+python-2.6.6-66.el6_8.x86_64
+ changed_by = 4294967295
+ checksum_data = 53c75a1756e5b4f6564c5229a37948c9b4561e0bf58076bd7dab7aff85a417f2
+ checksum_type = sha256
+ command_line = update -y
+ from_repo = updates
+ from_repo_revision = 1488370672
+ from_repo_timestamp = 1488371100
+ installed_by = 4294967295
+ reason = dep
+ releasever = 6
+
+
+```
+
+### [RPM Command][6] : View Package Information On RHEL/CentOS/Fedora Systems
+
+RPM stands for Red Hat Package Manager is a powerful, command line Package Management utility for Red Hat based system such as (RHEL, CentOS, Fedora, openSUSE & Mageia) distributions. The utility allow you to install, upgrade, remove, query & verify the software on your Linux system/server. RPM files comes with .rpm extension. RPM package built with required libraries and dependency which will not conflicts other packages were installed on your system.
+```
+# rpm -qi nano
+Name : nano Relocations: (not relocatable)
+Version : 2.0.9 Vendor: CentOS
+Release : 7.el6 Build Date: Fri 12 Nov 2010 02:18:36 AM EST
+Install Date: Fri 03 Mar 2017 08:57:47 AM EST Build Host: c5b2.bsys.dev.centos.org
+Group : Applications/Editors Source RPM: nano-2.0.9-7.el6.src.rpm
+Size : 1588347 License: GPLv3+
+Signature : RSA/8, Sun 03 Jul 2011 12:46:50 AM EDT, Key ID 0946fca2c105b9de
+Packager : CentOS BuildSystem
+URL : http://www.nano-editor.org
+Summary : A small text editor
+Description :
+GNU nano is a small and friendly text editor.
+
+```
+
+### [DNF Command][7] : View Package Information On Fedora System
+
+DNF stands for Dandified yum. We can tell DNF, the next generation of yum package manager (Fork of Yum) using hawkey/libsolv library for backend. Aleš Kozumplík started working on DNF since Fedora 18 and its implemented/launched in Fedora 22 finally. Dnf command is used to install, update, search & remove packages on Fedora 22 and later system. It automatically resolve dependencies and make it smooth package installation without any trouble.
+```
+$ dnf info tilix
+Last metadata expiration check: 27 days, 10:00:23 ago on Wed 04 Oct 2017 06:43:27 AM IST.
+Installed Packages
+Name : tilix
+Version : 1.6.4
+Release : 1.fc26
+Arch : x86_64
+Size : 3.6 M
+Source : tilix-1.6.4-1.fc26.src.rpm
+Repo : @System
+From repo : @commandline
+Summary : Tiling terminal emulator
+URL : https://github.com/gnunn1/tilix
+License : MPLv2.0 and GPLv3+ and CC-BY-SA
+Description : Tilix is a tiling terminal emulator with the following features:
+ :
+ : - Layout terminals in any fashion by splitting them horizontally or vertically
+ : - Terminals can be re-arranged using drag and drop both within and between
+ : windows
+ : - Terminals can be detached into a new window via drag and drop
+ : - Input can be synchronized between terminals so commands typed in one
+ : terminal are replicated to the others
+ : - The grouping of terminals can be saved and loaded from disk
+ : - Terminals support custom titles
+ : - Color schemes are stored in files and custom color schemes can be created by
+ : simply creating a new file
+ : - Transparent background
+ : - Supports notifications when processes are completed out of view
+ :
+ : The application was written using GTK 3 and an effort was made to conform to
+ : GNOME Human Interface Guidelines (HIG).
+
+```
+
+### [Zypper Command][8] : View Package Information On openSUSE System
+
+Zypper is a command line package manager which makes use of libzypp. Zypper provides functions like repository access, dependency solving, package installation, etc.
+```
+$ zypper info nano
+
+Loading repository data...
+Reading installed packages...
+
+
+Information for package nano:
+-----------------------------
+Repository : Main Repository (OSS)
+Name : nano
+Version : 2.4.2-5.3
+Arch : x86_64
+Vendor : openSUSE
+Installed Size : 1017.8 KiB
+Installed : No
+Status : not installed
+Source package : nano-2.4.2-5.3.src
+Summary : Pico editor clone with enhancements
+Description :
+ GNU nano is a small and friendly text editor. It aims to emulate
+ the Pico text editor while also offering a few enhancements.
+
+```
+
+### [pacman Command][9] : View Package Information On Arch Linux & Manjaro Systems
+
+Pacman stands for package manager utility. pacman is a simple command-line utility to install, build, remove and manage Arch Linux packages. Pacman uses libalpm (Arch Linux Package Management (ALPM) library) as a back-end to perform all the actions.
+```
+$ pacman -Qi bash
+Name : bash
+Version : 4.4.012-2
+Description : The GNU Bourne Again shell
+Architecture : x86_64
+URL : http://www.gnu.org/software/bash/bash.html
+Licenses : GPL
+Groups : base
+Provides : sh
+Depends On : readline>=7.0 glibc ncurses
+Optional Deps : bash-completion: for tab completion
+Required By : autoconf automake bison bzip2 ca-certificates-utils db
+ dhcpcd diffutils e2fsprogs fakeroot figlet findutils
+ flex freetype2 gawk gdbm gettext gmp grub gzip icu
+ iptables keyutils libgpg-error libksba libpcap libpng
+ libtool lvm2 m4 man-db mkinitcpio nano neofetch nspr
+ nss openresolv os-prober pacman pcre pcre2 shadow
+ systemd texinfo vte-common which xdg-user-dirs xdg-utils
+ xfsprogs xorg-mkfontdir xorg-xpr xz
+Optional For : None
+Conflicts With : None
+Replaces : None
+Installed Size : 7.13 MiB
+Packager : Jan Alexander Steffens (heftig)
+Build Date : Tue 14 Feb 2017 01:16:51 PM UTC
+Install Date : Thu 24 Aug 2017 06:08:12 AM UTC
+Install Reason : Explicitly installed
+Install Script : No
+Validated By : Signature
+
+```
+
+### [Apt-Cache Command][10] : View Package Information On Debian/Ubuntu/Mint Systems
+
+The apt-cache command can display much of the information stored in APT’s internal database. This information is a sort of cache since it is gathered from the different sources listed in the sources.list file. This happens during the apt update operation.
+```
+$ sudo apt-cache show apache2
+Package: apache2
+Priority: optional
+Section: web
+Installed-Size: 473
+Maintainer: Ubuntu Developers
+Original-Maintainer: Debian Apache Maintainers
+Architecture: amd64
+Version: 2.4.12-2ubuntu2
+Replaces: apache2.2-common
+Provides: httpd, httpd-cgi
+Depends: lsb-base, procps, perl, mime-support, apache2-bin (= 2.4.12-2ubuntu2), apache2-utils (>= 2.4), apache2-data (= 2.4.12-2ubuntu2)
+Pre-Depends: dpkg (>= 1.17.14)
+Recommends: ssl-cert
+Suggests: www-browser, apache2-doc, apache2-suexec-pristine | apache2-suexec-custom, ufw
+Conflicts: apache2.2-common (<< 2.3~)
+Filename: pool/main/a/apache2/apache2_2.4.12-2ubuntu2_amd64.deb
+Size: 91348
+MD5sum: ab0ee0b0d1c6b3d19bd87aa2a9537125
+SHA1: 350c9a1a954906088ed032aebb77de3d5bb24004
+SHA256: 03f515f7ebc3b67b050b06e82ebca34b5e83e34a528868498fce020bf1dbbe34
+Description-en: Apache HTTP Server
+ The Apache HTTP Server Project's goal is to build a secure, efficient and
+ extensible HTTP server as standards-compliant open source software. The
+ result has long been the number one web server on the Internet.
+ .
+ Installing this package results in a full installation, including the
+ configuration files, init scripts and support scripts.
+Description-md5: d02426bc360345e5acd45367716dc35c
+Homepage: http://httpd.apache.org/
+Bugs: https://bugs.launchpad.net/ubuntu/+filebug
+Origin: Ubuntu
+Supported: 9m
+Task: lamp-server, mythbuntu-frontend, mythbuntu-desktop, mythbuntu-backend-slave, mythbuntu-backend-master, mythbuntu-backend-master
+
+```
+
+### [APT Command][11] : View Package Information On Debian/Ubuntu/Mint Systems
+
+APT stands for Advanced Packaging Tool (APT) which is replacement for apt-get, like how DNF came to picture instead of YUM. It’s feature rich command-line tools with included all the futures in one command (APT) such as apt-cache, apt-search, dpkg, apt-cdrom, apt-config, apt-key, etc..,. and several other unique features. For example we can easily install .dpkg packages through APT but we can’t do through Apt-Get similar more features are included into APT command. APT-GET replaced by APT Due to lock of futures missing in apt-get which was not solved.
+```
+$ apt show nano
+Package: nano
+Version: 2.8.6-3
+Priority: standard
+Section: editors
+Origin: Ubuntu
+Maintainer: Ubuntu Developers
+Original-Maintainer: Jordi Mallach
+Bugs: https://bugs.launchpad.net/ubuntu/+filebug
+Installed-Size: 766 kB
+Depends: libc6 (>= 2.14), libncursesw5 (>= 6), libtinfo5 (>= 6)
+Suggests: spell
+Conflicts: pico
+Breaks: nano-tiny (<< 2.8.6-2)
+Replaces: nano-tiny (<< 2.8.6-2), pico
+Homepage: https://www.nano-editor.org/
+Task: standard, ubuntu-touch-core, ubuntu-touch
+Supported: 9m
+Download-Size: 222 kB
+APT-Manual-Installed: yes
+APT-Sources: http://in.archive.ubuntu.com/ubuntu artful/main amd64 Packages
+Description: small, friendly text editor inspired by Pico
+ GNU nano is an easy-to-use text editor originally designed as a replacement
+ for Pico, the ncurses-based editor from the non-free mailer package Pine
+ (itself now available under the Apache License as Alpine).
+ .
+ However, GNU nano also implements many features missing in pico, including:
+ - undo/redo
+ - line numbering
+ - syntax coloring
+ - soft-wrapping of overlong lines
+ - selecting text by holding Shift
+ - interactive search and replace (with regular expression support)
+ - a go-to line (and column) command
+ - support for multiple file buffers
+ - auto-indentation
+ - tab completion of filenames and search terms
+ - toggling features while running
+ - and full internationalization support
+
+```
+
+### [dpkg Command][12] : View Package Information On Debian/Ubuntu/Mint Systems
+
+dpkg stands for Debian package manager (dpkg). dpkg is a command-line tool to install, build, remove and manage Debian packages. dpkg uses Aptitude (primary and more user-friendly) as a front-end to perform all the actions. Other utility such as dpkg-deb and dpkg-query uses dpkg as a front-end to perform some action. Now a days most of the administrator using Apt, Apt-Get & Aptitude to manage packages easily without headache and its robust management too. Even though still we need to use dpkg to perform some software installation where it’s necessary.
+```
+$ dpkg -s python
+Package: python
+Status: install ok installed
+Priority: optional
+Section: python
+Installed-Size: 626
+Maintainer: Ubuntu Developers
+Architecture: amd64
+Multi-Arch: allowed
+Source: python-defaults
+Version: 2.7.14-2ubuntu1
+Replaces: python-dev (<< 2.6.5-2)
+Provides: python-ctypes, python-email, python-importlib, python-profiler, python-wsgiref
+Depends: python2.7 (>= 2.7.14-1~), libpython-stdlib (= 2.7.14-2ubuntu1)
+Pre-Depends: python-minimal (= 2.7.14-2ubuntu1)
+Suggests: python-doc (= 2.7.14-2ubuntu1), python-tk (>= 2.7.14-1~)
+Breaks: update-manager-core (<< 0.200.5-2)
+Conflicts: python-central (<< 0.5.5)
+Description: interactive high-level object-oriented language (default version)
+ Python, the high-level, interactive object oriented language,
+ includes an extensive class library with lots of goodies for
+ network programming, system administration, sounds and graphics.
+ .
+ This package is a dependency package, which depends on Debian's default
+ Python version (currently v2.7).
+Homepage: http://www.python.org/
+Original-Maintainer: Matthias Klose
+
+```
+
+Alternatively we can use `-p` option with dpkg that provides information similar to `dpkg -s` info but additionally it provides package checksum data and type.
+```
+$ dpkg -p python3
+Package: python3
+Priority: important
+Section: python
+Installed-Size: 67
+Origin: Ubuntu
+Maintainer: Ubuntu Developers
+Bugs: https://bugs.launchpad.net/ubuntu/+filebug
+Architecture: amd64
+Multi-Arch: allowed
+Source: python3-defaults
+Version: 3.6.3-0ubuntu2
+Replaces: python3-minimal (<< 3.1.2-2)
+Provides: python3-profiler
+Depends: python3.6 (>= 3.6.3-1~), libpython3-stdlib (= 3.6.3-0ubuntu2), dh-python
+Pre-Depends: python3-minimal (= 3.6.3-0ubuntu2)
+Suggests: python3-doc (>= 3.6.3-0ubuntu2), python3-tk (>= 3.6.3-1~), python3-venv (>= 3.6.3-0ubuntu2)
+Filename: pool/main/p/python3-defaults/python3_3.6.3-0ubuntu2_amd64.deb
+Size: 8712
+MD5sum: a8bae494c6e5d1896287675faf40d373
+Description: interactive high-level object-oriented language (default python3 version)
+Original-Maintainer: Matthias Klose
+SHA1: 2daec885cea7d4dc83c284301c3bebf42b23e095
+SHA256: 865e509c91d2504a16c4b573dbe27e260c36fceec2add3fa43a30c1751d7e9bb
+Homepage: http://www.python.org/
+Task: minimal, ubuntu-core, ubuntu-core
+Description-md5: 950ebd8122c0a7340f0a740c295b9eab
+Supported: 9m
+
+```
+
+### Aptitude Command : View Package Information On Debian/Ubuntu/Mint Systems
+
+aptitude is a text-based interface to the Debian GNU/Linux package system. It allows the user to view the list of packages and to perform package management tasks such as installing, upgrading, and removing packages. Actions may be performed from a visual interface or from the command-line.
+```
+$ aptitude show htop
+Package: htop
+Version: 2.0.2-1
+State: installed
+Automatically installed: no
+Priority: optional
+Section: universe/utils
+Maintainer: Ubuntu Developers
+Architecture: amd64
+Uncompressed Size: 216 k
+Depends: libc6 (>= 2.15), libncursesw5 (>= 6), libtinfo5 (>= 6)
+Suggests: lsof, strace
+Conflicts: htop:i386
+Description: interactive processes viewer
+ Htop is an ncursed-based process viewer similar to top, but it allows one to scroll the list vertically and horizontally to see all processes and their full command lines.
+
+ Tasks related to processes (killing, renicing) can be done without entering their PIDs.
+Homepage: http://hisham.hm/htop/
+
+```
+
+--------------------------------------------------------------------------------
+
+via: https://www.2daygeek.com/how-to-view-detailed-information-about-a-package-in-linux/
+
+作者:[Prakash Subramanian][a]
+选题:[lujun9972](https://github.com/lujun9972)
+译者:[译者ID](https://github.com/译者ID)
+校对:[校对者ID](https://github.com/校对者ID)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://www.2daygeek.com/author/prakash/
+[1]:https://www.2daygeek.com/list-of-command-line-package-manager-for-linux/
+[2]:https://www.2daygeek.com/list-of-graphical-frontend-tool-for-linux-package-manager/
+[3]:https://www.2daygeek.com/how-to-search-if-a-package-is-available-on-your-linux-distribution-or-not/
+[4]:https://www.2daygeek.com/how-to-add-enable-disable-a-repository-dnf-yum-config-manager-on-linux/
+[5]:https://www.2daygeek.com/yum-command-examples-manage-packages-rhel-centos-systems/
+[6]:https://www.2daygeek.com/rpm-command-examples/
+[7]:https://www.2daygeek.com/dnf-command-examples-manage-packages-fedora-system/
+[8]:https://www.2daygeek.com/zypper-command-examples-manage-packages-opensuse-system/
+[9]:https://www.2daygeek.com/pacman-command-examples-manage-packages-arch-linux-system/
+[10]:https://www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/
+[11]:https://www.2daygeek.com/apt-command-examples-manage-packages-debian-ubuntu-systems/
+[12]:https://www.2daygeek.com/dpkg-command-to-manage-packages-on-debian-ubuntu-linux-mint-systems/
diff --git a/sources/tech/20180710 Python Sets What Why and How.md b/sources/tech/20180710 Python Sets What Why and How.md
new file mode 100644
index 0000000000..32e0f6eda8
--- /dev/null
+++ b/sources/tech/20180710 Python Sets What Why and How.md
@@ -0,0 +1,394 @@
+MjSeven is translating
+
+
+Python Sets: What, Why and How
+============================================================
+
+posted on 07/10/2018 by [wilfredinni][5]
+
+![Python Sets: What, Why and How](https://raw.githubusercontent.com/wilfredinni/pysheetComments/master/2018-july/python_sets/sets.png)
+
+Python comes equipped with several built-in data types to help us organize our data. These structures include lists, dictionaries, tuples and sets.
+
+From the Python 3 documentation:
+
+> A set is an _unordered collection_ with no _duplicate elements_ . Basic uses include _membership testing_ and _eliminating duplicate entries_ . Set objects also support mathematical operations like _union_ , _intersection_ , _difference_ , and _symmetric difference_ .
+
+In this article, we are going to review and see examples of every one of the elements listed in the above definition. Let's start right away and see how we can create them.
+
+### Initializing a Set
+
+There are two ways to create a set: one is to provide the built-in function `set()` with a list of elements, and the other is to use the curly braces `{}`.
+
+Initializing a set using the `set()` built-in function:
+
+```
+>>> s1 = set([1, 2, 3])
+>>> s1
+{1, 2, 3}
+>>> type(s1)
+
+
+```
+
+Initializing a set using curly braces `{}`
+
+```
+>>> s2 = {3, 4, 5}
+>>> s2
+{3, 4, 5}
+>>> type(s2)
+
+>>>
+
+```
+
+As you can see, both options are valid. The problem comes when what we want is an empty one:
+
+```
+>>> s = {}
+>>> type(s)
+
+
+```
+
+That's right, we will get a dictionary instead of a set if we use empty curly braces =)
+
+It's a good moment to mention that for the sake of simplicity, all the examples provided in this article will use single digit integers, but sets can have all the [hashable][6] data types that Python support. In other words, integers, strings and tuples, but not _mutable_ items like _lists_ or _dictionaries_ :
+
+```
+>>> s = {1, 'coffee', [4, 'python']}
+Traceback (most recent call last):
+ File "", line 1, in
+TypeError: unhashable type: 'list'
+
+```
+
+Now that you know how to create a set and what type of elements it can contain, let's continue and see _why_ we should always have them in our toolkit.
+
+### Why You Should Use Them
+
+When writing code, you can do it in more than a single way. Some are considered to be pretty bad, and others, _clear, concise and maintainable_ . Or " [_pythonic_][7] ".
+
+From the [The Hitchhiker’s Guide to Python][8]:
+
+> When a veteran Python developer (a Pythonista) calls portions of code not “Pythonic”, they usually mean that these lines of code do not follow the common guidelines and fail to express its intent in what is considered the best (hear: most readable) way.
+
+Let's start exploring the way that Python sets can help us not just with readability, but also speeding up our programs execution time.
+
+### Unordered Collection of Elements
+
+First things first: you can't access a set element using indexes.
+
+```
+>>> s = {1, 2, 3}
+>>> s[0]
+Traceback (most recent call last):
+ File "", line 1, in
+TypeError: 'set' object does not support indexing
+
+```
+
+Or modify them with slices:
+
+```
+>>> s[0:2]
+Traceback (most recent call last):
+ File "", line 1, in
+TypeError: 'set' object is not subscriptable
+
+```
+
+BUT, if what we need is to remove duplicates, or do mathematical operations like combining lists (unions), we can, and _SHOULD_ always use Sets.
+
+I have to mention that when iterating over, sets are outperformed by lists, so prefer them if that is what you need. Why? well, this article does not intend to explain the inner workings of sets, but if you are interested, here are a couple of links where you can read about it:
+
+* [TimeComplexity][1]
+
+* [How is set() implemented?][2]
+
+* [Python Sets vs Lists][3]
+
+* [Is there any advantage or disadvantage to using sets over list comps to ensure a list of unique entries?][4]
+
+### No Duplicate Items
+
+While writing this I cannot stop thinking in all the times I used the _for_ loop and the _if_ statement to check and remove duplicate elements in a list. My face turns red remembering that, more than once, I wrote something like this:
+
+```
+>>> my_list = [1, 2, 3, 2, 3, 4]
+>>> no_duplicate_list = []
+>>> for item in my_list:
+... if item not in no_duplicate_list:
+... no_duplicate_list.append(item)
+...
+>>> no_duplicate_list
+[1, 2, 3, 4]
+
+```
+
+Or used a list comprehension:
+
+```
+>>> my_list = [1, 2, 3, 2, 3, 4]
+>>> no_duplicate_list = []
+>>> [no_duplicate_list.append(item) for item in my_list if item not in no_duplicate_list]
+[None, None, None, None]
+>>> no_duplicate_list
+[1, 2, 3, 4]
+
+```
+
+But it's ok, nothing of that matters anymore because we now have the sets in our arsenal:
+
+```
+>>> my_list = [1, 2, 3, 2, 3, 4]
+>>> no_duplicate_list = list(set(my_list))
+>>> no_duplicate_list
+[1, 2, 3, 4]
+>>>
+
+```
+
+Now let's use the _timeit_ module and see the excecution time of lists and sets when removing duplicates:
+
+```
+>>> from timeit import timeit
+>>> def no_duplicates(list):
+... no_duplicate_list = []
+... [no_duplicate_list.append(item) for item in list if item not in no_duplicate_list]
+... return no_duplicate_list
+...
+>>> # first, let's see how the list perform:
+>>> print(timeit('no_duplicates([1, 2, 3, 1, 7])', globals=globals(), number=1000))
+0.0018683355819786227
+
+```
+
+```
+>>> from timeit import timeit
+>>> # and the set:
+>>> print(timeit('list(set([1, 2, 3, 1, 2, 3, 4]))', number=1000))
+0.0010220493243764395
+>>> # faster and cleaner =)
+
+```
+
+Not only we write _fewer lines_ with sets than with lists comprehensions, we also obtain more _readable_ and _performant_ code.
+
+Note: remember that sets are unordered, so there is no guarantee that when converting them back to a list the order of the elements is going to be preserved.
+
+From the [Zen of Python][9]:
+
+> Beautiful is better than ugly.
+> Explicit is better than implicit.
+> Simple is better than complex.
+> Flat is better than nested.
+
+Aren't sets just Beautiful, Explicit, Simple and Flat? =)
+
+### Membership Tests
+
+Every time we use an _if_ statement to check if an element is, for example, in a list, you are doing a membership test:
+
+```
+my_list = [1, 2, 3]
+>>> if 2 in my_list:
+... print('Yes, this is a membership test!')
+...
+Yes, this is a membership test!
+
+```
+
+And sets are more performant than lists when doing them:
+
+```
+>>> from timeit import timeit
+>>> def in_test(iterable):
+... for i in range(1000):
+... if i in iterable:
+... pass
+...
+>>> timeit('in_test(iterable)',
+... setup="from __main__ import in_test; iterable = list(range(1000))",
+... number=1000)
+12.459663048726043
+
+```
+
+```
+>>> from timeit import timeit
+>>> def in_test(iterable):
+... for i in range(1000):
+... if i in iterable:
+... pass
+...
+>>> timeit('in_test(iterable)',
+... setup="from __main__ import in_test; iterable = set(range(1000))",
+... number=1000)
+0.12354438152988223
+>>>
+
+```
+
+Note: the above tests come from [this][10] StackOverflow thread.
+
+So if you are doing comparisons like this in huge lists, it should speed you a good bit if you convert that list into a set.
+
+### How to Use Them
+
+Now that you know what a set is and why you should use them, let's do a quick tour and see how can we modify and operate with them.
+
+### Adding Elements
+
+Depending on the number of elements to add, we will have to choose between the `add()` and `update()` methods.
+
+`add()` will add a single element:
+
+```
+>>> s = {1, 2, 3}
+>>> s.add(4)
+>>> s
+{1, 2, 3, 4}
+
+```
+
+And `update()` multiple ones:
+
+```
+>>> s = {1, 2, 3}
+>>> s.update([2, 3, 4, 5, 6])
+>>> s
+{1, 2, 3, 4, 5, 6}
+
+```
+
+Remember, sets remove duplicates.
+
+### Removing Elements
+
+If you want to be alerted when your code tries to remove an element that is not in the set, use `remove()`. Otherwise, `discard()` provides a good alternative:
+
+```
+>>> s = {1, 2, 3}
+>>> s.remove(3)
+>>> s
+{1, 2}
+>>> s.remove(3)
+Traceback (most recent call last):
+ File "", line 1, in
+KeyError: 3
+
+```
+
+`discard()` won't raise any errors:
+
+```
+>>> s = {1, 2, 3}
+>>> s.discard(3)
+>>> s
+{1, 2}
+>>> s.discard(3)
+>>> # nothing happens!
+
+```
+
+We can also use `pop()` to randomly discard an element:
+
+```
+>>> s = {1, 2, 3, 4, 5}
+>>> s.pop() # removes an arbitrary element
+1
+>>> s
+{2, 3, 4, 5}
+
+```
+
+Or `clear()` to remove all the values from a set:
+
+```
+>>> s = {1, 2, 3, 4, 5}
+>>> s.clear() # discard all the items
+>>> s
+set()
+
+```
+
+### union()
+
+`union()` or `|` will create a new set that contains all the elements from the sets we provide:
+
+```
+>>> s1 = {1, 2, 3}
+>>> s2 = {3, 4, 5}
+>>> s1.union(s2) # or 's1 | s2'
+{1, 2, 3, 4, 5}
+
+```
+
+### intersection()
+
+`intersection` or `&` will return a set containing only the elements that are common in all of them:
+
+```
+>>> s1 = {1, 2, 3}
+>>> s2 = {2, 3, 4}
+>>> s3 = {3, 4, 5}
+>>> s1.intersection(s2, s3) # or 's1 & s2 & s3'
+{3}
+
+```
+
+### difference()
+
+Using `diference()` or `-`, creates a new set with the values that are in "s1" but not in "s2":
+
+```
+>>> s1 = {1, 2, 3}
+>>> s2 = {2, 3, 4}
+>>> s1.difference(s2) # or 's1 - s2'
+{1}
+
+```
+
+### symmetric_diference()
+
+`symetric_difference` or `^` will return all the values that are not common between the sets.
+
+```
+>>> s1 = {1, 2, 3}
+>>> s2 = {2, 3, 4}
+>>> s1.symmetric_difference(s2) # or 's1 ^ s2'
+{1, 4}
+
+```
+
+### Conclusions
+
+I hope that after reading this article you know what a set is, how to manipulate their elements and the operations they can perform. Knowing when to use a set will definitely help you write cleaner code and speed up your programs.
+
+If you have any doubts, please leave a comment and I will gladly try to answer them. Also, don´t forget that if you already understand sets, they have their own [place][11] in the [Python Cheatsheet][12], where you can have a quick reference and refresh what you already know.
+
+--------------------------------------------------------------------------------
+
+via: https://www.pythoncheatsheet.org/blog/python-sets-what-why-how
+
+作者:[wilfredinni][a]
+译者:[译者ID](https://github.com/译者ID)
+校对:[校对者ID](https://github.com/校对者ID)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://www.pythoncheatsheet.org/author/wilfredinni
+[1]:https://wiki.python.org/moin/TimeComplexity
+[2]:https://stackoverflow.com/questions/3949310/how-is-set-implemented
+[3]:https://stackoverflow.com/questions/2831212/python-sets-vs-lists
+[4]:https://mail.python.org/pipermail/python-list/2011-June/606738.html
+[5]:https://www.pythoncheatsheet.org/author/wilfredinni
+[6]:https://docs.python.org/3/glossary.html#term-hashable
+[7]:http://docs.python-guide.org/en/latest/writing/style/
+[8]:http://docs.python-guide.org/en/latest/
+[9]:https://www.python.org/dev/peps/pep-0020/
+[10]:https://stackoverflow.com/questions/2831212/python-sets-vs-lists
+[11]:https://www.pythoncheatsheet.org/#sets
+[12]:https://www.pythoncheatsheet.org/
diff --git a/sources/tech/20180711 4 add-ons to improve your privacy on Thunderbird.md b/sources/tech/20180711 4 add-ons to improve your privacy on Thunderbird.md
index 980f7082aa..05057f6669 100644
--- a/sources/tech/20180711 4 add-ons to improve your privacy on Thunderbird.md
+++ b/sources/tech/20180711 4 add-ons to improve your privacy on Thunderbird.md
@@ -1,3 +1,5 @@
+translating---geekpi
+
4 add-ons to improve your privacy on Thunderbird
======
diff --git a/translated/tech/20180430 3 practical Python tools- magic methods, iterators and generators, and method magic.md b/translated/tech/20180430 3 practical Python tools- magic methods, iterators and generators, and method magic.md
new file mode 100644
index 0000000000..21f386df00
--- /dev/null
+++ b/translated/tech/20180430 3 practical Python tools- magic methods, iterators and generators, and method magic.md
@@ -0,0 +1,536 @@
+3 个实用的 Python 工具:魔术方法,迭代器和生成器,以及方法魔术
+======
+(to 校正者:magic)
+![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/serving-bowl-forks-dinner.png?itok=a3YqPwr5)
+Python 提供了一组独特的工具和语言特性来帮助你使代码更加优雅,可读和直观。通过为正确的问题选择合适的工具,你的代码将更易于维护。在本文中,我们将研究其中的三个工具:魔术方法,迭代器和生成器,以及方法魔术。
+
+### 魔术方法
+
+魔术方法可以看作是 Python 的管道。它们被称为“底层”方法,用于某些内置的方法、符号和操作。你可能熟悉的常见魔术方法是 `__init__()`,当我们想要初始化一个类的新实例时,它会被调用。
+
+你可能已经看过其他常见的魔术方法,如 `__str__` 和 `__repr__`。Python 中有一整套魔术方法,通过实现其中的一些方法,我们可以修改一个对象的行为,甚至使其行为类似于内置数据类型,例如数字,列表或字典。
+
+让我们创建一个 `Money` 类来示例:
+```
+class Money:
+
+ currency_rates = {
+
+ '$': 1,
+
+ '€': 0.88,
+
+ }
+
+ def __init__(self, symbol, amount):
+
+ self.symbol = symbol
+
+ self.amount = amount
+
+ def __repr__(self):
+
+ return '%s%.2f' % (self.symbol, self.amount)
+
+ def convert(self, other):
+
+ """ Convert other amount to our currency """
+
+ new_amount = (
+
+ other.amount / self.currency_rates[other.symbol]
+
+ * self.currency_rates[self.symbol])
+
+ return Money(self.symbol, new_amount)
+
+```
+
+该类定义为给定的符号和汇率定义了一个货币汇率,指定了一个初始化器(也称为构造函数),并实现 `__repr__`,因此当我们打印这个类时,我们会看到一个友好的表示,例如 `$2.00` ,一个带有货币符号和金额的 `Money('$', 2.00)` 实例。最重要的是,它定义了一种方法,允许你使用不同的汇率在不同的货币之间进行转换。
+
+打开 Python shell,假设我们已经定义了使用两种不同货币的食品的成本,如下所示:
+```
+>>> soda_cost = Money('$', 5.25)
+
+>>> soda_cost
+
+ $5.25
+
+>>> pizza_cost = Money('€', 7.99)
+
+>>> pizza_cost
+
+ €7.99
+
+```
+
+我们可以使用魔术方法使得这个类的实例之间可以相互交互。假设我们希望能够将这个类的两个实例一起加在一起,即使它们是不同的货币。为了实现这一点,我们可以在 `Money` 类上实现 `__add__` 这个魔术方法:
+```
+class Money:
+
+ # ... previously defined methods ...
+
+ def __add__(self, other):
+
+ """ Add 2 Money instances using '+' """
+
+ new_amount = self.amount + self.convert(other).amount
+
+ return Money(self.symbol, new_amount)
+
+```
+
+现在我们可以以非常直观的方式使用这个类:
+```
+>>> soda_cost = Money('$', 5.25)
+
+>>> pizza_cost = Money('€', 7.99)
+
+>>> soda_cost + pizza_cost
+
+ $14.33
+
+>>> pizza_cost + soda_cost
+
+ €12.61
+
+```
+
+当我们将两个实例加在一起时,我们得到第一个定义的货币的符号所表示的结果(to 校正者:这里意思是:得到的结果是第一个对象的符号所表示的。)。所有的转换都是在底层无缝完成的。如果我们想的话,我们也可以为减法实现 `__sub__`,为乘法实现 `__mul__` 等等。阅读[模拟数字类型][1]或[魔术方法指南][2]来获得更多信息。
+
+我们学习到 `__add__` 映射到内置运算符 `+`。其他魔术方法可以映射到像 `[]` 这样的符号。例如,在字典中通过索引或键来获得一项,其实是使用了 `__getitem__` 方法:
+```
+>>> d = {'one': 1, 'two': 2}
+
+>>> d['two']
+
+2
+
+>>> d.__getitem__('two')
+
+2
+
+```
+
+一些魔术方法甚至映射到内置函数,例如 `__len__()` 映射到 `len()`。
+```
+class Alphabet:
+
+ letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+
+ def __len__(self):
+
+ return len(self.letters)
+
+>>> my_alphabet = Alphabet()
+
+>>> len(my_alphabet)
+
+ 26
+
+```
+
+### 自定义迭代器
+
+对于新的和经验丰富的 Python 开发者来说,自定义迭代器是一个非常强大的但令人迷惑的主题。
+
+许多内置类型,例如列表、集合和字典,已经实现了允许它们在底层迭代的协议。这使我们可以轻松地遍历它们。
+```
+>>> for food in ['Pizza', 'Fries']:
+
+ print(food + '. Yum!')
+
+Pizza. Yum!
+
+Fries. Yum!
+
+```
+
+我们如何迭代我们自己的自定义类?首先,让我们来澄清一些术语。
+
+ * 要成为一个可迭代对象,一个类需要实现 `__iter__()`
+ * `__iter__()` 方法需要返回一个迭代器
+ * 要成为一个迭代器,一个类需要实现 `__next__()`(或[在 Python 2][3]中是 `next()`),当没有更多的项要迭代时,必须抛出一个 `StopIteration` 异常。
+
+呼!这听起来很复杂,但是一旦你记住了这些基本概念,你就可以在任何时候进行迭代。
+
+我们什么时候想使用自定义迭代器?让我们想象一个场景,我们有一个 `Server` 实例在不同的端口上运行不同的服务,如 `http` 和 `ssh`。其中一些服务处于 `active` 状态,而其他服务则处于 `inactive` 状态。
+```
+class Server:
+
+ services = [
+
+ {'active': False, 'protocol': 'ftp', 'port': 21},
+
+ {'active': True, 'protocol': 'ssh', 'port': 22},
+
+ {'active': True, 'protocol': 'http', 'port': 80},
+
+ ]
+
+```
+
+当我们遍历 `Server` 实例时,我们只想遍历那些处于 `active` 的服务。让我们创建一个 `IterableServer` 类:
+```
+class IterableServer:
+
+ def __init__(self):
+
+ self.current_pos = 0
+
+ def __next__(self):
+
+ pass # TODO: 实现并记得抛出 StopIteration
+
+```
+
+首先,我们将当前位置初始化为 `0`。然后,我们定义一个 `__next__()` 方法来返回下一项。我们还将确保在没有更多项返回时抛出 `StopIteration`。到目前为止都很好!现在,让我们实现这个 `__next__()` 方法。
+```
+class IterableServer:
+
+ def __init__(self):
+
+ self.current_pos = 0. # 我们初始化当前位置为 0
+
+ def __iter__(self): # 我们可以在这里返回 self,因为实现了 __next__
+
+ return self
+
+ def __next__(self):
+
+ while self.current_pos < len(self.services):
+
+ service = self.services[self.current_pos]
+
+ self.current_pos += 1
+
+ if service['active']:
+
+ return service['protocol'], service['port']
+
+ raise StopIteration
+
+ next = __next__ # 可选的 Python2 兼容性
+
+```
+
+我们对列表中的服务进行遍历,而当前的位置小于服务的个数,但只有在服务处于活动状态时才返回。一旦我们遍历完服务,就会抛出一个 `StopIteration` 异常。
+
+因为我们实现了 `__next __()` 方法,当它耗尽时,它会抛出 `StopIteration`。我们可以从 `__iter __()` 返回 `self`,因为 `IterableServer` 类遵循 `iterable` 协议。
+
+现在我们可以遍历一个 `IterableServer` 实例,这将允许我们查看每个处于活动的服务,如下所示:
+```
+>>> for protocol, port in IterableServer():
+
+ print('service %s is running on port %d' % (protocol, port))
+
+service ssh is running on port 22
+
+service http is running on port 21
+
+```
+
+太棒了,但我们可以做得更好!在这样类似的实例中,我们的迭代器不需要维护大量的状态,我们可以简化代码并使用 [generator(生成器)][4] 来代替。
+```
+class Server:
+
+ services = [
+
+ {'active': False, 'protocol': 'ftp', 'port': 21},
+
+ {'active': True, 'protocol': 'ssh', 'port': 22},
+
+ {'active': True, 'protocol': 'http', 'port': 21},
+
+ ]
+
+ def __iter__(self):
+
+ for service in self.services:
+
+ if service['active']:
+
+ yield service['protocol'], service['port']
+
+```
+
+`yield` 关键字到底是什么?在定义生成器函数时使用 yield。这有点像 `return`,虽然 `return` 返回值后退出函数,但 `yield` 会暂停执行直到下次调用它。这允许你的生成器功能在它恢复之前保持状态。查看 [yield 的文档][5]以了解更多信息。使用生成器,我们不必通过记住我们的位置来手动维护状态。生成器只知道两件事:它现在需要做什么以及计算下一个项目需要做什么。一旦我们到达执行点,即 `yield` 不再被调用,我们就知道停止迭代。
+
+这是因为一些内置的 Python 魔法。在 [Python 关于 `__iter__()` 的文档][6]中我们可以看到,如果 `__iter __()` 是作为一个生成器实现的,它将自动返回一个迭代器对象,该对象提供 `__iter __()` 和 `__next __( )` 方法。阅读这篇很棒的文章,深入了解[迭代器,可迭代对象和生成器][7]。
+
+### 方法魔法
+
+由于其独特的方面,Python 提供了一些有趣的方法魔法作为语言的一部分。
+
+其中一个例子是别名功能。因为函数只是对象,所以我们可以将它们赋值给多个变量。例如:
+```
+>>> def foo():
+
+ return 'foo'
+
+>>> foo()
+
+'foo'
+
+>>> bar = foo
+
+>>> bar()
+
+'foo'
+
+```
+
+我们稍后会看到它的作用。
+
+Python 提供了一个方便的内置函数[称为 `getattr()`][8],它接受 `object, name, default` 参数并在 `object` 上返回属性 `name`。这种编程方式允许我们访问实例变量和方法。例如:
+```
+>>> class Dog:
+
+ sound = 'Bark'
+
+ def speak(self):
+
+ print(self.sound + '!', self.sound + '!')
+
+
+>>> fido = Dog()
+
+>>> fido.sound
+
+'Bark'
+
+>>> getattr(fido, 'sound')
+
+'Bark'
+
+>>> fido.speak
+
+>
+
+>>> getattr(fido, 'speak')
+
+>
+
+
+>>> fido.speak()
+
+Bark! Bark!
+
+>>> speak_method = getattr(fido, 'speak')
+
+>>> speak_method()
+
+Bark! Bark!
+
+```
+
+这是一个很酷的技巧,但是我们如何在实际中使用 `getattr` 呢?让我们看一个例子,我们编写一个小型命令行工具来动态处理命令。
+```
+class Operations:
+
+ def say_hi(self, name):
+
+ print('Hello,', name)
+
+ def say_bye(self, name):
+
+ print ('Goodbye,', name)
+
+ def default(self, arg):
+
+ print ('This operation is not supported.')
+
+
+if __name__ == '__main__':
+
+ operations = Operations()
+
+ # 假设我们做了错误处理
+
+ command, argument = input('> ').split()
+
+ func_to_call = getattr(operations, command, operations.default)
+
+ func_to_call(argument)
+
+```
+
+脚本的输出是:
+```
+$ python getattr.py
+
+> say_hi Nina
+
+Hello, Nina
+
+> blah blah
+
+This operation is not supported.
+
+```
+
+接下来,我们来看看 `partial`。例如,**`functool.partial(func, *args, **kwargs)`** 允许你返回一个新的 [partial 对象][9],它的行为类似 `func`,参数是 `args` 和 `kwargs`。如果传入更多的 `args`,它们会被附加到 `args`。如果传入更多的 `kwargs`,它们会扩展并覆盖 `kwargs`。让我们通过一个简短的例子来看看:
+```
+>>> from functools import partial
+
+>>> basetwo = partial(int, base=2)
+
+>>> basetwo
+
+
+
+>>> basetwo('10010')
+
+18
+
+
+# 这等同于
+
+>>> int('10010', base=2)
+
+```
+
+让我们看看这个方法魔术如何在我喜欢的一个[名为 `agithub`][10] 的库中的一些示例代码结合在一起的,这是一个(poorly name)REST API 客户端。它具有透明的语法,允许你以最小的配置快速构建任何 REST API 原型(不仅仅是 GitHub)。我发现这个项目很有趣,因为它非常强大,但只有大约 400 行 Python 代码。你可以在大约 30 行配置代码中添加对任何 REST API 的支持。`agithub` 知道协议所需的一切(`REST`、`HTTP`、`TCP`),但它不考虑上游 API。让我们深入到它的实现中。
+
+以下是我们如何为 GitHub API 和任何其他相关连接属性定义端点 URL 的简化版本。在这里查看[完整代码][11]。
+```
+class GitHub(API):
+
+ def __init__(self, token=None, *args, **kwargs):
+
+ props = ConnectionProperties(api_url = kwargs.pop('api_url', 'api.github.com'))
+
+ self.setClient(Client(*args, **kwargs))
+
+ self.setConnectionProperties(props)
+
+```
+
+然后,一旦配置了[访问令牌][12],就可以开始使用 [GitHub API][13]。
+```
+>>> gh = GitHub('token')
+
+>>> status, data = gh.user.repos.get(visibility='public', sort='created')
+
+>>> # ^ 映射到 GET /user/repos
+
+>>> data
+
+... ['tweeter', 'snipey', '...']
+
+```
+
+请注意,由你决定拼写正确的 URL,因为我们没有验证 URL。如果 URL 不存在或出现了其他任何错误,将返回 API 抛出的错误。那么,这一切是如何运作的呢?让我们找出答案。首先,我们将查看一个 [`API` 类][14]的简化示例:
+```
+class API:
+
+ # ... other methods ...
+
+ def __getattr__(self, key):
+
+ return IncompleteRequest(self.client).__getattr__(key)
+
+ __getitem__ = __getattr__
+
+```
+
+在 `API` 类上的每次调用都会调用 [`IncompleteRequest` 类][15]作为指定的 `key`。
+```
+class IncompleteRequest:
+
+ # ... other methods ...
+
+ def __getattr__(self, key):
+
+ if key in self.client.http_methods:
+
+ htmlMethod = getattr(self.client, key)
+
+ return partial(htmlMethod, url=self.url)
+
+ else:
+
+ self.url += '/' + str(key)
+
+ return self
+
+ __getitem__ = __getattr__
+
+
+class Client:
+
+ http_methods = ('get') # 还有 post, put, patch 等等。
+
+ def get(self, url, headers={}, **params):
+
+ return self.request('GET', url, None, headers)
+
+```
+
+如果最后一次调用不是 HTTP 方法(如 'get'、'post' 等),则返回带有附加路径的 `IncompleteRequest`。否则,它从[ `Client` 类][16]获取 HTTP 方法对应的正确函数,并返回 `partial`。
+
+如果我们给出一个不存在的路径会发生什么?
+```
+>>> status, data = this.path.doesnt.exist.get()
+
+>>> status
+
+... 404
+
+```
+
+因为 `__getattr__` 别名为 `__getitem__`:
+```
+>>> owner, repo = 'nnja', 'tweeter'
+
+>>> status, data = gh.repos[owner][repo].pulls.get()
+
+>>> # ^ Maps to GET /repos/nnja/tweeter/pulls
+
+>>> data
+
+.... # {....}
+
+```
+
+以上是一些认真的方法魔术!(to 校正:这句话真的翻译得不行 )
+
+### 了解更多
+
+Python 提供了大量工具,使你的代码更优雅,更易于阅读和理解。挑战在于找到合适的工具来完成工作,但我希望本文为你的工具箱添加了一些新工具。而且,如果你想更进一步,你可以在我的博客 [nnja.io][17] 上阅读有关装饰器,上下文管理器,上下文生成器和 `NamedTuple(译注:这是命名元组)` 的内容。随着你成为一名更好的 Python 开发人员,我鼓励你到那里阅读一些设计良好的项目的源代码。[Requests][18] 和 [Flask][19] 是两个很好的代码库来开始。
+
+
+
+--------------------------------------------------------------------------------
+
+via: https://opensource.com/article/18/4/elegant-solutions-everyday-python-problems
+
+作者:[Nina Zakharenko][a]
+选题:[lujun9972](https://github.com/lujun9972)
+译者:[MjSeven](https://github.com/MjSeven)
+校对:[校对者ID](https://github.com/校对者ID)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://opensource.com/users/nnja
+[1]:https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types
+[2]:https://rszalski.github.io/magicmethods/
+[3]:https://docs.python.org/2/library/stdtypes.html#iterator.next
+[4]:https://docs.python.org/3/library/stdtypes.html#generator-types
+[5]:https://docs.python.org/3/reference/expressions.html#yieldexpr
+[6]:https://docs.python.org/3/reference/datamodel.html#object.__iter__
+[7]:http://nvie.com/posts/iterators-vs-generators/
+[8]:https://docs.python.org/3/library/functions.html#getattr
+[9]:https://docs.python.org/3/library/functools.html#functools.partial
+[10]:https://github.com/mozilla/agithub
+[11]:https://github.com/mozilla/agithub/blob/master/agithub/GitHub.py
+[12]:https://github.com/settings/tokens
+[13]:https://developer.github.com/v3/repos/#list-your-repositories
+[14]:https://github.com/mozilla/agithub/blob/dbf7014e2504333c58a39153aa11bbbdd080f6ac/agithub/base.py#L30-L58
+[15]:https://github.com/mozilla/agithub/blob/dbf7014e2504333c58a39153aa11bbbdd080f6ac/agithub/base.py#L60-L100
+[16]:https://github.com/mozilla/agithub/blob/dbf7014e2504333c58a39153aa11bbbdd080f6ac/agithub/base.py#L102-L231
+[17]:http://nnja.io
+[18]:https://github.com/requests/requests
+[19]:https://github.com/pallets/flask
+[20]:https://us.pycon.org/2018/schedule/presentation/164/
+[21]:https://us.pycon.org/2018/
diff --git a/translated/tech/20180628 Blockchain evolution- A quick guide and why open source is at the heart of it.md b/translated/tech/20180628 Blockchain evolution- A quick guide and why open source is at the heart of it.md
deleted file mode 100644
index 0dbf96da14..0000000000
--- a/translated/tech/20180628 Blockchain evolution- A quick guide and why open source is at the heart of it.md
+++ /dev/null
@@ -1,97 +0,0 @@
-区块链进化史:一个快速导览和为什么开源是其核心所在
-======
-
-![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/block-quilt-chain.png?itok=mECoDbrc)
-
-当在开源项目的一个新版本上工作时,用后缀 "-ng" 表示 ”下一代“的情况并不鲜见。幸运的是,到目前为止,快速演进的区块链成功地避开了这个命名陷阱。但是在这个开源生态系统的演进过程中,改变是不断发生的,而好的创意被采用、融入、并以典型的开源方式进化到许多不同的项目中。
-
-在本文中,我将审视不同代次的区块链,并且看一看他们在处理生态系统遇到的问题时采用了什么创意。当然,任何对生态系统进行分类的尝试都有其局限性的 —— 和反对者的 —— 但是这也将为混乱的区块链项目提供了一个粗略的指南。
-
-### 始作蛹者:比特币(Bitcoin)
-
-第一代的区块链起源于 [比特币][1] 区块链,以去中心化为基础的总帐,从 [Slashdot][2] 杂集变成主流话题的点对点加密货币。
-
-这个区块链是一个分布式总帐,它对所有用户的事务保持跟踪,以避免它们的货币重复支付(在历史上,这个任务是委托给第三方—— 银行 ——来做的)。为防范攻击者在系统上捣乱,总帐被复制到每个参与到比特币网络的计算机上,并且每次只允许一台计算机去更新总帐。为决定哪台计算机能够获得更新总帐的权力,系统安排在比特币网络上的计算机之间每 10 分钟进行一场竞赛,这将消耗它们的(许多)能源。赢家将获得将前 10 分钟发生的事务写入到总帐(区块链中的“区块”)的权力,并且为赢家写入区块链的工作给予一些比特币奖励。这些设置被称为一个 _工作量证明_ 共识机制。
-
-使用区块链的目标是提升网络中参与者的信任水平。
-
-这就是区块链最有趣的地方。比特币是发布于 2009 年 1 月的一个 [开源项目][3]。在 2010 年,由于意识到这些元素中的许多是可以调整的,围绕比特币聚集起了一个社区 —— [bitcointalk forums][4],来开始各种实验。
-
-起初,看到的比特币区块链是一个分布式数据库的形式, [Namecoin][5] 项目出现后,建议去保存任意数据到它的事务数据库中。如果区块链能够记录金钱的转移,那么它也应该能够记录其它资产的转移,比如域名。这确实是 Namecoin 的主要使用案例,它上线于 2011 年 4 月 —— 也就是比特币出现两年后。
-
-Namecoin 调整的地方是区块链的内容,[莱特币(Litecoin)][6] 调整了两个技术部分:一是将两个区块的时间间隔从 10 分钟减少到 2.5 分钟,二是改变了竞赛方式(用 [scrypt][7] 来替换 SHA-256 安全哈希算法)。这是能够做到的,因为比特币是以开源软件的方式来发布的,而莱特币本质上与比特币在其它部分是完全相同的。莱特币是修改了比特币共识机制的第一个分叉,这也为其它的更多“币”铺平了道路。
-
-沿着这条道路,基于比特币代码库的各种变种越来越多。其中一些扩展了比特币的用途,比如 [Zerocash][8] 协议,它专注于提供交易的匿名性和可替换性,但它最终分拆为它自己的货币 —— [Zcash][9]。
-
-虽然 Zcash 带来了它自己的创新,使用了最近被称为“零知识证明”的加密技术,但它维持着与大多数主要的比特币代码库的兼容性,这意味着它能够从上游的比特币创新中获益。
-
-另外的项目 —— [CryptoNote][10],它萌芽于相同的社区,但是并没有使用相同的代码,它以比特币为背景来构建的,但又与之不同。它发行于 2012 年 12 月,由于它的出现,导致了几种加密货币的诞生,最著名的 [Monero][11] (2014) 就是其中之一。Monero 与 Zcash 使用了不同的方法,但解决了相同的问题:隐私性和可替换性。
-
-就像在开源世界中经常出现的案例一样,做同样的工作有不止一个的工具可用。
-
-### 下一代:"Blockchain-ng"
-
-但是,到目前为止,所有的这些变体只是改进加密货币或者扩展它们去支持其它类型的事务。因此,这就引出了第二代区块链。
-
-一旦社区开始去修改区块链的用法和调整技术部分时,对于一些想去扩展和重新思考它们未来的人来说,这种调整花费不了多长时间的。比特币的长期追随者 —— [Vitalik Buterin][12] 在 2013 年底建议,区域链的事务应该能够表示一个状态机的状态变化,将区域链识为能够运行应用程序(“智能合约”)的分布式计算机。这个项目 —— [以太坊(Ethereum)][13],上线于 2015 年 4 月。它在运行分布式应用程序方面取得了巨大的成功,它的一些非常流行的分布式应用程序([CryptoKitties][14])甚至导致以太坊区块链变得很慢。
-
-这证明了目前的区块链存在一个很大的局限性:速度和容量。(速度通常用每秒事务数来测量,简称 TPS)有几个提议都建议去解决这个速度问题,从分片到侧链,以及一个被称为“第二层(second-layer)”的解决方案。这里需要更多的创新。
-
-随着“智能合约”这个词开始流行起来,并且一件被证明的事情是 —— 如果仍然用很慢的技术去运行它们,那么就需要另外的即将要实现的创意:许可区块链(Permissioned blockchains)。到目前为止,所有的区块链网络上,我们有两个没有明说的特征:一是它们是公开的(任何人都可以看到它们的功能),二是它们没有许可(任何人都可以加入它们)。这两个部分是运行一个分布式的、非基于第三方货币应该具有的和必需具有的条件。
-
-随着区块链被认为出现与加密货币越来越明显的分离趋势,开始去考虑一些隐私、许可设置是很有意义的。一个有业务关系但相互之间完全不信任的财团类型的参与者,能够从这些区块链类型中获益 —— 比如,物流链上的参与者,定期进行双边结算或者使用一个清算中心的金融、保险、或医疗保健机构。
-
-一旦你将设置从“任何人都可以加入”变为“仅邀请者方可加入”,进一步对区块链构建区块的方式进行改变和调整将变得可能,那么对一些人来说,结果将变得非常有趣。
-
-首先,为了保护网络不受恶意或者垃圾参与者的影响,工作量证明被替换为更简单的和更少资源消耗的一些东西,比如,基于 [Raft][15] 的共识协议。在更高级别的安全性和更快的速度之间进行权衡,采用更简单的共识算法。对于更多群体来说这样更理想,因为他们可以用基于加密技术的担保来取代其它的基于法律关系的担保,例如为避免由于竞争而产生的大量能源消耗,而工作量证明就是这种情况。另外一个创新的地方是,使用 [股权证明(Proof of Stake)][16],它是公共网络共识机制的一个重量级的竞争者。它将可能像许可网络一样找到它自己的实现方式。
-
-有几个项目可以让创建许可区块链变得更简单,包括 [Quorum][17] (以太坊的一个分叉)和 [Hyperledger][18] 的 [Fabric][19] 和 [Sawtooth][20],基于新代码的两个开源项目。
-
-许可区块链可以避免公共的、非许可方式的区块链中某些错综复杂的问题,但是它自己也存在一些问题。正确地管理参与者是其中的一个问题:谁可以加入?如何辨别他们?如何将他们从网络上移除?网络上的一个实体是否去管理一个中央公共密钥基础设施(PKI)?
-
-区块链的开放本质被识为一种治理形式。
-
-### 区块链的开放本质
-
-到目前为止的所有案例中,有一件事情是很明确的:使用一个区块链的目标是去提升网络中的参与者和它产生的数据的信任水平,理想情况下,不需要做进一步的工作即可足以使用它。
-
-只有为这个网络提供动力的软件是自由和开源的,才能达到这种信任水平。即便是一个正确的、专用的、分布式区块链,它的本质仍然是运行着相同的第三方代码的私有代理的集合。从本质上来说,区块链的源代码必须是开源的,但仅是开源还不够,随着生态系统持续成长,这既是最低限度的担保也是进一步创新的源头。
-
-最后,值得一提的是,虽然区块链的开放本质被认为是创新和变化的源头,它也被认为是一种治理形式:代码治理,用户期望运行的任何一个特定版本,都应该包含他们认为的整个网络应该包含的功能和方法。在这方面,需要说明的一点是,一些区块链的开放本质正在“变味”。但是这一问题正在解决。
-
-### 第三和第四代:治理
-
-接下来,我正在考虑第三和第四代区块链:区块链将内置治理工具,以及项目将去解决棘手的大量不同区块链之间互连互通的问题,以便于它们之间可以交换信息和价值。
-
---------------------------------------------------------------------------------
-
-via: https://opensource.com/article/18/6/blockchain-guide-next-generation
-
-作者:[Axel Simon][a]
-选题:[lujun9972](https://github.com/lujun9972)
-译者:[qhwdw](https://github.com/qhwdw)
-校对:[校对者ID](https://github.com/校对者ID)
-
-本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
-
-[a]:https://opensource.com/users/axel
-[1]:https://bitcoin.org
-[2]:https://slashdot.org/
-[3]:https://github.com/bitcoin/bitcoin
-[4]:https://bitcointalk.org/
-[5]:https://www.namecoin.org/
-[6]:https://litecoin.org/
-[7]:https://en.wikipedia.org/wiki/Scrypt
-[8]:http://zerocash-project.org/index
-[9]:https://z.cash
-[10]:https://cryptonote.org/
-[11]:https://en.wikipedia.org/wiki/Monero_(cryptocurrency)
-[12]:https://en.wikipedia.org/wiki/Vitalik_Buterin
-[13]:https://ethereum.org
-[14]:http://cryptokitties.co/
-[15]:https://en.wikipedia.org/wiki/Raft_(computer_science)
-[16]:https://www.investopedia.com/terms/p/proof-stake-pos.asp
-[17]:https://www.jpmorgan.com/global/Quorum
-[18]:https://hyperledger.org/
-[19]:https://www.hyperledger.org/projects/fabric
-[20]:https://www.hyperledger.org/projects/sawtooth
diff --git a/translated/tech/20180704 Install an NVIDIA GPU on almost any machine.md b/translated/tech/20180704 Install an NVIDIA GPU on almost any machine.md
deleted file mode 100644
index 7f49fcda9d..0000000000
--- a/translated/tech/20180704 Install an NVIDIA GPU on almost any machine.md
+++ /dev/null
@@ -1,154 +0,0 @@
-在绝大部分类型的机器上安装 NVIDIA 显卡驱动
-======
-
-![](https://fedoramagazine.org/wp-content/uploads/2018/06/nvidia-816x345.jpg)
-
-无论是研究还是娱乐,安装一个最新的显卡驱动都能提升你的计算机性能,并且使你能全方位地实现新功能。本安装指南使用 Fedora 28 的新的第三方仓库来安装 NVIDIA 驱动。它将引导您完成硬件和软件两方面的安装,并且涵盖你需要得到的 NVIDIA 显卡启动和运行的一切。这个流程适用于任何支持 UEFI 的计算机和任意新的 NVIDIA 显卡。
-
-### 准备
-
-本指南依赖于下面这些材料:
-
- * 一台使用 UEFI 的计算机,如果你不确定你的电脑是否有这个这个固件,请运行 sudo dmidecode -t 0。如果输出中出现了“UEFI is supported”,你的安装过程就可以继续了。不然的话,虽然可以在技术上更新部分电脑来支持 UEFI,但是这个过程的要求很苛刻,我们通常不建议你这么使用。
- * 一个现代的,支持 UEFI 的 NVIDIA 的显卡
- * 一个满足你的 NVIDIA 显卡的功率和接线要求的电源(有关详细信息,请参考硬件和修改的章节)
- * 网络连接
- * Fedora 28 系统
-
-
-
-### 安装实例
-
-这个安装示例使用的是:
-
- * 一台 Optiplex 9010 的主机(一台相当老的机器)
- * NVIDIA GeForce GTX 1050 Ti XLR8 游戏超频版 4 GB GDDR5 PCI Express 3.0 显卡
- * 为了满足新显卡的电源要求,电源升级为 EVGA – 80 PLUS 600 W ATX 12V/EPS 12V,这个最新的 PSU 比推荐的最低要求高了 300 W,但在大部分情况下,满足推荐的最低要求就足够了。
- * 然后,当然的,Fedora 28 也别忘了.
-
-
-
-### 硬件和修改
-
-#### PSU
-
-打开你的台式机的机箱,检查印刷在电源上的最大输出功率。然后,查看你的 NVIDIA 显卡的文档,确定推荐的最小电源功率要求(以瓦特为单位)。除此之外,检查你的显卡,看它是否需要额外的接线,例如 6 针口连接器,大多数的入门级显卡只从主板获取电力,但是有一些显卡需要额外的电力,如果出现以下情况,你需要升级的 PSU:
-
- 1. 你的电源的最大输出功率低于显卡建议的最小电源功率。注意:根据一些显卡厂家的说法,比起推荐的功率,预先构建的系统可能会需要更多或更少的功率,而这取决于系统的配置。如果你使用的是一个特别耗电或者特别节能的配置,请灵活决定你的电源需求。
- 2. 你的电源没有提供必须的接线口来为你的显卡供电。
-
-
-
-PSU 的更换很容易,但是在你拆除你当前正在使用的电源之前,请务必注意你的接线布局。除此之外,请确保你选择的 PSU 适合你的机箱。
-
-#### CPU
-
-虽然在大多数老机器上安装高性能的 NVIDIA 显卡是可能的,但是一个缓慢或受损的 CPU 会阻碍显卡性能的发挥,如果要计算在你的机器上瓶颈效果的影响,请点击这里。知道你的 CPU 性能来避免高性能的显卡和 CPU 无法保持匹配是很重要的。升级你的 CPU 是一个潜在的考虑因素。
-
-#### 主板
-
-在继续进行之前,请确认你的主板和你选择的显卡是兼容的。你的显卡应该插在最靠近散热器的 PCI-E x16 插槽中。确保你的设置为显卡预留了足够的空间。此外,请注意,现在大部分的显卡使用的都是 PCI-E 3.0 技术。虽然这些显卡如果插在 PCI-E 3.0 插槽上会运行地最好,但如果插在一个旧版的插槽上的话,性能也不会受到太大的影响。
-
-### 安装
-```
-sudo dnf update
-
-```
-
-2\. 然后,使用这条简单的命令进行重启:
-```
-reboot
-
-```
-
-3\. 在重启之后,安装 Fedora 28 的工作站仓库:
-```
-sudo dnf install fedora-workstation-repositories
-
-```
-
-4\. 接着,设置 NVIDIA 驱动仓库:
-```
-sudo dnf config-manager --set-enabled rpmfusion-nonfree-nvidia-driver
-
-```
-
-5\. 然后,再次重启。
-
-6\. 在这次重启之后,通过下面这条命令验证是否添加了仓库:
-```
-sudo dnf repository-packages rpmfusion-nonfree-nvidia-driver info
-
-```
-
-如果加载了多个 NVIDIA 工具和它们各自的参数,请继续进行下一步。如果没有,你可能在添加新仓库的时候遇到了一个错误。你应该再试一次。
-
-7\. 登陆,连接到互联网,然后打开软件应用程序。点击加载项>硬件驱动> NVIDIA Linux 图形驱动>安装。
-
-接着,再一次重启。
-
-8\. 在重新启动后,转到侧栏上的‘显示应用程序’,然后打开新添加的 NVIDIA X 服务器设置应用程序。一个图形界面会被打开,然后出现一个对话框并包含以下信息:
-
-![NVIDIA X Server Prompt][5]
-
-请参考应用程序的建议,但是在这样做之前,请确保你的 NVIDIA 显卡就在手里,并且已准备好去安装。请注意在以 root 身份运行 nvidia xconfig 的时候,如果在没有立刻安装显卡的情况下关闭电源,这可能会造成严重损坏。这样做可能会导致你的电脑无法启动,并强制你通过重启屏幕来修复系统。重新安装 Fedora 会修复这些问题,但是效果会更加糟糕。
-
-如果你已准备好继续,请输入下面这条命令:
-```
-sudo nvidia-xconfig
-
-```
-
-如果系统提示你完成任何地下载,请选择接收然后继续。
-
-9\. 一旦这个过程完成,关闭所有的应用程序并关闭电脑,拔掉机器的电源。然后,按一下电源按钮来释放掉多有的剩余电量,以此来保护你自己不会被点击。如果你的 PSU 有电源开关,请将其关闭。
-
-10\. 最后,安装显卡,拔掉老的显卡并将新的显卡插入到正确的 PCI-E x16 插槽中,风扇朝着下方。如果这个位置已经没有空间让风扇通风。那作为代替,如果可以的话就把显卡面朝上放置。成功安装新的显卡之后,关闭你的机箱,插入 PSU ,然后打开计算机,它应该会成功启动。
-
-**注意:** 要禁用此安装中使用的 NVIDIA 驱动仓库,或者要禁用所有的 Fedora 工作站仓库,请参考这个 Fedora Wiki 页面。
-
-### 验证
-
-1\. 如果你新安装的显卡已连接到你的显示器并显示正确,则表明你的 NVIDIA 驱动程序已成功和显卡建立连接。
-
-如果你想去查看你的设置,或者验证驱动是否在正常工作(如果机箱的主板里安装了两块显卡),再次打开 NVIDIA X 服务器设置应用程序。这次,你应该不会被提示一个错误信息,并且系统会给出有关 X 的设置文件和你的 NVIDIA 显卡的信息。(请参考下面的屏幕截图)
-
-![NVIDIA X Server Settings][7]
-
-通过这个应用程序,你可以根据你的需要需改 X 配置文件,并可以监控显卡的性能,时钟速度和温度信息。
-
-2\. 为确保新显卡以满功率运行,一次显卡性能测试是非常必要的。GL Mark 2,是一个提供后台处理、构建、照明、纹理等等有关信息的标准工具。它提供了一个优秀的解决方案。GL Mark 2 记录了各种各样的图形测试的帧速率,然后输出一个总体的性能评分(这被称为 glmark2 分数)。
-
-**注意:** glxgears 只会测试你的屏幕或显示器的性能,不会测试显卡本身,请使用 GL Mark 2。
-
-要运行 GLMark2:
-
- 1. 打开终端并关闭其他所有的应用程序
- 2. 运行 sudo dnf install glmark2 命令
- 3. 运行 glmark2 命令
- 4. 允许运行完整的测试来得到最好的结果。检查帧速率是否符合你对这块显卡的预期。如果你想要额外的验证,你可以查阅网站来确认是否已有你这块显卡的 glmark2 测试评分被公布到网上,你可以比较这个分数来评估你这块显卡的性能。
- 5. 如果你的帧速率或者 glmark2 评分低于预期,请思考潜在的因素。CPU 造成的瓶颈?其他问题导致?
-
-
-如果诊断的结果很好,就开始享受你的新显卡吧。
-
-
---------------------------------------------------------------------------------
-
-via: https://fedoramagazine.org/install-nvidia-gpu/
-
-作者:[Justice del Castillo][a]
-选题:[lujun9972](https://github.com/lujun9972)
-译者:[hopefully2333](https://github.com/hopefully2333)
-校对:[校对者ID](https://github.com/校对者ID)
-
-本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
-
-[a]:https://fedoramagazine.org/author/justice/
-[1]:https://whatis.techtarget.com/definition/Unified-Extensible-Firmware-Interface-UEFI
-[2]:https://www.cnet.com/products/pny-geforce-gtx-xlr8-gaming-1050-ti-overclocked-edition-graphics-card-gf-gtx-1050-ti-4-gb/specs/
-[3]:https://www.evga.com/products/product.aspx?pn=100-B1-0600-KR
-[4]:http://thebottlenecker.com (Home: The Bottle Necker)
-[5]:https://bytebucket.org/kenneym/fedora-28-nvidia-gpu-installation/raw/7bee7dc6effe191f1f54b0589fa818960a8fa18b/nvidia_xserver_error.jpg?token=c6a7effe35f1c592a155a4a46a068a19fd060a91 (NVIDIA X Sever Prompt)
-[6]:https://fedoraproject.org/wiki/Workstation/Third_Party_Software_Repositories
-[7]:https://bytebucket.org/kenneym/fedora-28-nvidia-gpu-installation/raw/7bee7dc6effe191f1f54b0589fa818960a8fa18b/NVIDIA_XCONFIG.png?token=64e1a7be21e5e9ba157f029b65e24e4eef54d88f (NVIDIA X Server Settings)
diff --git a/translated/tech/20180706 6 RFCs for understanding how the internet works.md b/translated/tech/20180706 6 RFCs for understanding how the internet works.md
new file mode 100644
index 0000000000..c8e209b00c
--- /dev/null
+++ b/translated/tech/20180706 6 RFCs for understanding how the internet works.md
@@ -0,0 +1,75 @@
+6 个用于了解互联网工作原理的 RFC
+======
+
+![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/LAW-Internet_construction_9401467_520x292_0512_dc.png?itok=RPkPPtDe)
+
+阅读源码是开源软件的重要组成部分。这意味着用户可以查看代码并了解做了什么。
+
+但“阅读源码”并不仅适用于代码。理解代码实现的标准同样重要。这些标准由[互联网工程任务组][1](IETF)发布的称为“注释请求”(RFC)的文档中编写的。多年来已经发布了数以千计的 RFC,因此我们收集了一些我们的贡献者认为必读的内容。
+
+### 6 个必读的 RFC
+
+#### RFC 2119-在 RFC 中用于指示需求级别的关键字
+
+这是一个快速阅读,但它对了解其他 RFC 非常重要。 [RFC 2119][2] 定义了后续 RFC 中使用的需求级别。 “MAY” 究竟意味着什么?如果标准说 “SHOULD”,你真的必须这样做吗?通过为需求提供明确定义的分类,RFC 2119 有助于避免歧义。
+
+时间是全世界程序员的祸根。 [RFC 3339][3] 定义了如何格式化时间戳。基于 [ISO 8601][4] 标准,3339 为我们提供了一种表达时间的常用方法。例如,像星期几这样的冗余信息不应该包含在存储的时间戳中,因为它很容易计算。
+
+#### RFC 1918—私有互联网的地址分配
+
+有属于每个人的互联网,也有只属于你的互联网。专用网络一直在使用,[RFC 1918][5] 定义了这些网络。当然,你可以在路由器上设置路由公网地址,但这是一个坏主意。或者,你可以将未使用的公共 IP 地址视为内部网络。在任何一种情况下都表明你从未阅读过 RFC 1918。
+
+#### RFC 1912—常见的 DNS 操作和配置错误
+
+一切都是 #@%@ DNS 问题,对吧? [RFC 1912][6] 列出了管理员在试图保持互联网运行时所犯的错误。虽然它是在 1996 年发布的,但 DNS(以及人们犯的错误)并没有真正改变这么多。为了理解我们为什么首先需要 DNS,请考虑[ RFC 289-What we hope is an official list of host names]][7]如今看起来像什么。
+
+#### RFC 2822—互联网邮件格式
+
+想想你知道什么是有效的电子邮件地址么?如果不接受我地址中 “+” 的站点的数量是任何迹象, 你就不会。 [RFC 2822][8] 定义了有效的电子邮件地址。它还详细介绍了电子邮件的其余部分。
+
+#### RFC 7231—超文本传输协议(HTTP/1.1):语义和内容
+
+当你停下来思考它时,我们在网上做的几乎所有东西都依赖于 HTTP。 [RFC 7231][9] 是该协议的最新更新。它有超过 100 页,定义了方法、头和状态代码。
+
+### 3个应该阅读的 RFC
+
+好吧,并非每个RFC都是严肃的业务。
+
+#### RFC 1149—在禽类载体上传输 IP 数据报的标准
+
+网络以多种不同方式传递数据包。 [RFC 1149][10] 描述了鸽子载体的使用。当我距离州际高速公路一英里以外时,它们的可靠性不会低于我的移动提供商。
+
+#### RFC 2324—超文本咖啡壶控制协议(HTCPCP/1.0)
+
+咖啡对于完成工作非常重要,当然,我们需要一个用于管理咖啡壶的程序化界面。 [RFC 2324][11] 定义了一个用于与咖啡壶交互的协议,并添加了 HTTP 418(“我是一个茶壶”)。
+
+#### RFC 69—M.I.T.的分发列表更改
+
+[RFC 69] [12]是否是第一个误导取消订阅请求的发布示例?
+
+你必须阅读的 RFC 是什么(无论它们是否严肃)?在评论中分享你的列表。
+
+--------------------------------------------------------------------------------
+
+via: https://opensource.com/article/18/7/requests-for-comments-to-know
+
+作者:[Ben Cotton][a]
+选题:[lujun9972](https://github.com/lujun9972)
+译者:[geekpi](https://github.com/geekpi)
+校对:[校对者ID](https://github.com/校对者ID)
+
+本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
+
+[a]:https://opensource.com/users/bcotton
+[1]:https://www.ietf.org
+[2]:https://www.rfc-editor.org/rfc/rfc2119.txt
+[3]:https://www.rfc-editor.org/rfc/rfc3339.txt
+[4]:https://www.iso.org/iso-8601-date-and-time-format.html
+[5]:https://www.rfc-editor.org/rfc/rfc1918.txt
+[6]:https://www.rfc-editor.org/rfc/rfc1912.txt
+[7]:https://www.rfc-editor.org/rfc/rfc289.txt
+[8]:https://www.rfc-editor.org/rfc/rfc2822.txt
+[9]:https://www.rfc-editor.org/rfc/rfc7231.txt
+[10]:https://www.rfc-editor.org/rfc/rfc1149.txt
+[11]:https://www.rfc-editor.org/rfc/rfc2324.txt
+[12]:https://www.rfc-editor.org/rfc/rfc69.txt