mirror of
https://github.com/LCTT/TranslateProject.git
synced 2026-08-26 04:13:30 +08:00
177
published/20200310 Getting started with Emacs.md
Normal file
177
published/20200310 Getting started with Emacs.md
Normal file
@@ -0,0 +1,177 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12868-1.html)
|
||||
[#]: subject: (Getting started with Emacs)
|
||||
[#]: via: (https://opensource.com/article/20/3/getting-started-emacs)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
10 个让你进入 Emacs 世界的技巧
|
||||
======
|
||||
|
||||
> 10 个技巧,让你深入这个有用的开源文本编辑器的世界。
|
||||
|
||||

|
||||
|
||||
很多人都说想学 [Emacs][2],但很多人在短暂的接触后就退缩了。这并不是因为 Emacs 不好,也不是 Emacs 复杂。我相信,问题在于人们其实并不想“学习” Emacs,而是他们想习惯 Emacs 的传统。他们想了解那些神秘的键盘快捷键和不熟悉的术语。他们想按照他们认为的“使用目的”来使用 Emacs。
|
||||
|
||||
我很同情这一点,因为我对 Emacs 的感觉就是这样。我以为真正的 Emacs 用户都只会在终端里面运行,从来不用方向键和菜单,更不会用鼠标。这是个阻止自己开始使用 Emacs 的好办法。有足够多的独特的 `.emacs` 配置文件证明,如果说 Emacs 用户有一个共同的变化,那就是每个人使用 Emacs 的方式不同。
|
||||
|
||||
学习 Emacs 很容易。爱上 Emacs 才是最难的。要爱上 Emacs,你必须发现它所拥有的功能,而这些功能是你一直在寻找的,有时你并不知道你已经错过了它们。这需要经验。
|
||||
|
||||
获得这种经验的唯一方法就是从一开始就积极使用 Emacs。这里有十个小提示,可以帮助你找出最适合你的方法。
|
||||
|
||||
### 从 GUI 开始
|
||||
|
||||
Emacs(以及它的友好竞争者 [Vim][3])最伟大的事情之一是它可以在终端中运行,这在你 SSH 进入服务器时很有用,但在过去 15 年来制造的计算机上意义不大。Emacs 的 GUI 版本可以在极度[低功耗的设备][4]上运行,它有很多实用的功能,无论是新手还是有经验的用户都可以使用它。
|
||||
|
||||
例如,如果你不知道如何在 Emacs 中只用键盘快捷键复制一个单词,编辑菜单的复制、剪切和粘贴选择提供了最轻松的路径。没有理由因为选择了 Emacs 而惩罚自己。使用它的菜单,用鼠标选择区域,点击缓冲区内的按钮,不要让陌生感阻碍你的工作效率。
|
||||
|
||||
![Emacs slackware][5]
|
||||
|
||||
这些功能被内置到 Emacs 中,是因为用户在使用它们。你应该在你需要的时候使用它们,而当你最终在 VT100 终端上通过 SSH 使用 Emacs,没有 `Alt` 或方向键的时候,你才应该使用这些晦涩的命令。
|
||||
|
||||
### 习惯术语
|
||||
|
||||
Emacs 的 UI 元素有着特殊的术语。个人计算的发展并不是建立在相同的术语上,所以很多术语对现代计算机用户来说比较陌生,还有一些术语虽然相同,但含义不同。下面是一些最常见的术语。
|
||||
|
||||
* <ruby>框架<rt>Frame</rt></ruby>。在 Emacs 中,“框架”就是现代计算机所说的“窗口”。
|
||||
* <ruby>缓冲区<rt>Buffer</rt></ruby>:“缓冲区”是 Emacs 的一个通信通道。它可以作为 Emacs 进程的命令行,也可以作为 shell,或者只是一个文件的内容。
|
||||
* <ruby>窗口<rt>Window</rt></ruby>:“窗口”是你进入一个缓冲区的视角。
|
||||
* <ruby>迷你缓冲区<rt>Mini-buffer</rt></ruby>。它是主要的命令行,位于 Emacs 窗口的底部。
|
||||
|
||||
![Emacs tutorial map][6]
|
||||
|
||||
### 让 Emacs 的修饰键变得更有意义
|
||||
|
||||
在 PC 键盘上,`Ctrl` 键被称为 `C`,`Alt` 键被称为 `M`,这些键并不是 `C` 和 `M` 键,由于它们总是与相应的字母或符号键配对,所以在文档中很容易识别。
|
||||
|
||||
例如,`C-x` 在现代键盘符号中的意思是 `Ctrl+X`,`M-x` 是 `Alt+X`。就像你从任何应用程序中剪切文本时一样,同时按下这两个键。
|
||||
|
||||
不过,还有另一个层次的键盘快捷键,与现代电脑上的任何东西都完全不同。有时,键盘快捷键并不只是一个键组合,而是由一系列的按键组成。
|
||||
|
||||
例如,`C-x C-f` 的意思是像往常一样按 `Ctrl+X`,然后再按 `Ctrl+C`。
|
||||
|
||||
有时,一个键盘快捷键有混合的键型。组合键 `C-x 3` 意味着像往常一样按 `Ctrl+X`,然后按数字 `3` 键。
|
||||
|
||||
Emacs 之所以能做到这些花哨的强力组合,是因为某些键会让 Emacs 进入一种特殊的命令模式。如果你按 `C-X`(也就是 `Ctrl+X`),就是告诉 `Emacs` 进入空闲状态,等待第二个键或键盘快捷键。
|
||||
|
||||
Emacs 的文档,无论是官方的还是非官方的,都有很多键盘快捷键。在心里练习把 `C` 键翻译成 `Ctrl` 键,`M` 键翻译成 `Alt` 键,那么这些文档对你来说都会变得更有意义。
|
||||
|
||||
### 剪切、复制和粘贴的备用快捷方式
|
||||
|
||||
从规范上,复制文本是通过一系列的键盘快捷键进行的,这些快捷键取决于你想要复制或剪切的方式。
|
||||
|
||||
例如,你可以用 `M-d`(`Alt+d` 的 Emacs 行话)剪切一整个单词,或者用`C-k`(`Ctrl+K`)剪切一整行,或者用 `M-m`(`Alt+M`)剪切一个高亮区域。如果你想的话,你可以习惯这样,但如果你喜欢 `Ctrl+C` 和 `Ctrl+X` 和 `Ctrl-V`,那么你可以用这些来代替。
|
||||
|
||||
启用现代的“剪切-复制-粘贴”需要激活一个名为 CUA(<ruby>通用用户访问<rt>Common User Access</rt></ruby>)的功能。要激活 CUA,请单击“选项”菜单并选择“使用 CUA 键”。启用后,`C-c` 复制高亮显示的文本,`C-x` 剪切高亮显示的文本,`C-v` 粘贴文本。这个模式只有在你选择了文本之后才会实际激活,所以你仍然可以学习 Emacs 通常使用的 `C-x` 和 `C-c` 绑定。
|
||||
|
||||
### 用哪个都好
|
||||
|
||||
Emacs 是一个应用程序,它不会意识到你对它的感情或忠诚度。如果你想只用 Emacs 来完成那些“感觉”适合 Emacs 的任务,而用不同的编辑器(比如 Vim)来完成其他任务,你可以这样做。
|
||||
|
||||
你与一个应用程序的交互会影响你的工作方式,所以如果 Emacs 中所需要的按键模式与特定任务不一致,那么就不要强迫自己使用 Emacs 来完成该任务。Emacs 只是众多可供你使用的开源工具之一,没有理由让自己只限于一种工具。
|
||||
|
||||
### 探索新函数
|
||||
|
||||
Emacs 所做的大部分工作都是一个 elisp 函数,它可以从菜单选择和键盘快捷键调用,或者在某些情况下从特定事件中调用。所有的函数都可以从迷你缓冲区(Emacs 框架底部的命令行)执行。理论上,你甚至可以通过键入 `forward-word` 和 `backward-word` 以及 `next-line` 和 `previous-line` 等函数来导航光标。这肯定是无比低效的,但这就是一种直接访问你运行的代码的方式。在某种程度上,Emacs 就是自己的 API。
|
||||
|
||||
你可以通过在社区博客上阅读有关 Emacs 的资料来了解新函数,或者你可以采取更直接的方法,使用描述函数(`describe-function`)。要获得任何函数的帮助,按 `M-x`(也就是 `Alt+X`),然后输入 `describe-function`,然后按回车键。系统会提示你输入一个函数名称,然后显示该函数的描述。
|
||||
|
||||
你可以通过键入`M-x(`Alt+X`),然后键入 `?` 来获得所有可用函数的列表。
|
||||
|
||||
你也可以在输入函数时,通过按 `M-x` 键,然后输入 `auto-complete-mode`,再按回车键,获得弹出的函数描述。激活该模式后,当你在文档中键入任何 Emacs 函数时,都会向你提供自动补完选项,以及函数的描述。
|
||||
|
||||
![Emacs function][7]
|
||||
|
||||
当你找到一个有用的函数并使用它时,Emacs 会告诉你它的键盘绑定,如果有的话。如果没有的话,你可以通过打开你的 `$HOME/.emacs` 配置文件并输入键盘快捷键来自己分配一个。语法是 ` global-set-key`,后面是你要使用的键盘快捷键,然后是你要调用的函数。
|
||||
|
||||
例如,要将 `screenwriter-slugline` 函数分配一个键盘绑定:
|
||||
|
||||
```
|
||||
(global-set-key (kbd “C-c s”) 'screenwriter-slugline)
|
||||
```
|
||||
|
||||
重新加载配置文件,键盘快捷键就可以使用了:
|
||||
|
||||
```
|
||||
M-x load-file ~/.emacs
|
||||
```
|
||||
|
||||
### 紧急按钮
|
||||
|
||||
当你使用 Emacs 并尝试新的函数时,你一定会开始调用一些你并不想调用的东西。Emacs 中通用的紧急按钮是 `C-g`(就是 `Ctrl+G`)。
|
||||
|
||||
我通过将 G 与 GNU 联系起来来记住这一点,我想我是在呼吁 GNU 将我从一个错误的决定中拯救出来,但请随意编造你自己的记忆符号。
|
||||
|
||||
如果你按几下 `C-g`,Emacs 的迷你缓冲区就会回到潜伏状态,弹出窗口被隐藏,你又回到了一个普通的、无聊的文本编辑器的安全状态。
|
||||
|
||||
### 忽略键盘快捷键
|
||||
|
||||
潜在的键盘快捷键太多,在这里无法一一总结,更不希望你能记住。这是设计好的。Emacs 的目的是为了定制,当人们为 Emacs 编写插件时,他们可以定义自己的特殊键盘快捷键。
|
||||
|
||||
我们的想法不是要马上记住所有的快捷键。相反,你的目标是让你在使用 Emacs 时感到舒适。你在 Emacs 中变得越舒适,你就越会厌倦总是求助于菜单栏,你就会开始记住对你重要的组合键。
|
||||
|
||||
根据自己在 Emacs 中通常做的事情,每个人都有自己喜欢的快捷方式。一个整天用 Emacs 写代码的人可能知道运行调试器或启动特定语言模式的所有键盘快捷键,但对 Org 模式或 Artist 模式一无所知。这很自然,也很好。
|
||||
|
||||
### 使用 Bash 时练习 Emacs
|
||||
|
||||
了解 Emacs 键盘快捷键的一个好处是,其中许多快捷键也适用于 Bash。
|
||||
|
||||
* `C-a`:到行首
|
||||
* `C-e`:到行尾
|
||||
* `C-k`:剪切整行
|
||||
* `M-f`:向前一个字
|
||||
* `M-b`:向后一个字
|
||||
* `M-d`:剪切一个字
|
||||
* `C-y`:贴回(粘贴)最近剪切的内容
|
||||
* `M-Shift-U`:大写一个词
|
||||
* `C-t`:交换两个字符(例如,`sl` 变成 `ls`)
|
||||
|
||||
还有更多的例子,它能让你与 Bash 终端的交互速度超乎你的想象。
|
||||
|
||||
### 包
|
||||
|
||||
Emacs 有一个内置的包管理器来帮助你发现新的插件。它的包管理器包含了帮助你编辑特定类型文本的模式(例如,如果你经常编辑 JSON 文件,你可以尝试使用 ejson 模式)、嵌入的应用程序、主题、拼写检查选项、linter 等。这就是 Emacs 有可能成为你日常计算的关键所在;一旦你找到一个优秀的 Emacs 包,你可能离不开它了。
|
||||
|
||||
![Emacs emoji][8]
|
||||
|
||||
你可以按 `M-x`(就是 `Alt+X`)键,然后输入 `package-list-packages` 命令,再按回车键来浏览包。软件包管理器在每次启动时都会更新缓存,所以第一次使用时要耐心等待它下载可用软件包的列表。一旦加载完毕,你可以用键盘或鼠标进行导航(记住,Emacs 是一个 GUI 应用程序)。每一个软件包的名称都是一个按钮,所以你可以将光标移到它上面,然后按回车键,或者直接用鼠标点击它。你可以在 Emacs 框架中出现的新窗口中阅读有关软件包的信息,然后用安装按钮来安装它。
|
||||
|
||||
有些软件包需要特殊的配置,有时会在它的描述中列出,但有时需要你访问软件包的主页来阅读更多的信息。例如,自动完成包 `ac-emoji` 很容易安装,但需要你定义一个符号字体。无论哪种方式都可以使用,但你只有在安装了字体的情况下才能看到相应的表情符号,除非你访问它的主页,否则你可能不会知道。
|
||||
|
||||
### 俄罗斯方块
|
||||
|
||||
Emacs 有游戏,信不信由你。有数独、拼图、扫雷、一个好玩的心理治疗师,甚至还有俄罗斯方块。这些并不是特别有用,但在任何层面上与 Emacs 进行交互都是很好的练习,游戏是让你在 Emacs 中花费时间的好方法。
|
||||
|
||||
![Emacs tetris][9]
|
||||
|
||||
俄罗斯方块也是我最初接触 Emacs 的方式,所以在该游戏的所有版本中,Emacs 版本才是我真正的最爱。
|
||||
|
||||
### 使用 Emacs
|
||||
|
||||
GNU Emacs 之所以受欢迎,是因为它的灵活性和高度可扩展性。人们习惯了 Emacs 的键盘快捷键,以至于他们习惯性地尝试在其他所有的应用程序中使用这些快捷键,他们将应用程序构建到 Emacs 中,所以他们永远不需要离开。如果你想让 Emacs 在你的计算生活中扮演重要角色,最终的关键是拥抱未知,开始使用 Emacs。磕磕绊绊地,直到你发现如何让它为你工作,然后安下心来,享受 40 年的舒适生活。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/3/getting-started-emacs
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/keyboaord_enter_writing_documentation.jpg?itok=kKrnXc5h (Computer keyboard typing)
|
||||
[2]: https://opensource.com/downloads/emacs-cheat-sheet
|
||||
[3]: https://opensource.com/downloads/cheat-sheet-vim
|
||||
[4]: https://opensource.com/article/17/2/pocketchip-or-pi
|
||||
[5]: https://opensource.com/sites/default/files/uploads/emacs-slackware.jpg (Emacs slackware)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/emacs-tutorial-map.png (Emacs tutorial map)
|
||||
[7]: https://opensource.com/sites/default/files/uploads/emacs-function.jpg (Emacs function)
|
||||
[8]: https://opensource.com/sites/default/files/uploads/emacs-emoji_0.jpg (Emacs emoji)
|
||||
[9]: https://opensource.com/sites/default/files/uploads/emacs-tetris.jpg (Emacs tetris)
|
||||
@@ -0,0 +1,155 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (MjSeven)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12871-1.html)
|
||||
[#]: subject: (An introduction to mutation testing in Python)
|
||||
[#]: via: (https://opensource.com/article/20/7/mutmut-python)
|
||||
[#]: author: (Moshe Zadka https://opensource.com/users/moshez)
|
||||
|
||||
Python 突变测试介绍
|
||||
======
|
||||
|
||||
> 通过突变测试来修复未知的 bug。
|
||||
|
||||

|
||||
|
||||
你一定对所有内容都进行了测试,也许你甚至在项目仓库中有一个徽章,标明有 100% 的测试覆盖率,但是这些测试真的帮到你了吗?你怎么知道的?
|
||||
|
||||
开发人员很清楚单元测试的*成本*。测试必须要编写。有时它们无法按照预期工作:存在假告警或者抖动测试。在不更改任何代码的情况下有时成功,有时失败。通过单元测试发现的小问题很有价值,但是通常它们悄无声息的出现在开发人员的机器上,并且在提交到版本控制之前就已得到修复。但真正令人担忧的问题大多是看不见的。最糟糕的是,*丢失的告警*是完全不可见的:你看不到没能捕获的错误,直到出现在用户手上 —— 有时甚至连用户都看不到。
|
||||
|
||||
有一种测试可以使不可见的错误变为可见:<ruby>[突变测试][2]<rt>mutation testing</rt></ruby>。
|
||||
|
||||
变异测试通过算法修改源代码,并检查每次测试是否都有“变异体”存活。任何在单元测试中幸存下来的变异体都是问题:这意味着对代码的修改(可能会引入错误)没有被标准测试套件捕获。
|
||||
|
||||
[Python][3] 中用于突变测试的一个框架是 `mutmut`。
|
||||
|
||||
假设你需要编写代码来计算钟表中时针和分针之间的角度,直到最接近的度数,代码可能会这样写:
|
||||
|
||||
```
|
||||
def hours_hand(hour, minutes):
|
||||
base = (hour % 12 ) * (360 // 12)
|
||||
correction = int((minutes / 60) * (360 // 12))
|
||||
return base + correction
|
||||
|
||||
def minutes_hand(hour, minutes):
|
||||
return minutes * (360 // 60)
|
||||
|
||||
def between(hour, minutes):
|
||||
return abs(hours_hand(hour, minutes) - minutes_hand(hour, minutes))
|
||||
```
|
||||
|
||||
首先,写一个简单的单元测试:
|
||||
|
||||
```
|
||||
import angle
|
||||
|
||||
def test_twelve():
|
||||
assert angle.between(12, 00) == 0
|
||||
```
|
||||
|
||||
足够了吗?代码没有 `if` 语句,所以如果你查看覆盖率:
|
||||
|
||||
```
|
||||
$ coverage run `which pytest`
|
||||
============================= test session starts ==============================
|
||||
platform linux -- Python 3.8.3, pytest-5.4.3, py-1.8.2, pluggy-0.13.1
|
||||
rootdir: /home/moshez/src/mut-mut-test
|
||||
collected 1 item
|
||||
|
||||
tests/test_angle.py . [100%]
|
||||
|
||||
============================== 1 passed in 0.01s ===============================
|
||||
```
|
||||
|
||||
完美!测试通过,覆盖率为 100%,你真的是一个测试专家。但是,当你使用突变测试时,覆盖率会变成多少?
|
||||
|
||||
```
|
||||
$ mutmut run --paths-to-mutate angle.py
|
||||
<snip>
|
||||
Legend for output:
|
||||
🎉 Killed mutants. The goal is for everything to end up in this bucket.
|
||||
⏰ Timeout. Test suite took 10 times as long as the baseline so were killed.
|
||||
🤔 Suspicious. Tests took a long time, but not long enough to be fatal.
|
||||
🙁 Survived. This means your tests needs to be expanded.
|
||||
🔇 Skipped. Skipped.
|
||||
<snip>
|
||||
⠋ 21/21 🎉 5 ⏰ 0 🤔 0 🙁 16 🔇 0
|
||||
```
|
||||
|
||||
天啊,在 21 个突变体中,有 16 个存活。只有 5 个通过了突变测试,但是,这意味着什么呢?
|
||||
|
||||
对于每个突变测试,`mutmut` 会修改部分源代码,以模拟潜在的错误,修改的一个例子是将 `>` 比较更改为 `>=`,查看会发生什么。如果没有针对这个边界条件的单元测试,那么这个突变将会“存活”:这是一个没有任何测试用例能够检测到的潜在错误。
|
||||
|
||||
是时候编写更好的单元测试了。很容易检查使用 `results` 所做的更改:
|
||||
|
||||
```
|
||||
$ mutmut results
|
||||
<snip>
|
||||
Survived 🙁 (16)
|
||||
|
||||
---- angle.py (16) ----
|
||||
|
||||
4-7, 9-14, 16-21
|
||||
$ mutmut apply 4
|
||||
$ git diff
|
||||
diff --git a/angle.py b/angle.py
|
||||
index b5dca41..3939353 100644
|
||||
--- a/angle.py
|
||||
+++ b/angle.py
|
||||
@@ -1,6 +1,6 @@
|
||||
def hours_hand(hour, minutes):
|
||||
hour = hour % 12
|
||||
- base = hour * (360 // 12)
|
||||
+ base = hour / (360 // 12)
|
||||
correction = int((minutes / 60) * (360 // 12))
|
||||
return base + correction
|
||||
```
|
||||
|
||||
这是 `mutmut` 执行突变的一个典型例子,它会分析源代码并将运算符更改为不同的运算符:减法变加法。在本例中由乘法变为除法。一般来说,单元测试应该在操作符更换时捕获错误。否则,它们将无法有效地测试行为。按照这种逻辑,`mutmut` 会遍历源代码仔细检查你的测试。
|
||||
|
||||
你可以使用 `mutmut apply` 来应用失败的突变体。事实证明你几乎没有检查过 `hour` 参数是否被正确使用。修复它:
|
||||
|
||||
```
|
||||
$ git diff
|
||||
diff --git a/tests/test_angle.py b/tests/test_angle.py
|
||||
index f51d43a..1a2e4df 100644
|
||||
--- a/tests/test_angle.py
|
||||
+++ b/tests/test_angle.py
|
||||
@@ -2,3 +2,6 @@ import angle
|
||||
|
||||
def test_twelve():
|
||||
assert angle.between(12, 00) == 0
|
||||
+
|
||||
+def test_three():
|
||||
+ assert angle.between(3, 00) == 90
|
||||
```
|
||||
|
||||
以前,你只测试了 12 点钟,现在增加一个 3 点钟的测试就足够了吗?
|
||||
|
||||
```
|
||||
$ mutmut run --paths-to-mutate angle.py
|
||||
<snip>
|
||||
⠋ 21/21 🎉 7 ⏰ 0 🤔 0 🙁 14 🔇 0
|
||||
```
|
||||
|
||||
这项新测试成功杀死了两个突变体,比以前更好,当然还有很长的路要走。我不会一一解决剩下的 14 个测试用例,因为我认为模式已经很明确了。(你能将它们降低到零吗?)
|
||||
|
||||
变异测试和覆盖率一样,是一种工具,它允许你查看测试套件的全面程度。使用它使得测试用例需要改进:那些幸存的突变体中的任何一个都是人类在篡改代码时可能犯的错误,以及潜伏在程序中的隐藏错误。继续测试,愉快地搜寻 bug 吧。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/7/mutmut-python
|
||||
|
||||
作者:[Moshe Zadka][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/moshez
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/search_find_code_python_programming.png?itok=ynSL8XRV (Searching for code)
|
||||
[2]: https://opensource.com/article/19/8/mutation-testing-evolution-tdd
|
||||
[3]: https://opensource.com/resources/python
|
||||
@@ -0,0 +1,452 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12862-1.html)
|
||||
[#]: subject: (Use your favorite programming language to provision Infrastructure as Code)
|
||||
[#]: via: (https://opensource.com/article/20/8/infrastructure-as-code-pulumi)
|
||||
[#]: author: (Lee Briggs https://opensource.com/users/lbriggs)
|
||||
|
||||
使用你喜欢的编程语言,将基础设施作为代码进行配置
|
||||
======
|
||||
|
||||
> 用 Node.js 或其他编程语言为你提供启动基础设施所需的一切服务。
|
||||
|
||||

|
||||
|
||||
当你在 IT 和技术的世界里遨游时,你会反复遇到一些术语。其中有些术语很难量化,随着时间的推移,可能会有不同的含义。[“DevOps”][2] 就是一个例子,这个词似乎(在我看来)会根据使用它的人而改变;最初的 DevOps 先驱者可能甚至不认识我们今天所说的 DevOps。
|
||||
|
||||
如果你是一个软件开发者,“<ruby>基础架构即代码<rt>Infrastructure as Code</rt></ruby>”(IaC)可能是其中一个术语。IaC 是使用与你编写面向用户的功能相同的软件开发实践来声明应用程序运行的基础设施。这通常意味着使用 [Git][3] 或 [Mercurial][4] 等工具进行版本控制,使用 Puppet、Chef 或 Ansible 进行[配置管理][5]。在基础设施供应层,最常见的技术是 CloudFormation(专用于 AWS),或开源替代品 [Terraform][6],用来创建供你的应用程序运行的混合云资源。
|
||||
|
||||
在配置管理领域有很好产品可供选择,可以将 IaC 写成配置文件或首选的编程语言,但这种选择在基础设施供应领域并不常见。
|
||||
|
||||
[Pulumi][7] 提供了一个使用标准编程语言来定义基础设施的方式。它支持一系列语言,包括 [JavaScript][8]、[TypeScript][9]、[Go][10]、[Python][11] 和 [C#][12]。就像 Terraform 一样,Pulumi 对许多熟悉的云提供商有一流的支持,比如 [AWS][13]、[Azure][14]、[Google Cloud][15] 和[其他提供商][16]。
|
||||
|
||||
在本文中,我将向你展示如何使用 Pulumi 以 Node.js 编写基础设施。
|
||||
|
||||
### 先决条件
|
||||
|
||||
首先,确保你已经做好了使用 Pulumi 的准备。Pulumi 支持所有主流的操作系统,所以你安装其先决条件的方法取决于你使用的操作系统。
|
||||
|
||||
首先,安装你喜欢的编程语言的解释器。我将使用 TypeScript,所以我需要安装 `node` 二进制。请查阅 Node 的[安装说明][17],了解你的操作系统的信息。你可以在 [Mac][19] 或 [Linux][20] 上使用 [Homebrew][18] 来安装:
|
||||
|
||||
```
|
||||
brew install node
|
||||
```
|
||||
|
||||
在 Linux 上,你可以使用你常用的软件包管理器,如 `apt` 或 `dnf`。
|
||||
|
||||
```
|
||||
$ sudo dnf install nodejs
|
||||
```
|
||||
|
||||
无论哪种情况,结果都应该是 `node` 二进制文件在你的 `$PATH` 中可用。要确认它是可访问的,运行:
|
||||
|
||||
```
|
||||
node --version
|
||||
```
|
||||
|
||||
接下来,安装 Pulumi 命令行界面(CLI)。你可以在 Pulumi 的文档中找到针对不同操作系统的[安装说明][21]。在 Mac 或 Linux 上使用 `brew`:
|
||||
|
||||
```
|
||||
brew install pulumi
|
||||
```
|
||||
|
||||
另外,你也可以使用安装脚本。首先下载并审查它,然后执行它:
|
||||
|
||||
```
|
||||
$ curl -fsSL --output pulumi_installer.sh https://get.pulumi.com/
|
||||
$ more pulumi_installer.sh
|
||||
$ sh ./pulumi_installer.sh
|
||||
```
|
||||
|
||||
同样,我们所希望的结果是在你的路径上有 `pulumi` 二进制。检查版本以确保你已经准备好了:
|
||||
|
||||
```
|
||||
pulumi version
|
||||
v2.5.0
|
||||
```
|
||||
|
||||
### 配置 Pulumi
|
||||
|
||||
在你开始配置任何基础设施之前,给 Pulumi 一个存储其[状态][22]的地方。
|
||||
|
||||
Pulumi 将其状态存储在后端。默认的后端是 Pulumi 的软件即服务(它有一个针对个人用户的免费计划),但在这个例子中,我使用替代的文件后端。文件后端将在你的本地文件系统上创建一个文件来存储状态:
|
||||
|
||||
```
|
||||
pulumi login --local
|
||||
```
|
||||
|
||||
如果你打算和别人分享这个项目,文件后台可能不是一个好的起点。Pulumi 还可以将其状态存储在 AWS S3 等云对象存储中。要使用它,请创建一个 S3 bucket 并登录:
|
||||
|
||||
```
|
||||
pulumi login --cloud-url s3://my-pulumi-state-bucket
|
||||
```
|
||||
|
||||
现在你已经登录到了状态后端,你可以创建一个项目和一个堆栈了!
|
||||
|
||||
在你开始创建 Pulumi 项目之前,请先了解以下 Pulumi 术语,你将在本教程中看到这些术语。
|
||||
|
||||
#### 项目
|
||||
|
||||
<ruby>[项目][23]<rt>project</rt></ruby>是一个包含 `Pulumi.yaml` 文件的目录。这个文件包含了 Pulumi 需要知道的元数据,以便进行它的工作。在 `Pulumi.yaml` 文件中可以找到的示例字段有:
|
||||
|
||||
* 运行时(例如,Python、Node、Go、.Net)
|
||||
* 项目说明(如“我的第一个 Pulumi 项目”)
|
||||
* 项目名称
|
||||
|
||||
项目是一个松散的概念,可以满足你的需求。一般来说,一个项目包含了一系列的*资源*,这些资源是你想要提供和控制的东西。你可以选择拥有资源很少的小型 Pulumi 项目,也可以选择包含所有你需要的资源的大型项目。随着你对 Pulumi 越来越熟悉,你想如何布局你的项目会变得更加清晰。
|
||||
|
||||
#### 堆栈
|
||||
|
||||
Pulumi <ruby>[堆栈][24]<rt>stack</rt></ruby>允许你根据可配置的值来区分你的 Pulumi 项目。一个常见的用途是将一个项目部署到不同的环境,如开发或生产环境,或不同的地区,如欧洲、中东和非洲以及美国。
|
||||
|
||||
在入门时,你不大需要一个复杂的堆栈设置,所以本演练使用默认的堆栈名称 `dev`。
|
||||
|
||||
### 在 IaC 中使用 TypeScript
|
||||
|
||||
你可以使用方便的 `pulumi new` 命令来<ruby>初建<rt>bootstrap</rt></ruby>一个 Pulumi 项目。`new` 命令有一大堆标志和选项,可以帮助你入门 Pulumi,所以请继续创建你的第一个项目:
|
||||
|
||||
```
|
||||
$ pulumi new typescript
|
||||
This command will walk you through creating a new Pulumi project.
|
||||
|
||||
Enter a value or leave blank to accept the (default), and press <ENTER>.
|
||||
Press ^C at any time to quit.
|
||||
|
||||
project name: (pulumi) my-first-project
|
||||
project description: (A minimal TypeScript Pulumi program) My very first Pulumi program
|
||||
Created project 'my-first-project'
|
||||
|
||||
Please enter your desired stack name.
|
||||
To create a stack in an organization, use the format <org-name>/<stack-name> (e.g. `acmecorp/dev`).
|
||||
stack name: (dev) dev
|
||||
Created stack 'dev'
|
||||
|
||||
Installing dependencies...
|
||||
|
||||
|
||||
> node scripts/postinstall
|
||||
|
||||
added 82 packages from 126 contributors and audited 82 packages in 2.84s
|
||||
|
||||
13 packages are looking for funding
|
||||
run `npm fund` for details
|
||||
|
||||
found 0 vulnerabilities
|
||||
|
||||
Finished installing dependencies
|
||||
|
||||
Your new project is ready to go! ✨
|
||||
|
||||
To perform an initial deployment, run 'pulumi up'
|
||||
```
|
||||
|
||||
这里发生了很多事情,我将其展开来说:
|
||||
|
||||
第一部分是为你的 Pulumi 项目确定一个模板。我选择了通用的 `typescript` 选项,但是有[很多选项可供选择][25]。
|
||||
|
||||
这个 `new` 命令从你的模板库中抓取模板,并将这个文件复制到本地,包括运行时的依赖关系(在本例中是 `package.json`)。
|
||||
|
||||
`new` 命令通过在这个目录下运行 `npm install` 来安装这些依赖关系。然后 `npm install` 下载并安装运行 Pulumi 程序所需的一切,在这种情况下就是:`@pulumi/pulumi` NPM 包。
|
||||
|
||||
你已经准备好创建你的第一个资源了!
|
||||
|
||||
### 创建你的第一个云资源
|
||||
|
||||
资源是一个由你的基础设施供应软件生命周期进行管理的东西。资源一般是一个<ruby>云提供商对象<rt>cloud provider object</rt></ruby>,比如 S3 桶。Pulumi 的提供商处理 Pulumi 资源,提供商是具体的云提供商。Pulumi 有大约 [40 个提供商][26]可供你使用,但对于你的第一个资源,使用一个最简单的:<ruby>[随机提供商][27]<rt>random provider</rt></ruby>。
|
||||
|
||||
随机提供者顾名思义:它幂等地创建一个随机资源(例如,可以是一个字符串),并将其存储在 Pulumi 状态中。
|
||||
|
||||
使用 `npm` 将其添加到你的 Pulumi 项目中作为依赖关系:
|
||||
|
||||
```
|
||||
npm install @pulumi/random
|
||||
```
|
||||
|
||||
npm 包管理器下载并安装随机提供者包,并为你安装。现在你已经准备好编写你的 Pulumi 程序了。
|
||||
|
||||
当你之前生成你的项目时,Pulumi 的初建过程创建了一个 `index.ts` TypeScript 文件。在你喜欢的集成开发环境(IDE)中打开它,并添加你的第一个资源:
|
||||
|
||||
```
|
||||
import * as pulumi from "@pulumi/pulumi";
|
||||
import * as random from "@pulumi/random";
|
||||
|
||||
const password = new random.RandomString(`password`, {
|
||||
length: 10
|
||||
})
|
||||
```
|
||||
|
||||
如果你对 TypeScript 或 JavaScript 非常熟悉,这看起来会非常熟悉,因为它是用你熟悉的编程语言编写的。如果你使用的是 Pulumi 支持的其他语言之一,也是一样的。这里是之前的那个随机资源,但这次是用 Python 写的:
|
||||
|
||||
```
|
||||
import pulumi_random as random
|
||||
|
||||
password = random.RandomString("password", length=10)
|
||||
```
|
||||
|
||||
一个 Pulumi 项目目前只支持单一一种语言,但每个项目都可以引用其他语言编写的项目,这对于多语言团队的成员来说是一个很有用的技巧。
|
||||
|
||||
你已经编写了第一个 Pulumi 资源。现在你需要部署它。
|
||||
|
||||
离开编辑器,回到命令行。在你的项目目录下,运行 `pulumi up`,然后看着神奇的事情发生:
|
||||
|
||||
```
|
||||
pulumi up
|
||||
|
||||
Previewing update (dev):
|
||||
Type Name Plan
|
||||
+ pulumi:pulumi:Stack my-first-project-dev create
|
||||
+ └─ random:index:RandomString password create
|
||||
|
||||
Resources:
|
||||
+ 2 to create
|
||||
|
||||
Do you want to perform this update? yes
|
||||
Updating (dev):
|
||||
Type Name Status
|
||||
+ pulumi:pulumi:Stack my-first-project-dev created
|
||||
+ └─ random:index:RandomString password created
|
||||
|
||||
Resources:
|
||||
+ 2 created
|
||||
|
||||
Duration: 2s
|
||||
|
||||
Permalink: file:///Users/lbriggs/.pulumi/stacks/dev.json
|
||||
```
|
||||
|
||||
太好了,你有了第一个 Pulumi 资源! 虽然你可能很享受这种成就感,但不幸的是,这个随机资源并没有那么有用:它只是一个随机的字符串,你甚至看不到它是什么。先解决这部分问题。修改你之前的程序,在你创建的常量中加入 `export`:
|
||||
|
||||
```
|
||||
import * as pulumi from "@pulumi/pulumi";
|
||||
import * as random from "@pulumi/random";
|
||||
|
||||
export const password = new random.RandomString(`password`, {
|
||||
length: 10
|
||||
})
|
||||
```
|
||||
|
||||
重新运行 `pulumi up`,看看输出:
|
||||
|
||||
```
|
||||
pulumi up
|
||||
Previewing update (dev):
|
||||
Type Name Plan
|
||||
pulumi:pulumi:Stack my-first-project-dev
|
||||
|
||||
Outputs:
|
||||
+ password: {
|
||||
+ id : "&+r?{}J$J7"
|
||||
+ keepers : output<string>
|
||||
+ length : 10
|
||||
+ lower : true
|
||||
+ minLower : 0
|
||||
+ minNumeric : 0
|
||||
+ minSpecial : 0
|
||||
+ minUpper : 0
|
||||
+ number : true
|
||||
+ overrideSpecial: output<string>
|
||||
+ result : "&+r?{}J$J7"
|
||||
+ special : true
|
||||
+ upper : true
|
||||
+ urn : "urn:pulumi:dev::my-first-project::random:index/randomString:RandomString::password"
|
||||
}
|
||||
|
||||
Resources:
|
||||
2 unchanged
|
||||
|
||||
Do you want to perform this update? yes
|
||||
Updating (dev):
|
||||
Type Name Status
|
||||
pulumi:pulumi:Stack my-first-project-dev
|
||||
|
||||
Outputs:
|
||||
+ password: {
|
||||
+ id : "&+r?{}J$J7"
|
||||
+ length : 10
|
||||
+ lower : true
|
||||
+ minLower : 0
|
||||
+ minNumeric: 0
|
||||
+ minSpecial: 0
|
||||
+ minUpper : 0
|
||||
+ number : true
|
||||
+ result : "&+r?{}J$J7"
|
||||
+ special : true
|
||||
+ upper : true
|
||||
+ urn : "urn:pulumi:dev::my-first-project::random:index/randomString:RandomString::password"
|
||||
}
|
||||
|
||||
Resources:
|
||||
2 unchanged
|
||||
|
||||
Duration: 1s
|
||||
Permalink: file:///Users/lbriggs/.pulumi/stacks/dev.json
|
||||
```
|
||||
|
||||
现在你可以在 `Outputs` 的 `result` 部分下看到一个随机生成的字符串。你现在可以看到你创建的资源有很多属性。
|
||||
|
||||
这一切都很好,但如果你想享受 IaC,你得提供一些随机字符串以外的东西。试试吧。
|
||||
|
||||
### 部署一个容器
|
||||
|
||||
到目前为止,你已经通过安装依赖关系和注册一个简单的随机资源来 体验了初建你的 Pulumi。现在部署一些实际的基础设施,尽管是在你的本地机器上。
|
||||
|
||||
首先,将 `@pulumi/docker` 提供者添加到你的堆栈中。使用你选择的包管理器将其添加到项目中:
|
||||
|
||||
```
|
||||
npm install @pulumi/docker
|
||||
```
|
||||
|
||||
你已经从 `npm` 下拉了 Pulumi Docker 提供商包,这意味着你现在可以在你的项目中创建 Docker 镜像。
|
||||
|
||||
如果你的机器上还没有安装 Docker,现在是一个极好的时机去安装它。说明将取决于你的操作系统,所以看看 [Docker 的安装页面][28]了解信息。
|
||||
|
||||
再次打开你喜欢的 IDE,运行一个 Docker 容器。修改你之前的 `index.ts` 文件,让它看起来像这样:
|
||||
|
||||
```
|
||||
import * as pulumi from "@pulumi/pulumi";
|
||||
import * as random from "@pulumi/random";
|
||||
import * as docker from "@pulumi/docker";
|
||||
|
||||
const password = new random.RandomString(`password`, {
|
||||
length: 10
|
||||
})
|
||||
|
||||
const container = new docker.Container(`my-password`, {
|
||||
image: 'hashicorp/http-echo',
|
||||
command: [ pulumi.interpolate`-text=Your super secret password is: ${password.result}` ],
|
||||
ports: [{
|
||||
internal: 5678,
|
||||
external: 5678,
|
||||
}]
|
||||
})
|
||||
|
||||
export const id = container.id
|
||||
```
|
||||
|
||||
这将创建一个容器,创建一个 Web 服务器。Web 服务器的输出是你随机生成的字符串,在本例中是一个密码。运行这个,看看会发生什么:
|
||||
|
||||
```
|
||||
pulumi up
|
||||
|
||||
Previewing update (dev):
|
||||
Type Name Plan
|
||||
pulumi:pulumi:Stack my-first-project-dev
|
||||
+ └─ docker:index:Container my-password create
|
||||
|
||||
Outputs:
|
||||
+ id : output<string>
|
||||
~ password: {
|
||||
id : "&+r?{}J$J7"
|
||||
length : 10
|
||||
lower : true
|
||||
minLower : 0
|
||||
minNumeric: 0
|
||||
minSpecial: 0
|
||||
minUpper : 0
|
||||
number : true
|
||||
result : "&+r?{}J$J7"
|
||||
special : true
|
||||
upper : true
|
||||
urn : "urn:pulumi:dev::my-first-project::random:index/randomString:RandomString::password"
|
||||
}
|
||||
|
||||
Resources:
|
||||
+ 1 to create
|
||||
2 unchanged
|
||||
|
||||
Do you want to perform this update? yes
|
||||
Updating (dev):
|
||||
Type Name Status
|
||||
pulumi:pulumi:Stack my-first-project-dev
|
||||
+ └─ docker:index:Container my-password created
|
||||
|
||||
Outputs:
|
||||
+ id : "e73b34aeca34a64b72b61b0b9b8438637ce28853937bc359a1528ca99f49ddda"
|
||||
password: {
|
||||
id : "&+r?{}J$J7"
|
||||
length : 10
|
||||
lower : true
|
||||
minLower : 0
|
||||
minNumeric: 0
|
||||
minSpecial: 0
|
||||
minUpper : 0
|
||||
number : true
|
||||
result : "&+r?{}J$J7"
|
||||
special : true
|
||||
upper : true
|
||||
urn : "urn:pulumi:dev::my-first-project::random:index/randomString:RandomString::password"
|
||||
}
|
||||
|
||||
Resources:
|
||||
+ 1 created
|
||||
2 unchanged
|
||||
|
||||
Duration: 2s
|
||||
Permalink: file:///Users/lbriggs/.pulumi/stacks/dev.json
|
||||
```
|
||||
|
||||
你会注意到在 `Outputs` 部分,你输出的值已经改变了,它只是一个 Docker 容器 ID。检查你的非常简单的密码生成器是否工作:
|
||||
|
||||
```
|
||||
curl http://localhost:5678
|
||||
Your super secret password is: &+r?{}J$J7
|
||||
```
|
||||
|
||||
就是这样! 你刚刚用 TypeScript 配置了你的第一个基础架构。
|
||||
|
||||
#### 关于 Pulumi 输出的快速说明
|
||||
|
||||
你会注意到在创建 Docker 容器的代码中,它使用了一个特殊的 `pulumi.interpolate` 调用。如果你熟悉 TypeScript,你可能会好奇为什么需要这样做(因为它是 Pulumi 特有的)。这有一个有趣的原因。
|
||||
|
||||
当 Pulumi 创建一个资源时,直到程序执行时有一些值是 Pulumi 不知道的。在 Pulumi 中,这些值被称为 `Outputs`。这些 `Outputs` 可以在上面的代码中看到,例如,在你的第一个随机资源中,你使用 `export` 关键字来输出随机资源的属性,你还输出了你创建的容器的容器 ID。
|
||||
|
||||
因为 Pulumi 直到执行时才知道这些 `Outputs` 的值,所以在操作字符串时,它需要特殊的助手来使用它们。如果你想了解更多关于这个特殊的编程模型,请观看[这个短视频][29]。
|
||||
|
||||
### 总结
|
||||
|
||||
随着混合云基础架构中出现的复杂性,IaC 在很多方面都有了发展。在基础设施供应领域,Pulumi 是一个很好的选择,它可以使用你最喜欢的编程语言来供应你所需要的一切基础设施,然后你可以在你最喜欢的配置管理工具中进行标记,以采取下一步措施。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/8/infrastructure-as-code-pulumi
|
||||
|
||||
作者:[Lee Briggs][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/lbriggs
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/puzzle_computer_solve_fix_tool.png?itok=U0pH1uwj (Puzzle pieces coming together to form a computer screen)
|
||||
[2]: https://opensource.com/resources/devops
|
||||
[3]: https://git-scm.com/
|
||||
[4]: https://www.mercurial-scm.org/
|
||||
[5]: https://opensource.com/article/18/12/configuration-management-tools
|
||||
[6]: https://opensource.com/article/20/7/terraform-kubernetes
|
||||
[7]: https://www.pulumi.com/
|
||||
[8]: https://developer.mozilla.org/en-US/docs/Web/JavaScript
|
||||
[9]: https://www.typescriptlang.org/
|
||||
[10]: https://golang.org/
|
||||
[11]: https://www.python.org/
|
||||
[12]: https://en.wikipedia.org/wiki/C_Sharp_(programming_language)
|
||||
[13]: https://www.pulumi.com/docs/intro/cloud-providers/aws/
|
||||
[14]: https://www.pulumi.com/docs/intro/cloud-providers/azure/
|
||||
[15]: https://www.pulumi.com/docs/intro/cloud-providers/gcp/
|
||||
[16]: https://www.pulumi.com/docs/reference/pkg/
|
||||
[17]: https://nodejs.org/en/download/
|
||||
[18]: https://brew.sh/
|
||||
[19]: https://opensource.com/article/20/6/homebrew-mac
|
||||
[20]: https://opensource.com/article/20/6/homebrew-linux
|
||||
[21]: https://www.pulumi.com/docs/get-started/install/
|
||||
[22]: https://www.pulumi.com/docs/intro/concepts/state/
|
||||
[23]: https://www.pulumi.com/docs/intro/concepts/project/
|
||||
[24]: https://www.pulumi.com/docs/intro/concepts/stack/
|
||||
[25]: https://github.com/pulumi/templates
|
||||
[26]: https://www.pulumi.com/docs/intro/cloud-providers/
|
||||
[27]: https://www.pulumi.com/docs/intro/cloud-providers/random/
|
||||
[28]: https://docs.docker.com/get-docker/
|
||||
[29]: https://www.youtube.com/watch?v=lybOxul2otM
|
||||
665
published/20200918 Add throwing mechanics to your Python game.md
Normal file
665
published/20200918 Add throwing mechanics to your Python game.md
Normal file
@@ -0,0 +1,665 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (robsean)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12872-1.html)
|
||||
[#]: subject: (Add throwing mechanics to your Python game)
|
||||
[#]: via: (https://opensource.com/article/20/9/add-throwing-python-game)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
在你的 Python 游戏中添加投掷机制
|
||||
======
|
||||
|
||||
> 四处奔跑躲避敌人是一回事,反击敌人是另一回事。学习如何在这系列的第十二篇文章中在 Pygame 中创建平台游戏。
|
||||
|
||||

|
||||
|
||||
这是仍在进行中的关于使用 [Pygame][3] 模块在 [Python 3][2] 中创建电脑游戏的第十二部分。先前的文章是:
|
||||
|
||||
1. [通过构建一个简单的掷骰子游戏去学习怎么用 Python 编程][4]
|
||||
2. [使用 Python 和 Pygame 模块构建一个游戏框架][5]
|
||||
3. [如何在你的 Python 游戏中添加一个玩家][6]
|
||||
4. [用 Pygame 使你的游戏角色移动起来][7]
|
||||
5. [如何向你的 Python 游戏中添加一个敌人][8]
|
||||
6. [在 Pygame 游戏中放置平台][9]
|
||||
7. [在你的 Python 游戏中模拟引力][10]
|
||||
8. [为你的 Python 平台类游戏添加跳跃功能][11]
|
||||
9. [使你的 Python 游戏玩家能够向前和向后跑][12]
|
||||
10. [在你的 Python 平台类游戏中放一些奖励][13]
|
||||
11. [添加计分到你的 Python 游戏][14]
|
||||
|
||||
我的上一篇文章本来是这一系列文章的最后一篇,它鼓励你为这个游戏编写自己的附加程序。你们很多人都这么做了!我收到了一些电子邮件,要求帮助我还没有涵盖的常用机制:战斗。毕竟,跳起来躲避坏人是一回事,但是有时候让他们走开是一件非常令人满意的事。在电脑游戏中向你的敌人投掷一些物品是很常见的,不管是一个火球、一支箭、一道闪电,还是其它适合游戏的东西。
|
||||
|
||||
与迄今为止你在这个系列中为你的平台游戏编程的任何东西不同,可投掷物品有一个*生存时间*。在你投掷一个物品后,它会如期在移动一段距离后消失。如果它是一支箭或其它类似的东西,它可能会在通过屏幕的边缘时而消失。如果它是一个火球或一道闪电,它可能会在一段时间后熄灭。
|
||||
|
||||
这意味着每次生成一个可投掷的物品时,也必须生成一个独特的衡量其生存时间的标准。为了介绍这个概念,这篇文章演示如何一次只投掷一个物品。(换句话说,每次仅存在一个投掷物品)。 一方面,这是一个游戏的限制条件,但另一方面,它却是游戏本身的运行机制。你的玩家不能每次同时投掷 50 个火球,因为每次仅允许一个投掷物品,所以当你的玩家释放一个火球来尝试击中一名敌人就成为了一项挑战。而在幕后,这也使你的代码保持简单。
|
||||
|
||||
如果你想启用每次投掷多个项目,在完成这篇教程后,通过学习这篇教程所获取的知识来挑战你自己。
|
||||
|
||||
### 创建 Throwable 类
|
||||
|
||||
如果你跟随学习这系列的其它文章,那么你应该熟悉在屏幕上生成一个新的对象基础的 `__init__` 函数。这和你用来生成你的 [玩家][6] 和 [敌人][8] 的函数是一样的。这里是生成一个 `throwable` 对象的 `__init__` 函数来:
|
||||
|
||||
```
|
||||
class Throwable(pygame.sprite.Sprite):
|
||||
"""
|
||||
生成一个 throwable 对象
|
||||
"""
|
||||
def __init__(self, x, y, img, throw):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.image = pygame.image.load(os.path.join('images',img))
|
||||
self.image.convert_alpha()
|
||||
self.image.set_colorkey(ALPHA)
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.x = x
|
||||
self.rect.y = y
|
||||
self.firing = throw
|
||||
```
|
||||
|
||||
同你的 `Player` 类或 `Enemy` 类的 `__init__` 函数相比,这个函数的主要区别是,它有一个 `self.firing` 变量。这个变量保持跟踪一个投掷的物品是否在当前屏幕上活动,因此当一个 `throwable` 对象创建时,将变量设置为 `1` 的合乎情理的。
|
||||
|
||||
### 判断存活时间
|
||||
|
||||
接下来,就像使用 `Player` 和 `Enemy` 一样,你需要一个 `update` 函数,以便投掷的物品在瞄准敌人抛向空中时,它会自己移动。
|
||||
|
||||
测定一个投掷的物品存活时间的最简单方法是侦测它何时离开屏幕。你需要监视的屏幕边缘取决于你投掷的物品的物理特性。
|
||||
|
||||
* 如果你的玩家正在投掷的物品是沿着水平轴快速移动的,像一只弩箭或箭或一股非常快的魔法力量,而你想监视你游戏屏幕的水平轴极限。这可以通过 `worldx` 定义。
|
||||
* 如果你的玩家正在投掷的物品是沿着垂直方向或同时沿着水平方向和垂直方向移动的,那么你必须监视你游戏屏幕的垂直轴极限。这可以通过 `worldy` 定义。
|
||||
|
||||
这个示例假设你投掷的物品向前移动一点并最终落到地面上。不过,投掷的物品不会从地面上反弹起来,而是继续掉落出屏幕。你可以尝试不同的设置来看看什么最适合你的游戏:
|
||||
|
||||
```
|
||||
def update(self,worldy):
|
||||
'''
|
||||
投掷物理学
|
||||
'''
|
||||
if self.rect.y < worldy: #垂直轴
|
||||
self.rect.x += 15 #它向前移动的速度有多快
|
||||
self.rect.y += 5 #它掉落的速度有多快
|
||||
else:
|
||||
self.kill() #移除投掷对象
|
||||
self.firing = 0 #解除火力发射
|
||||
```
|
||||
|
||||
为使你的投掷物品移动地更快,增加 `self.rect` 的动量值。
|
||||
|
||||
如果投掷物品不在屏幕上,那么该物品将被销毁,以及释放其所占用的寄存器。另外,`self.firing` 将被设置回 `0` 以允许你的玩家来进行另一次射击。
|
||||
|
||||
### 设置你的投掷对象
|
||||
|
||||
就像使用你的玩家和敌人一样,你必须在你的设置部分中创建一个精灵组来保持投掷对象。
|
||||
|
||||
此外,你必须创建一个非活动的投掷对象来供开始的游戏使用。如果在游戏开始时却没有一个投掷对象,那么玩家在第一次尝试投掷一柄武器时,投掷将失败。
|
||||
|
||||
这个示例假设你的玩家使用一个火球作为开始的武器,因此,每一个投掷实例都是由 `fire` 变量指派的。在后面的关卡中,当玩家获取新的技能时,你可以使用相同的 `Throwable` 类来引入一个新的变量以使用一张不同的图像。
|
||||
|
||||
在这代码块中,前两行已经在你的代码中,因此不要重新键入它们:
|
||||
|
||||
```
|
||||
player_list = pygame.sprite.Group() #上下文
|
||||
player_list.add(player) #上下文
|
||||
fire = Throwable(player.rect.x,player.rect.y,'fire.png',0)
|
||||
firepower = pygame.sprite.Group()
|
||||
```
|
||||
|
||||
注意,每一个投掷对象的起始位置都是和玩家所在的位置相同。这使得它看起来像是投掷对象来自玩家。在第一个火球生成时,使用 `0` 来显示 `self.firing` 是可用的。
|
||||
|
||||
### 在主循环中获取投掷行为
|
||||
|
||||
没有在主循环中出现的代码不会在游戏中使用,因此你需要在你的主循环中添加一些东西,以便能在你的游戏世界中获取投掷对象。
|
||||
|
||||
首先,添加玩家控制。当前,你没有火力触发器。在键盘上的按键是有两种状态的:释放的按键,按下的按键。为了移动,你要使用这两种状态:按下按键来启动玩家移动,释放按键来停止玩家移动。开火仅需要一个信号。你使用哪个按键事件(按键按下或按键释放)来触发你的投掷对象取决于你的品味。
|
||||
|
||||
在这个代码语句块中,前两行是用于上下文的:
|
||||
|
||||
```
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
player.jump(platform_list)
|
||||
if event.key == pygame.K_SPACE:
|
||||
if not fire.firing:
|
||||
fire = Throwable(player.rect.x,player.rect.y,'fire.png',1)
|
||||
firepower.add(fire)
|
||||
```
|
||||
|
||||
与你在设置部分创建的火球不同,你使用一个 `1` 来设置 `self.firing` 为不可用。
|
||||
|
||||
最后,你必须更新和绘制你的投掷物品。这个顺序很重要,因此把这段代码放置到你现有的 `enemy.move` 和 `player_list.draw` 的代码行之间:
|
||||
|
||||
```
|
||||
enemy.move() # 上下文
|
||||
|
||||
if fire.firing:
|
||||
fire.update(worldy)
|
||||
firepower.draw(world)
|
||||
player_list.draw(screen) # 上下文
|
||||
enemy_list.draw(screen) # 上下文
|
||||
```
|
||||
|
||||
注意,这些更新仅在 `self.firing` 变量被设置为 1 时执行。如果它被设置为 0 ,那么 `fire.firing` 就不为 `true`,接下来就跳过更新。如果你尝试做上述这些更新,不管怎样,你的游戏都会崩溃,因为在游戏中将不会更新或绘制一个 `fire` 对象。
|
||||
|
||||
启动你的游戏,尝试挑战你的武器。
|
||||
|
||||
### 检测碰撞
|
||||
|
||||
如果你玩使用了新投掷技巧的游戏,你可能会注意到,你可以投掷对象,但是它却不会对你的敌人有任何影响。
|
||||
|
||||
原因是你的敌人没有被查到碰撞事故。一名敌人可能会被你的投掷物品所击中,但是敌人却从来不知道被击中了。
|
||||
|
||||
你已经在你的 `Player` 类中完成了碰撞检测,这非常类似。在你的 `Enemy` 类中,添加一个新的 `update` 函数:
|
||||
|
||||
```
|
||||
def update(self,firepower, enemy_list):
|
||||
"""
|
||||
检测火力碰撞
|
||||
"""
|
||||
fire_hit_list = pygame.sprite.spritecollide(self,firepower,False)
|
||||
for fire in fire_hit_list:
|
||||
enemy_list.remove(self)
|
||||
```
|
||||
|
||||
代码很简单。每个敌人对象都检查并看看它自己是否被 `firepower` 精灵组的成员所击中。如果它被击中,那么敌人就会从敌人组中移除和消失。
|
||||
|
||||
为集成这些功能到你的游戏之中,在主循环中调用位于新触发语句块中的函数:
|
||||
|
||||
```
|
||||
if fire.firing: # 上下文
|
||||
fire.update(worldy) # 上下文
|
||||
firepower.draw(screen) # 上下文
|
||||
enemy_list.update(firepower,enemy_list) # 更新敌人
|
||||
```
|
||||
|
||||
你现在可以尝试一下你的游戏了,大多数的事情都如预期般的那样工作。不过,这里仍然有一个问题,那就是投掷的方向。
|
||||
|
||||
### 更改投掷机制的方向
|
||||
|
||||
当前,你英雄的火球只会向右移动。这是因为 `Throwable` 类的 `update` 函数将像素添加到火球的位置,在 Pygame 中,在 X 轴上一个较大的数字意味着向屏幕的右侧移动。当你的英雄转向另一个方向时,你可能希望它投掷的火球也抛向左侧。
|
||||
|
||||
到目前为止,你已经知道如何实现这一点,至少在技术上是这样的。然而,最简单的解决方案却是使用一个变量,在一定程度上对你来说可能是一种新的方法。一般来说,你可以“设置一个标记”(有时也被称为“翻转一个位”)来标明你的英雄所面向的方向。在你做完后,你就可以检查这个变量来得知火球是向左移动还是向右移动。
|
||||
|
||||
首先,在你的 `Player` 类中创建一个新的变量来代表你的游戏所面向的方向。因为我的游戏天然地面向右侧,由此我把面向右侧作为默认值:
|
||||
|
||||
```
|
||||
self.score = 0
|
||||
self.facing_right = True # 添加这行
|
||||
self.is_jumping = True
|
||||
```
|
||||
|
||||
当这个变量是 `True` 时,你的英雄精灵是面向右侧的。当玩家每次更改英雄的方向时,变量也必须重新设置,因此,在你的主循环中相关的 `keyup` 事件中这样做:
|
||||
|
||||
```
|
||||
if event.type == pygame.KEYUP:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(steps, 0)
|
||||
player.facing_right = False # 添加这行
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(-steps, 0)
|
||||
player.facing_right = True # 添加这行
|
||||
```
|
||||
|
||||
最后,更改你的 `Throwable` 类的 `update` 函数,以检测英雄是否面向右侧,并恰当地添加或减去来自火球位置的像素:
|
||||
|
||||
```
|
||||
if self.rect.y < worldy:
|
||||
if player.facing_right:
|
||||
self.rect.x += 15
|
||||
else:
|
||||
self.rect.x -= 15
|
||||
self.rect.y += 5
|
||||
```
|
||||
|
||||
再次尝试你的游戏,清除掉你游戏世界中的一些坏人。
|
||||
|
||||
![Python 平台类使用投掷能力][15]
|
||||
|
||||
作为一项额外的挑战,当彻底打败敌人时,尝试增加你玩家的得分。
|
||||
|
||||
### 完整的代码
|
||||
|
||||
```
|
||||
#!/usr/bin/env python3
|
||||
# 作者: Seth Kenlon
|
||||
|
||||
# GPLv3
|
||||
# This program is free software: you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <[http://www.gnu.org/licenses/>][17].
|
||||
|
||||
import pygame
|
||||
import pygame.freetype
|
||||
import sys
|
||||
import os
|
||||
|
||||
'''
|
||||
变量
|
||||
'''
|
||||
|
||||
worldx = 960
|
||||
worldy = 720
|
||||
fps = 40
|
||||
ani = 4
|
||||
world = pygame.display.set_mode([worldx, worldy])
|
||||
forwardx = 600
|
||||
backwardx = 120
|
||||
|
||||
BLUE = (80, 80, 155)
|
||||
BLACK = (23, 23, 23)
|
||||
WHITE = (254, 254, 254)
|
||||
ALPHA = (0, 255, 0)
|
||||
|
||||
tx = 64
|
||||
ty = 64
|
||||
|
||||
font_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "fonts", "amazdoom.ttf")
|
||||
font_size = tx
|
||||
pygame.freetype.init()
|
||||
myfont = pygame.freetype.Font(font_path, font_size)
|
||||
|
||||
'''
|
||||
对象
|
||||
'''
|
||||
|
||||
def stats(score, health):
|
||||
myfont.render_to(world, (4, 4), "Score:"+str(score), BLUE, None, size=64)
|
||||
myfont.render_to(world, (4, 72), "Health:"+str(health), BLUE, None, size=64)
|
||||
|
||||
class Throwable(pygame.sprite.Sprite):
|
||||
"""
|
||||
生成一个投掷的对象
|
||||
"""
|
||||
def __init__(self, x, y, img, throw):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.image = pygame.image.load(os.path.join('images', img))
|
||||
self.image.convert_alpha()
|
||||
self.image.set_colorkey(ALPHA)
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.x = x
|
||||
self.rect.y = y
|
||||
self.firing = throw
|
||||
|
||||
def update(self, worldy):
|
||||
'''
|
||||
投掷物理学
|
||||
'''
|
||||
if self.rect.y < worldy:
|
||||
if player.facing_right:
|
||||
self.rect.x += 15
|
||||
else:
|
||||
self.rect.x -= 15
|
||||
self.rect.y += 5
|
||||
else:
|
||||
self.kill()
|
||||
self.firing = 0
|
||||
|
||||
# x 位置, y 位置, img 宽度, img 高度, img 文件
|
||||
class Platform(pygame.sprite.Sprite):
|
||||
def __init__(self, xloc, yloc, imgw, imgh, img):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.image = pygame.image.load(os.path.join('images', img)).convert()
|
||||
self.image.convert_alpha()
|
||||
self.image.set_colorkey(ALPHA)
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.y = yloc
|
||||
self.rect.x = xloc
|
||||
|
||||
class Player(pygame.sprite.Sprite):
|
||||
"""
|
||||
生成一名玩家
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.movex = 0
|
||||
self.movey = 0
|
||||
self.frame = 0
|
||||
self.health = 10
|
||||
self.damage = 0
|
||||
self.score = 0
|
||||
self.facing_right = True
|
||||
self.is_jumping = True
|
||||
self.is_falling = True
|
||||
self.images = []
|
||||
for i in range(1, 5):
|
||||
img = pygame.image.load(os.path.join('images', 'walk' + str(i) + '.png')).convert()
|
||||
img.convert_alpha()
|
||||
img.set_colorkey(ALPHA)
|
||||
self.images.append(img)
|
||||
self.image = self.images[0]
|
||||
self.rect = self.image.get_rect()
|
||||
|
||||
def gravity(self):
|
||||
if self.is_jumping:
|
||||
self.movey += 3.2
|
||||
|
||||
def control(self, x, y):
|
||||
"""
|
||||
控制玩家移动
|
||||
"""
|
||||
self.movex += x
|
||||
|
||||
def jump(self):
|
||||
if self.is_jumping is False:
|
||||
self.is_falling = False
|
||||
self.is_jumping = True
|
||||
|
||||
def update(self):
|
||||
"""
|
||||
更新精灵位置
|
||||
"""
|
||||
|
||||
# 向左移动
|
||||
if self.movex < 0:
|
||||
self.is_jumping = True
|
||||
self.frame += 1
|
||||
if self.frame > 3 * ani:
|
||||
self.frame = 0
|
||||
self.image = pygame.transform.flip(self.images[self.frame // ani], True, False)
|
||||
|
||||
# 向右移动
|
||||
if self.movex > 0:
|
||||
self.is_jumping = True
|
||||
self.frame += 1
|
||||
if self.frame > 3 * ani:
|
||||
self.frame = 0
|
||||
self.image = self.images[self.frame // ani]
|
||||
|
||||
# 碰撞
|
||||
enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
|
||||
if self.damage == 0:
|
||||
for enemy in enemy_hit_list:
|
||||
if not self.rect.contains(enemy):
|
||||
self.damage = self.rect.colliderect(enemy)
|
||||
if self.damage == 1:
|
||||
idx = self.rect.collidelist(enemy_hit_list)
|
||||
if idx == -1:
|
||||
self.damage = 0 # 设置伤害回 0
|
||||
self.health -= 1 # 减去 1 单位健康度
|
||||
|
||||
ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
|
||||
for g in ground_hit_list:
|
||||
self.movey = 0
|
||||
self.rect.bottom = g.rect.top
|
||||
self.is_jumping = False # 停止跳跃
|
||||
|
||||
# 掉落世界
|
||||
if self.rect.y > worldy:
|
||||
self.health -=1
|
||||
print(self.health)
|
||||
self.rect.x = tx
|
||||
self.rect.y = ty
|
||||
|
||||
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
|
||||
for p in plat_hit_list:
|
||||
self.is_jumping = False # 停止跳跃
|
||||
self.movey = 0
|
||||
if self.rect.bottom <= p.rect.bottom:
|
||||
self.rect.bottom = p.rect.top
|
||||
else:
|
||||
self.movey += 3.2
|
||||
|
||||
if self.is_jumping and self.is_falling is False:
|
||||
self.is_falling = True
|
||||
self.movey -= 33 # 跳跃多高
|
||||
|
||||
loot_hit_list = pygame.sprite.spritecollide(self, loot_list, False)
|
||||
for loot in loot_hit_list:
|
||||
loot_list.remove(loot)
|
||||
self.score += 1
|
||||
print(self.score)
|
||||
|
||||
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
|
||||
|
||||
self.rect.x += self.movex
|
||||
self.rect.y += self.movey
|
||||
|
||||
class Enemy(pygame.sprite.Sprite):
|
||||
"""
|
||||
生成一名敌人
|
||||
"""
|
||||
|
||||
def __init__(self, x, y, img):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.image = pygame.image.load(os.path.join('images', img))
|
||||
self.image.convert_alpha()
|
||||
self.image.set_colorkey(ALPHA)
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.x = x
|
||||
self.rect.y = y
|
||||
self.counter = 0
|
||||
|
||||
def move(self):
|
||||
"""
|
||||
敌人移动
|
||||
"""
|
||||
distance = 80
|
||||
speed = 8
|
||||
|
||||
if self.counter >= 0 and self.counter <= distance:
|
||||
self.rect.x += speed
|
||||
elif self.counter >= distance and self.counter <= distance * 2:
|
||||
self.rect.x -= speed
|
||||
else:
|
||||
self.counter = 0
|
||||
|
||||
self.counter += 1
|
||||
|
||||
def update(self, firepower, enemy_list):
|
||||
"""
|
||||
检测火力碰撞
|
||||
"""
|
||||
fire_hit_list = pygame.sprite.spritecollide(self, firepower, False)
|
||||
for fire in fire_hit_list:
|
||||
enemy_list.remove(self)
|
||||
|
||||
class Level:
|
||||
def ground(lvl, gloc, tx, ty):
|
||||
ground_list = pygame.sprite.Group()
|
||||
i = 0
|
||||
if lvl == 1:
|
||||
while i < len(gloc):
|
||||
ground = Platform(gloc[i], worldy - ty, tx, ty, 'tile-ground.png')
|
||||
ground_list.add(ground)
|
||||
i = i + 1
|
||||
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl))
|
||||
|
||||
return ground_list
|
||||
|
||||
def bad(lvl, eloc):
|
||||
if lvl == 1:
|
||||
enemy = Enemy(eloc[0], eloc[1], 'enemy.png')
|
||||
enemy_list = pygame.sprite.Group()
|
||||
enemy_list.add(enemy)
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl))
|
||||
|
||||
return enemy_list
|
||||
|
||||
# x 位置, y 位置, img 宽度, img 高度, img 文件
|
||||
def platform(lvl, tx, ty):
|
||||
plat_list = pygame.sprite.Group()
|
||||
ploc = []
|
||||
i = 0
|
||||
if lvl == 1:
|
||||
ploc.append((200, worldy - ty - 128, 3))
|
||||
ploc.append((300, worldy - ty - 256, 3))
|
||||
ploc.append((550, worldy - ty - 128, 4))
|
||||
while i < len(ploc):
|
||||
j = 0
|
||||
while j <= ploc[i][2]:
|
||||
plat = Platform((ploc[i][0] + (j * tx)), ploc[i][1], tx, ty, 'tile.png')
|
||||
plat_list.add(plat)
|
||||
j = j + 1
|
||||
print('run' + str(i) + str(ploc[i]))
|
||||
i = i + 1
|
||||
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl))
|
||||
|
||||
return plat_list
|
||||
|
||||
def loot(lvl):
|
||||
if lvl == 1:
|
||||
loot_list = pygame.sprite.Group()
|
||||
loot = Platform(tx*5, ty*5, tx, ty, 'loot_1.png')
|
||||
loot_list.add(loot)
|
||||
|
||||
if lvl == 2:
|
||||
print(lvl)
|
||||
|
||||
return loot_list
|
||||
|
||||
'''
|
||||
Setup 部分
|
||||
'''
|
||||
|
||||
backdrop = pygame.image.load(os.path.join('images', 'stage.png'))
|
||||
clock = pygame.time.Clock()
|
||||
pygame.init()
|
||||
backdropbox = world.get_rect()
|
||||
main = True
|
||||
|
||||
player = Player() # 生成玩家
|
||||
player.rect.x = 0 # 转到 x
|
||||
player.rect.y = 30 # 转到 y
|
||||
player_list = pygame.sprite.Group()
|
||||
player_list.add(player)
|
||||
steps = 10
|
||||
fire = Throwable(player.rect.x, player.rect.y, 'fire.png', 0)
|
||||
firepower = pygame.sprite.Group()
|
||||
|
||||
eloc = []
|
||||
eloc = [300, worldy-ty-80]
|
||||
enemy_list = Level.bad(1, eloc)
|
||||
gloc = []
|
||||
|
||||
i = 0
|
||||
while i <= (worldx / tx) + tx:
|
||||
gloc.append(i * tx)
|
||||
i = i + 1
|
||||
|
||||
ground_list = Level.ground(1, gloc, tx, ty)
|
||||
plat_list = Level.platform(1, tx, ty)
|
||||
enemy_list = Level.bad( 1, eloc )
|
||||
loot_list = Level.loot(1)
|
||||
|
||||
'''
|
||||
主循环
|
||||
'''
|
||||
|
||||
while main:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit()
|
||||
try:
|
||||
sys.exit()
|
||||
finally:
|
||||
main = False
|
||||
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == ord('q'):
|
||||
pygame.quit()
|
||||
try:
|
||||
sys.exit()
|
||||
finally:
|
||||
main = False
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(-steps, 0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(steps, 0)
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
player.jump()
|
||||
|
||||
if event.type == pygame.KEYUP:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(steps, 0)
|
||||
player.facing_right = False
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(-steps, 0)
|
||||
player.facing_right = True
|
||||
if event.key == pygame.K_SPACE:
|
||||
if not fire.firing:
|
||||
fire = Throwable(player.rect.x, player.rect.y, 'fire.png', 1)
|
||||
firepower.add(fire)
|
||||
|
||||
# 向向滚动世界
|
||||
if player.rect.x >= forwardx:
|
||||
scroll = player.rect.x - forwardx
|
||||
player.rect.x = forwardx
|
||||
for p in plat_list:
|
||||
p.rect.x -= scroll
|
||||
for e in enemy_list:
|
||||
e.rect.x -= scroll
|
||||
for l in loot_list:
|
||||
l.rect.x -= scroll
|
||||
|
||||
# 向后滚动世界
|
||||
if player.rect.x <= backwardx:
|
||||
scroll = backwardx - player.rect.x
|
||||
player.rect.x = backwardx
|
||||
for p in plat_list:
|
||||
p.rect.x += scroll
|
||||
for e in enemy_list:
|
||||
e.rect.x += scroll
|
||||
for l in loot_list:
|
||||
l.rect.x += scroll
|
||||
|
||||
world.blit(backdrop, backdropbox)
|
||||
player.update()
|
||||
player.gravity()
|
||||
player_list.draw(world)
|
||||
if fire.firing:
|
||||
fire.update(worldy)
|
||||
firepower.draw(world)
|
||||
enemy_list.draw(world)
|
||||
enemy_list.update(firepower, enemy_list)
|
||||
loot_list.draw(world)
|
||||
ground_list.draw(world)
|
||||
plat_list.draw(world)
|
||||
for e in enemy_list:
|
||||
e.move()
|
||||
stats(player.score, player.health)
|
||||
pygame.display.flip()
|
||||
clock.tick(fps)
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/9/add-throwing-python-game
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[robsean](https://github.com/robsean)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/game_pawn_grid_linux.png?itok=4gERzRkg (Gaming on a grid with penguin pawns)
|
||||
[2]: https://www.python.org/
|
||||
[3]: https://www.pygame.org/news
|
||||
[4]: https://linux.cn/article-9071-1.html
|
||||
[5]: https://linux.cn/article-10850-1.html
|
||||
[6]: https://linux.cn/article-10858-1.html
|
||||
[7]: https://linux.cn/article-10874-1.html
|
||||
[8]: https://linux.cn/article-10883-1.html
|
||||
[9]: https://linux.cn/article-10902-1.html
|
||||
[10]: https://linux.cn/article-11780-1.html
|
||||
[11]: https://linux.cn/article-11790-1.html
|
||||
[12]: https://linux.cn/article-11819-1.html
|
||||
[13]: https://linux.cn/article-11828-1.html
|
||||
[14]: https://linux.cn/article-11839-1.html
|
||||
[15]: https://opensource.com/sites/default/files/uploads/pygame-throw.jpg (Python platformer with throwing capability)
|
||||
[16]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[17]: http://www.gnu.org/licenses/\>
|
||||
136
published/20200922 Easily set image transparency using GIMP.md
Normal file
136
published/20200922 Easily set image transparency using GIMP.md
Normal file
@@ -0,0 +1,136 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (robsean)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12874-1.html)
|
||||
[#]: subject: (Easily set image transparency using GIMP)
|
||||
[#]: via: (https://opensource.com/article/20/9/chroma-key-gimp)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
使用 GIMP 轻松地设置图片透明度
|
||||
======
|
||||
|
||||
> 使用色键(绿屏)技巧来设置你电脑游戏中图片的透明度。
|
||||
|
||||

|
||||
|
||||
不管你是否正在使用 [Python][2] 或 [Lua][3] 编程一个游戏或一个 APP,你都有可能在你的游戏资源中使用 PNG 图像。PNG 格式图像的一个优点是能够存储一个 **alpha 通道**,这在一个 JPEG 格式的图像中是不可能获得的。alpha 在本质上是不可见的或透明的“颜色”。alpha 是你图像 _不可见_ 的一部分。例如,你要绘制一个甜甜圈,甜甜圈的空洞将使用 alpha 填充,你就可以看到它后面的任何东西。
|
||||
|
||||
一个常见的问题是如何找到一幅图像的 alpha 部分。有时你的编程框架,不管它是 [Python Arcade][4]、[Pygame][5]、LÖVE,或者其它的任何东西都会检测出 alpha 通道,(在适当地调用函数后)将其作为透明处理。这意味着它将不会在 alpha 部分来渲染新的像素,而留下甜甜圈的空洞。100% 是透明的,0% 是不透明的,在功能上起到“不可见”的作用。
|
||||
|
||||
有些时候,你的框架与你的图像资源在 alpha 通道的位置上是不一致的(或者,alpha 通道根本就不存在),你在你想要透明度的地方却得到像素。
|
||||
|
||||
这篇文章描述了我所知道的最可靠的方法来解决透明度的问题。
|
||||
|
||||
### 色键
|
||||
|
||||
在计算机图形学中,有一些有助于确定每一个像素是如何渲染的值。<ruby>色度<rt>Chrominance</rt></ruby>(或者 chroma),描述一个像素的饱和度或强度。<ruby>色键<rt>chroma key</rt></ruby>技术(也称为<ruby>绿屏<rt>green screening</rt></ruby>)最初是作为一种化学工艺而发展起来的,在复印一张底片时,使用一种特定的 **无光泽** 的颜色(最初是蓝色,后来是绿色)来故意遮掩,以允许使用另一幅图像来取代曾经有蓝色或绿色屏幕的地方。这是一种简化的解释,但是它说明了计算机图形学中被称为 alpha 通道的起源。
|
||||
|
||||
alpha 通道是保存在图像中的信息,用以标识要透明的像素。例如,RGB 图像有红、绿、蓝通道。RGBA 图像包含红、绿、蓝通道,以及 alpha 通道。alpha 值的范围可以从 0 到 1 ,使用小数是也有效的。
|
||||
|
||||
因为一个 alpha 通道可以用几种不同的方法表达,因此依赖于嵌入的 alpha 通道可能是有问题的。作为替代方案,你可以在你的游戏框架中选择一种颜色并将其转化为一个 0 的 alpha 值。要做到这一点,你必须知道在你图像中的颜色值。
|
||||
|
||||
### 准备你的图片
|
||||
|
||||
要准备一个专门为色度键保留明确颜色的图形,在你最喜欢的图片编辑器中打开图片。我建议使用 [GIMP][6] 或 [Glimpse][7],但是 [mtPaint][8] 或 [Pinta][9],甚至 [Inkscape][10] 也能很好地工作,这取决于你的图像的性质,以及你将这些操作指南转换到一种不同图片编辑器工具的能力。
|
||||
|
||||
首先打开这幅 Tux 企鹅的图像:
|
||||
|
||||
![Tux 企鹅][11]
|
||||
|
||||
### 选择图片
|
||||
|
||||
在图片打开后,转到 **窗口** 菜单,选择 **可停靠对话框** ,接下来选择 **图层**。在 **图层** 面板中 Tux 图层上右击。从弹出菜单中,选择 **Alpha 到选区** 。如果你的图像没有内置的 alpha 通道,那么你必须手动创建你自己的选区。
|
||||
|
||||
![Alpha 到选区][13]
|
||||
|
||||
为手动创建一个选区,单击来自工具箱的 **路径** 工具。
|
||||
|
||||
![GIMP 的路径工具][14]
|
||||
|
||||
使用 **路径** 工具,在图像周围移动鼠标,在其轮廓的每个主要交叉点处都单击和释放(不要拖动)。 不要担心沿着曲线走;只需要找到主要的交叉点和拐角。这将在每个点处创建一个节点,并在节点中间绘制一条条线段。你不需要闭合你的路径,因此当你最后到达你开始时的交叉点时,你就完成了。
|
||||
|
||||
![在 GIMP 中创建一个路径][15]
|
||||
|
||||
在你创建你的轮廓路径后,转到 **窗口** 菜单,选择 **可停靠对话框** ,接下来选择 **工具选项** 。在 **工具选项** 面板中,选择 **编辑 (Ctrl)** 。随着这项操作的激活,你可以编辑你刚刚通过单击线或单击节点绘制的路径,并通过调整它们来更好地适应你的图像。你甚至能够将直线弯曲。
|
||||
|
||||
![编辑路径][16]
|
||||
|
||||
现在从 **窗口 > 可停靠对话框** 菜单中选择 **路径** 面板。在 **路径** 面板中,单击 **路径到选区** 按钮。你的绘图现在已经被选中了。
|
||||
|
||||
### 扩大选区
|
||||
|
||||
如果你觉得你的选区太紧贴了,你可以通过扩大来给予你自己的选区一些富余。当我想在一张图像周围采用或加厚一个边框时,我有时会这么扩大选区。
|
||||
|
||||
为扩大一个选区,单击 **选择** 菜单,选择 **扩大** 。输入一个像素值并单击 **确定** 。
|
||||
|
||||
### 反转选区
|
||||
|
||||
你已经选择了你的图形,但是你真正想选择的东西却 _不包括_ 你所选择的图像。这是因为你要创建一个 alpha 蒙版来定义图像中的一些内容的来被其它一些内容所替换。换句话说,你需要标记那些将被转变为不可见的像素。
|
||||
|
||||
为了反转选择区,单击 **选择** 菜单,选择 **反转** 。现在除你的图像以外的一切东西都是被选择的。
|
||||
|
||||
### 使用 alpha 填充
|
||||
|
||||
随着选择了除了你的图像以外的一切东西,再选择你想使用的颜色来指定你的 alpha 蒙版。最常用的颜色是绿色(正如你可能从术语“绿屏”中所猜到的一样)。绿色不是什么神奇的颜色,甚至也不是特定的绿色色调。之所以使用它是因为人们经常处理不包含绿色色素的图像,这样人们能够很容易分离出绿色,而不会意外地分离出图像中重要的部分。当然,如果你的图像是一位绿色的外星人或一枚绿宝石或一些 _确实_ 包含绿色的东西,那么你应该使用一种不同的颜色。只要你所选择的颜色是单一的单色,那么你就可以使用你所希望的任意颜色。如果你正在处理很多图像,你的选择应该在所有图像中保持一致。
|
||||
|
||||
![在工具箱中的前景色][17]
|
||||
|
||||
使用你选择的颜色值来设置你的前景色。为确保你的选择是精确的,使用 [HTML][18] 或 [HSV][19] 表示的颜色。例如,如果你正在使用纯绿色,它可以在 GIMP(以及大多数的开放源码图像应用程序)中表示为 `00ff00`(`00` 是红色,`FF` 是绿色,`00` 是蓝色,`F` 是最大值)。
|
||||
|
||||
![设置颜色值][20]
|
||||
|
||||
不管你选择什么颜色,务必记录下 HTML 或 HSV 的值,以便你可以为每一张图像使用完全相同的颜色。
|
||||
|
||||
为填充你的 alpha 蒙版,单击 **编辑** 菜单,选择 **使用前景色填充** 。
|
||||
|
||||
### 平整和导出
|
||||
|
||||
如果你在你的图像周围留下边框,设置背景颜色来着色你想使用的边界笔刷。这通常是黑色或白色,但是它也可以是任何适宜你游戏审美观的颜色。
|
||||
|
||||
在你设置背景颜色后,单击 **图像** 菜单,选择 **平整图像**。不管你是否添加了边框,这样做都是安全的。这个过程将从图像中移除 alpha 通道,并使用背景色填充任何“透明的”像素。
|
||||
|
||||
![平整图像][21]
|
||||
|
||||
你现在已经为你的游戏引擎准备好了一张图像。导出图像为你的游戏引擎喜欢的任何格式,接下来使用游戏引擎所需要的每一个函数来将图像导入的你的游戏中。在的代码中,设置 alpha 值为 `00ff00`(或你使用的任何颜色),接下来使用游戏引擎的图像转换器来将该颜色作为 alpha 通道处理。
|
||||
|
||||
### 其它的方法
|
||||
|
||||
这不是唯一能在你游戏图像中获取透明度的方法。查看你游戏引擎的文档来找出它是如何默认尝试处理 alpha 通道的,在你不确定的时候,尝试让你的游戏引擎来自动侦测图像中透明度,然后再去编辑它。有时,你游戏引擎的预期值和你图像的预设值恰巧匹配,那么你就可以直接获取透明度,而不需要做任何额外的工作。
|
||||
|
||||
不过,当这些尝试都失败时,尝试一下色键。它为电影业工作了将近 100 年,它也可以为你工作。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/9/chroma-key-gimp
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[robsean](https://github.com/robsean)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/gaming_grid_penguin.png?itok=7Fv83mHR (Gaming with penguin pawns)
|
||||
[2]: https://opensource.com/article/17/10/python-101
|
||||
[3]: https://opensource.com/article/17/4/how-program-games-raspberry-pi
|
||||
[4]: https://opensource.com/article/18/4/easy-2d-game-creation-python-and-arcade
|
||||
[5]: https://opensource.com/article/17/12/game-framework-python
|
||||
[6]: http://gimp.org
|
||||
[7]: https://glimpse-editor.github.io
|
||||
[8]: https://opensource.com/article/17/2/mtpaint-pixel-art-animated-gifs
|
||||
[9]: https://www.pinta-project.com/
|
||||
[10]: http://inkscape.org
|
||||
[11]: https://opensource.com/sites/default/files/uploads/tux.png (Tux the penguin)
|
||||
[12]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[13]: https://opensource.com/sites/default/files/uploads/gimp_alpha-to-selection.jpg (Alpha to selection)
|
||||
[14]: https://opensource.com/sites/default/files/uploads/gimp_path-tool.jpg (GIMP Paths tool)
|
||||
[15]: https://opensource.com/sites/default/files/uploads/gimp_path-create.jpg (Create a path in GIMP)
|
||||
[16]: https://opensource.com/sites/default/files/uploads/gimp_path-edit.jpg (Edit path)
|
||||
[17]: https://opensource.com/sites/default/files/uploads/gimp_foreground-colour.jpg (Foreground color in toolbox)
|
||||
[18]: https://www.w3schools.com/colors/colors_picker.asp
|
||||
[19]: https://en.wikipedia.org/wiki/HSL_and_HSV
|
||||
[20]: https://opensource.com/sites/default/files/uploads/gimp_colour.jpg (Setting color values)
|
||||
[21]: https://opensource.com/sites/default/files/uploads/gimp_matte.jpg (Flattening image)
|
||||
184
published/20201022 5 steps to learn any programming language.md
Normal file
184
published/20201022 5 steps to learn any programming language.md
Normal file
@@ -0,0 +1,184 @@
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "xiao-song-123"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-12842-1.html"
|
||||
[#]: subject: "5 steps to learn any programming language"
|
||||
[#]: via: "https://opensource.com/article/20/10/learn-any-programming-language"
|
||||
[#]: author: "Seth Kenlon https://opensource.com/users/seth"
|
||||
|
||||
五步学会任何编程语言
|
||||
======
|
||||
|
||||
> 只需一点编程经验,你就可以在短短几天内(有时更少)学会一种新编程语言。
|
||||
|
||||

|
||||
|
||||
有些人喜欢学习新的编程语言,也有一些人觉得学习一种都是可望不可及的事情。在本文中,我将向你展示如何像程序员一样思考,这样你就可以自信地学习任何一门你想要学习的编程语言。
|
||||
|
||||
事实上,一旦你学会了如何编程,你使用的编程语言就不再是一个障碍,而更像是一种形式。实际上,这就是教育家们倡导 [让孩子尽早学习编程][2] 的众多原因之一。不管他们的入门语言有多简单,这种编程的逻辑和儿童们(或成人学习者)以后可能遇到的其他语言的逻辑有着想通之处。
|
||||
|
||||
只需有一点编程经验(你可以从我们这里的几篇介绍性文章中获得),你就可以在短短几天内(有时更短)学习任何编程语言。这并不是魔法,你也确实要为此付出一些努力。诚然,学习一种编程语言每个的可用库,或者学习打包代码以及进行交付的细微差别,需要的时间远远不止几天。但是,就入门来说,比你想像中的要容易许多,剩下的则要通过不断练习来完成。
|
||||
|
||||
当有经验的程序员静下心来学习一门新的编程语言时,他们会寻找五样东西。只要你知道了这五件事,你就可以开始编码了。
|
||||
|
||||
### 1、语法
|
||||
|
||||
![Syntax][3]
|
||||
|
||||
语言的语法描述了代码的结构。这包括如何逐行编写代码,以及用于构造代码语句的实际单词。
|
||||
|
||||
例如,[Python][5] 以使用缩进来指示一个代码块在哪里结束以及另一代码块在哪里开始而闻名:
|
||||
|
||||
```
|
||||
while j < rows:
|
||||
while k < columns:
|
||||
tile = Tile(k * w)
|
||||
board.add(tile)
|
||||
k += 1
|
||||
j += 1
|
||||
k = 0
|
||||
```
|
||||
|
||||
[Lua][6] 只是使用关键字 `end`:
|
||||
|
||||
```
|
||||
for i,obj in ipairs(hit) do
|
||||
if obj.moving == 1 then
|
||||
obj.x,obj.y = v.mouse.getPosition()
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
[Java][7]、[C][8]、C++ 之类的编程语言使用花括号:
|
||||
|
||||
```
|
||||
while (std::getline(e,r)) {
|
||||
wc++;
|
||||
}
|
||||
```
|
||||
|
||||
编程语言的语法还包括包括库、设置变量和终止行等内容。通过练习,你将学会在阅读示例代码时下意识地识别语法需求(和惯例)。
|
||||
|
||||
#### 实践
|
||||
|
||||
当学习一门新的编程语言时,要努力理解它的语法。你不需要去记住它,只需要知道如果忘记了以后去哪里查找。使用好的 [IDE][9] 也很有帮助,因为很多 IDE 在出现语法错误时会提醒你。
|
||||
|
||||
### 2、内置函数和条件
|
||||
|
||||
![built-in words][10]
|
||||
|
||||
就像自然语言一样,编程语言可以识别的合法单词是有限的。这个词汇表可以使用其他库进行扩展,但是核心语言知道一组特定的关键字。大多数语言并没有你想的那么多关键字。即使在像 C 语言这样非常低级的语言中,也只有 32 个关键字,比如 `for`、`do`、`while`、`int`、`float`、`char`、`break` 等等。
|
||||
|
||||
了解了这些关键字,你就可以编写基本的表达式,也就是构建程序的代码块。许多内置的关键字能帮助你构建条件语句,这些条件语句影响整个程序的流程。例如,如果你想编写一个允许单击和拖动图标的程序,那么你的代码就必须检测用户的鼠标指针何时位于图标上。只有当鼠标光标位于图标外部边缘相同的坐标时,才执行导致使鼠标抓取图标的代码。这是一个经典的 `if` / `then` 语句,但不同的语言可以用不同的方式表达。
|
||||
|
||||
Python 使用 `if`、`elif `和 `else` 的组合来实现条件语句,但是并不显式的关闭语句:
|
||||
|
||||
```
|
||||
if var == 1:
|
||||
# action
|
||||
elif var == 2:
|
||||
# some action
|
||||
else:
|
||||
# some other action
|
||||
```
|
||||
|
||||
[Bash][11] 使用 `if`、`elif`、`else`,并且使用 `fi` 来结束语句:
|
||||
|
||||
```
|
||||
if [ "$var" = "foo" ]; then
|
||||
# action
|
||||
elif [ "$var" = "bar" ]; then
|
||||
# some action
|
||||
else
|
||||
# some other action
|
||||
fi
|
||||
```
|
||||
|
||||
然而 C 和 Java, 使用 `if`、`else` 和 `else if`,用花括号把它们括起来:
|
||||
|
||||
```
|
||||
if (boolean) {
|
||||
// action
|
||||
} else if (boolean) {
|
||||
// some action
|
||||
} else {
|
||||
// some other action
|
||||
}
|
||||
```
|
||||
|
||||
各种编程语言虽然在关键字的选择和语法上有细微的变化,但基本是相同的。学习如何在编程语言中定义条件语句,包括 `if` / `then`、`do...while` 和 `case` 语句。
|
||||
|
||||
#### 实践
|
||||
|
||||
要熟悉编程语言能够理解的关键字集。在实践中,你的代码将不仅仅包含编程语言的关键字,可以肯定的是,有包含很多简单函数的库来帮助你做一些事情,诸如将输出打印到屏幕或显示窗口之类。然而,驱动这些库的逻辑始于编程语言的内置关键字。
|
||||
|
||||
### 3、数据类型
|
||||
|
||||
![Data types][12]
|
||||
|
||||
代码是用来处理数据的,因此你必须学习编程语言如何识别不同类型的数据。所有编程语言都能理解整数,大多数的语言能理解小数和单个字符(`a`、`b`、`c` 等等)。它们通常被表示为 `int`、 `float`、`double` 和 `char`,当然,语言的内置词汇表会告诉你如何引用这些实体。
|
||||
|
||||
有时候,在编程语言中内置了一些额外的数据类型,也有时是通过引用库来启用复杂的数据类型。例如,Python 可以识别关键字为 `str` 的字符串,但是 C 语言的代码中必须包含 `string.h` 头文件才能实现字符串特性。
|
||||
|
||||
#### 实践
|
||||
|
||||
库可以为你的代码解锁各种类型的数据,但是学习编程语言中包含的基本数据类型是一个明智的起点。
|
||||
|
||||
### 4、运算符和解析器
|
||||
|
||||
![Operators][13]
|
||||
|
||||
一旦你理解了编程语言可处理的数据类型,就可以学习如何分析这些数据了。幸运的是,数学这门学科是相当稳定的,所以算数运算符在许多语言中通常是相同的(或至少非常相似)。例如,两个整数相加通常用 `+` 符号完成,而测试一个整数是否大于另一个整数通常用 `>` 符号完成。测试是否相等通常使用 `==` 来完成(是的,是两个等号,因为通常一个等号用来赋值)。
|
||||
|
||||
当然也有一些例外,比如像 Lisp 和 Bash 语言算数运算符就不是如此,但与其他语言一样,这只是一个心理翻译的问题。一旦你了解了表达方式有何不同,很快就可以适应它。快速浏览一下一门编程语言的算数运算符通常足以让你了解算数操作是如何完成的。
|
||||
|
||||
你还需要知道如何比较和操作非数值数据,比如字符和字符串。这些通常是通过编程语言的核心库来进行的的。例如,Python 提供了 `split()` 方法,而 C 语言需要引入头文件 `string.h` 来提供 `strtok()` 函数。
|
||||
|
||||
#### 实践
|
||||
|
||||
了解用于处理基本数据类型的基本函数和关键字,并寻找可帮助你完成复杂操作的核心库。
|
||||
|
||||
### 5、函数
|
||||
|
||||
![Class][14]
|
||||
|
||||
代码不只是计算机的待办清单。通常情况下,在编写代码时你往往希望向计算机提供一组理论条件和一组操作指令,当满足每个条件时计算机就会采取这些操作。尽管使用条件语句以及数学和逻辑运算符进行流控制可以做很多事情,但是引入了函数和类之后,代码会变得更加高效,因为它们使你可以定义子程序。例如,如果应用程序非常频繁地需要一个确认对话框,那么将其作为类的实例编写一次要比每次需要它时重新编写实现起来要容易得多。
|
||||
|
||||
你需要学习如何在编程语言中定义类和函数。更准确地说,你首先需要了解编程语言中是否支持类和函数。大多数现代语言都支持函数,但是类是面向对象的编程语言中所特有的。
|
||||
|
||||
#### 实践
|
||||
|
||||
学习语言中可用的结构,这些结构可以帮助你高效地编写和使用代码。
|
||||
|
||||
### 你可以学到任何东西
|
||||
|
||||
学习编程语言,就其本身而言,是一种编码过程中的子程序。一旦理解了代码如何工作,你所使用的语言就只是一种传递逻辑的媒介。学习一门新编程语言的过程几乎都是一样的:通过简单的练习来学习语法,通过学习词汇来积累进行复杂动作的能力,然后练习、练习、再练习。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/10/learn-any-programming-language
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[xiao-song-123](https://github.com/xiao-song-123)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/learn-programming-code-keyboard.png?itok=xaLyptT4 "Learning to program"
|
||||
[2]: https://opensource.com/article/20/9/scratch
|
||||
[3]: https://opensource.com/sites/default/files/uploads/syntax_0.png "Syntax"
|
||||
[4]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[5]: https://opensource.com/downloads/cheat-sheet-python-37-beginners
|
||||
[6]: https://opensource.com/article/20/2/lua-cheat-sheet
|
||||
[7]: https://opensource.com/downloads/java-cheat-sheet
|
||||
[8]: https://opensource.com/downloads/c-programming-cheat-sheet
|
||||
[9]: https://opensource.com/resources/what-ide
|
||||
[10]: https://opensource.com/sites/default/files/uploads/builtin.png "built-in words"
|
||||
[11]: https://opensource.com/downloads/bash-cheat-sheet
|
||||
[12]: https://opensource.com/sites/default/files/uploads/type.png "Data types"
|
||||
[13]: https://opensource.com/sites/default/files/uploads/operator.png "Operators"
|
||||
[14]: https://opensource.com/sites/default/files/uploads/class.png "Class"
|
||||
167
published/20201023 Secure NTP with NTS.md
Normal file
167
published/20201023 Secure NTP with NTS.md
Normal file
@@ -0,0 +1,167 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12860-1.html)
|
||||
[#]: subject: (Secure NTP with NTS)
|
||||
[#]: via: (https://fedoramagazine.org/secure-ntp-with-nts/)
|
||||
[#]: author: (Miroslav Lichvar https://fedoramagazine.org/author/mlichvar/)
|
||||
|
||||
用 NTS 保证 NTP 的安全
|
||||
======
|
||||
|
||||

|
||||
|
||||
许多计算机使用<ruby>网络时间协议<rt>Network Time Protocol</rt></ruby>(NTP)通过互联网来同步系统时钟。NTP 是少数几个仍在普遍使用的不安全的互联网协议之一。攻击者如果能够观察到客户端和服务器之间的网络流量,就可以向客户端提供虚假的数据,并根据客户端的实现和配置,强迫其将系统时钟设置为任何时间和日期。如果客户端的系统时钟不准确,一些程序和服务就可能无法工作。例如,如果根据客户端的系统时钟,Web 服务器的证书似乎已经过期,Web 浏览器将无法正常工作。可以使用<ruby>网络时间安全<rt>Network Time Security</rt></ruby>(NTS)来保证 NTP 的安全。
|
||||
|
||||
Fedora 33 [^1] 是第一个支持 NTS 的 Fedora 版本。NTS 是一种新的 NTP 验证机制。它使客户端能够验证它们从服务器接收的数据包在传输过程中有没有被修改。当 NTS 启用时,攻击者唯一能做的就是丢弃或延迟数据包。关于 NTS 的更多细节,请参见 [RFC8915][3]。
|
||||
|
||||
使用对称密钥可以很好地保证 NTP 的安全。遗憾的是,服务器必须为每个客户端配备不同的密钥,而且密钥必须安全地分发才行。这对于本地网络上的私有服务器来说可能是实用的,但它不能扩展到有着数百万客户端的公共服务器上。
|
||||
|
||||
NTS 包括一个<ruby>密钥建立<rt>Key Establishment</rt></ruby>(NTS-KE)协议,它可以自动创建服务器与其客户端之间使用的加密密钥。它在 TCP 端口 4460 上使用<ruby>传输层安全<rt>Transport Layer Security</rt></ruby>(TLS)。它被设计成可以扩展到非常多的客户端,而对准确性的影响最小。服务器不需要保存任何客户端特定的状态。它为客户提供 cookie,cookie 是加密的,包含验证 NTP 数据包所需的密钥。隐私是 NTS 的目标之一。客户端在每次服务器响应时都会得到一个新的 cookie,所以它不必重复使用 cookie。这可以防止被动观察者跟踪在网络之间迁移的客户端。
|
||||
|
||||
Fedora 中默认的 NTP 客户端是 Chrony。Chrony 在 4.0 版本中增加了 NTS 支持,但并没有改变默认配置。Chrony 仍然使用 [pool.ntp.org][4] 项目中的公共服务器,而且默认情况下 NTS 没有启用。
|
||||
|
||||
目前,支持 NTS 的公共 NTP 服务器非常少。两个主要的提供商是 Cloudflare 和 Netnod。[Cloudflare 服务器][5]分布在世界各地的不同地方。他们使用的是<ruby>任播<rt>anycast</rt></ruby>地址,应该可以让大多数客户到达一个接近的服务器。[Netnod 服务器][6]位于瑞典。在未来,我们可能会看到更多支持 NTS 的公共 NTP 服务器。
|
||||
|
||||
为了获得最佳的可靠性,配置 NTP 客户端的一般建议是至少有三个工作的服务器。为了达到最好的精度,建议选择距离较近的服务器,以减少网络延迟和非对称网络路由造成的不对称性。如果你不关心细粒度的精度,你可以忽略这个建议,使用任何你信任的 NTS 服务器,无论它们位于哪里。
|
||||
|
||||
如果你确实想要高准确度,但又没有近距离的 NTS 服务器,你可以将远处的 NTS 服务器和近处的非 NTS 服务器混合使用。但是,这样的配置不如只使用 NTS 服务器的配置安全。攻击者仍然不能强迫客户机接受任意时间,但他们确实对客户机的时钟及其估计精度有更大的控制权,这在某些环境下可能是不可接受的。
|
||||
|
||||
### 在安装程序中启用客户端 NTS
|
||||
|
||||
安装 Fedora 33 时,你可以在“Time & Date”对话框的“Network Time”配置中启用 NTS。在点击“+”(添加)按钮之前,请输入服务器的名称并检查 NTS 支持情况。你可以添加一个或多个具有 NTS 的服务器或池。要删除默认的服务器池(`2.fedora.pool.ntp.org`),请取消选中“Use”列中的相应标记。
|
||||
|
||||
![Fedora 安装程序中的网络时间配置][7]
|
||||
|
||||
### 在配置文件中启用客户端 NTS
|
||||
|
||||
如果你从之前的 Fedora 版本升级,或者你没有在安装程序中启用 NTS,你可以直接在 `/etc/chrony.conf` 中启用 NTS。除了推荐的 `iburst` 选项外,还可以对指定服务器使用 `nts` 选项。例如:
|
||||
|
||||
```
|
||||
server time.cloudflare.com iburst nts
|
||||
server nts.sth1.ntp.se iburst nts
|
||||
server nts.sth2.ntp.se iburst nts
|
||||
```
|
||||
|
||||
你还应该允许客户端将 NTS 密钥和 cookie 保存到磁盘上,这样它就不必在每次启动时重复 NTS-KE 会话。在 `chrony.conf` 中添加以下一行,如果还没有的话:
|
||||
|
||||
```
|
||||
ntsdumpdir /var/lib/chrony
|
||||
```
|
||||
|
||||
如果不想让 DHCP 提供的 NTP 服务器与你指定的服务器混在一起,请在 `chrony.conf` 中删除或注释以下一行:
|
||||
|
||||
```
|
||||
sourcedir /run/chrony-dhcp
|
||||
```
|
||||
|
||||
当你完成编辑 `chrony.conf` 后,保存你的更改并重新启动 `chronyd` 服务:
|
||||
|
||||
```
|
||||
systemctl restart chronyd
|
||||
```
|
||||
|
||||
### 检查客户端状态
|
||||
|
||||
在 root 用户下运行以下命令,检查 NTS 密钥建立是否成功:
|
||||
|
||||
```
|
||||
# chronyc -N authdata
|
||||
Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
|
||||
=========================================================================
|
||||
time.cloudflare.com NTS 1 15 256 33m 0 0 8 100
|
||||
nts.sth1.ntp.se NTS 1 15 256 33m 0 0 8 100
|
||||
nts.sth2.ntp.se NTS 1 15 256 33m 0 0 8 100
|
||||
```
|
||||
|
||||
`KeyID`、`Type` 和 `KLen` 列应该有非零值。如果它们为零,请检查系统日志中是否有来自 `chronyd` 的错误信息。一个可能的故障原因是防火墙阻止了客户端与服务器的 TCP 端口(端口 4460)的连接。
|
||||
|
||||
另一个可能的故障原因是由于客户机的时钟错误而导致证书无法验证。这是 NTS 的先有鸡还是先有蛋的问题。你可能需要手动修正日期或暂时禁用 NTS,以使 NTS 正常工作。如果你的电脑有实时时钟,几乎所有的电脑都有,而且有好的电池做备份,这种操作应该只需要一次。
|
||||
|
||||
如果计算机没有实时时钟或电池,就像一些常见的小型 ARM 计算机(如树莓派)那样,你可以在 `/etc/sysconfig/chronyd` 中添加 `-s` 选项来恢复上次关机或重启时保存的时间。时钟会落后于真实时间,但如果电脑没有关机太久,服务器的证书也没有在离到期时间太近的时候更新,应该足以让时间检查成功。作为最后的手段,你可以用 `nocerttimecheck` 指令禁用时间检查。详情请参见`chrony.conf(5)` 手册页。
|
||||
|
||||
运行下面的命令来确认客户端是否在进行 NTP 测量:
|
||||
|
||||
```
|
||||
# chronyc -N sources
|
||||
MS Name/IP address Stratum Poll Reach LastRx Last sample
|
||||
===============================================================================
|
||||
^* time.cloudflare.com 3 6 377 45 +355us[ +375us] +/- 11ms
|
||||
^+ nts.sth1.ntp.se 1 6 377 44 +237us[ +237us] +/- 23ms
|
||||
^+ nts.sth2.ntp.se 1 6 377 44 -170us[ -170us] +/- 22ms
|
||||
```
|
||||
|
||||
`Reach` 列应该有一个非零值,最好是 377。上图所示的值 377 是一个八进制数,它表示最后八个请求都有有效的响应。如果启用了 NTS 的话,验证检查将包括 NTS 认证。如果该值一直很少或从未达到 377,则表明 NTP 请求或响应在网络中丢失了。众所周知,一些主要的网络运营商有中间设备,它可以阻止或限制大的 NTP 数据包的速率,以缓解利用 `ntpd` 的监控协议进行的放大攻击。不幸的是,这影响了受 NTS 保护的 NTP 数据包,尽管它们不会引起任何放大。NTP 工作组正在考虑为 NTP 提供一个替代端口,作为解决这个问题的办法。
|
||||
|
||||
### 在服务器上启用 NTS
|
||||
|
||||
如果你有自己的 NTP 服务器,运行着 `chronyd`,你可以启用服务器的 NTS 支持,让它的客户端安全同步。如果该服务器是其他服务器的客户端,它应该使用 NTS 或对称密钥与之同步。客户端假设同步链在所有服务器到主时间服务器之间是安全的。
|
||||
|
||||
启用服务器 NTS 类似于在 Web 服务器上启用 HTTPS。你只需要一个私钥和证书。例如,证书可以由 Let's Encrypt 权威机构使用 `certbot` 工具签署。当你有了密钥和证书文件(包括中间证书),在 `chrony.conf` 中用以下指令指定它们:
|
||||
|
||||
```
|
||||
ntsserverkey /etc/pki/tls/private/foo.example.net.key
|
||||
ntsservercert /etc/pki/tls/certs/foo.example.net.crt
|
||||
```
|
||||
|
||||
确保之前在客户端配置中提到的 `ntsdumpdir` 指令存在于 `chrony.conf` 中。它允许服务器将其密钥保存到磁盘上,这样服务器的客户端在重启服务器时就不必获取新的密钥和 cookie 了。
|
||||
|
||||
重新启动 `chronyd` 服务:
|
||||
|
||||
```
|
||||
systemctl restart chronyd
|
||||
```
|
||||
|
||||
如果系统日志中没有来自 `chronyd` 的错误信息,那么它应该是可以接受客户端连接的,如果服务器有防火墙,则需要同时允许 UDP 123 和 TCP 4460 端口的 NTP 和 NTS-KE 服务。
|
||||
|
||||
你可以用下面的命令在客户端机器上进行快速测试:
|
||||
|
||||
```
|
||||
$ chronyd -Q -t 3 'server foo.example.net iburst nts maxsamples 1'
|
||||
2020-10-13T12:00:52Z chronyd version 4.0 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCDNS +NTS +SECHASH +IPV6 +DEBUG)
|
||||
2020-10-13T12:00:52Z Disabled control of system clock
|
||||
2020-10-13T12:00:55Z System clock wrong by -0.001032 seconds (ignored)
|
||||
2020-10-13T12:00:55Z chronyd exiting
|
||||
```
|
||||
|
||||
如果你看到一个“System clock wrong”消息,说明它是正确工作的。
|
||||
|
||||
在服务器上,你可以使用下面的命令来检查它已经处理了多少个 NTS-KE 连接和认证的 NTP 数据包:
|
||||
|
||||
```
|
||||
# chronyc serverstats
|
||||
NTP packets received : 2143106240
|
||||
NTP packets dropped : 117180834
|
||||
Command packets received : 16819527
|
||||
Command packets dropped : 0
|
||||
Client log records dropped : 574257223
|
||||
NTS-KE connections accepted: 104
|
||||
NTS-KE connections dropped : 0
|
||||
Authenticated NTP packets : 52139
|
||||
```
|
||||
|
||||
如果你看到非零的 “NTS-KE connections accepted” 和 “Authenticated NTP packets”,这意味着至少有一些客户端能够连接到 NTS-KE 端口,并发送一个认证的 NTP 请求。
|
||||
|
||||
[^1]: Fedora 33 Beta 安装程序包含一个较旧的 Chrony 预发布版本,它不能与当前的 NTS 服务器一起工作,因为 NTS-KE 端口已经改变。因此,在安装程序中的网络时间配置中,服务器总是显示为不工作。安装后,需要更新 chrony 包,才能与当前的服务器配合使用。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/secure-ntp-with-nts/
|
||||
|
||||
作者:[Miroslav Lichvar][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/mlichvar/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2020/10/secure-ntp-with-nts-816x345.jpg
|
||||
[2]: tmp.rl0XC1HIGm#footnote1
|
||||
[3]: https://tools.ietf.org/html/rfc8915
|
||||
[4]: https://www.pool.ntp.org
|
||||
[5]: https://developers.cloudflare.com/time-services/nts/usage
|
||||
[6]: https://www.netnod.se/time-and-frequency/how-to-use-nts
|
||||
[7]: https://fedoramagazine.org/wp-content/uploads/2020/10/anaconda-nts.png
|
||||
@@ -0,0 +1,172 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12850-1.html)
|
||||
[#]: subject: (You can Surf Internet in Linux Terminal With These Command Line Browsers)
|
||||
[#]: via: (https://itsfoss.com/terminal-web-browsers/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
使用命令行浏览器在 Linux 终端上网浏览
|
||||
======
|
||||
|
||||

|
||||
|
||||
我猜你阅读这篇文章可能是用 Firefox 或基于 Chrome 的浏览器(如 [Brave][1]),或者,也可能是 Chrome 浏览器或 [Chromium][2]。
|
||||
|
||||
换句话说,你正在利用基于 GUI 的方式浏览网页。然而,在以前,人们使用终端来获取资源和浏览网页,因为所有的东西大多是基于文本的。
|
||||
|
||||
虽然现在不能从终端上获取每个信息,但对于一些文本信息,还是可以尝试使用命令行浏览器,从 Linux 终端上打开网页。
|
||||
|
||||
不仅如此,如果你访问的是远程服务器,或者只有一个没有 GUI 的终端,终端网页浏览器就可以发挥用处了。
|
||||
|
||||
因此,在本文中,我将介绍一些基于终端的 Web 浏览器,你可以在 Linux 上尝试它们。
|
||||
|
||||
### Linux 用户的最佳终端 Web 浏览器
|
||||
|
||||
注:此榜单排名不分先后。
|
||||
|
||||
#### 1、W3M
|
||||
|
||||
![][3]
|
||||
|
||||
`w3m` 是一个流行的基于文本的开源终端 Web 浏览器。尽管其初始项目已经不再活跃,但另一个开发者 Tatsuya Kinoshita 正在维护着它的一个活跃分支。
|
||||
|
||||
`w3m` 相当简单,支持 SSL 连接、色彩,也支持内嵌图片。当然,根据你试图访问的资源,你那边的情况可能会有所不同。根据我的简单测试,它似乎无法加载 [DuckDuckGo][4],但我可以[在终端中使用 Google][5]就够了。
|
||||
|
||||
安装后,你可以简单的在终端中输入 `w3m` 以得到帮助。如果你感兴趣的话,也可以到 [GitHub][6] 上去查看它的仓库。
|
||||
|
||||
**如何安装和使用 w3m?**
|
||||
|
||||
`w3m` 在任何基于 Debian 的 Linux 发行版的默认仓库中都是可用的。如果你有一个基于 Arch 的发行版,但没有直接可用的软件包,你可能需要查看一下 [AUR][7]。
|
||||
|
||||
对于 Ubuntu,你可以通过键入以下内容来安装它:
|
||||
|
||||
```
|
||||
sudo apt install w3m w3m-img
|
||||
```
|
||||
|
||||
在这里,我们将 w3m 包和图片扩展一起安装,以支持内嵌图片。接下来,要开始安装,你只需要按照下面的命令进行操作即可:
|
||||
|
||||
```
|
||||
w3m xyz.com
|
||||
```
|
||||
|
||||
当然,你需要将 `xyz.com` 替换成任何你想浏览或测试的网站。最后,你应该知道,你可以使用键盘上的方向键来导航,当你想采取一个动作时,按回车键。
|
||||
|
||||
要退出,你可以按 `SHIFT+Q`,返回上一页是 `SHIFT+B`。其他快捷键包括用 `SHIFT+T` 打开新标签页和用 `SHIFT+U` 打开新的 URL。
|
||||
|
||||
你可以通过访问它的手册页来了解更多信息。
|
||||
|
||||
#### 2、Lynx
|
||||
|
||||
![][8]
|
||||
|
||||
Lynx 是另一个开源的命令行浏览器,你可以试试。幸运的是,很多的网站在使用 Lynx 时往往能正常工作,所以我说它在这方面肯定更好。我能够加载 DuckDuckGo,并使其工作。
|
||||
|
||||
除此之外,我还注意到它可以让你在访问各种 Web 资源时接受或拒绝 cookie。你也可以将它设置为总是接受或拒绝。所以,这是件好事。
|
||||
|
||||
另一方面,在终端上使用时,窗口不能很好地调整大小。我还没有寻找到任何解决方法,所以如果你正在尝试这个,你可能会想要这样做。不论如何,它都很好用,当你在终端启动它时,你会得到所有键盘快捷键的说明。
|
||||
|
||||
请注意,它与系统终端主题不匹配,所以无论你的终端看起来如何,它都会看起来不同。
|
||||
|
||||
**如何安装 Lynx?**
|
||||
|
||||
与 w3m 不同的是,如果你有兴趣尝试的话,确实可以找到一些 Win32 上的安装程序。不过,在 Linux 上,它在大多数的默认仓库中都是可用的。
|
||||
|
||||
对于 Ubuntu 来说,你只需要输入:
|
||||
|
||||
```
|
||||
sudo apt install lynx
|
||||
```
|
||||
|
||||
要想使用,你只需要按照下面的命令进行操作:
|
||||
|
||||
```
|
||||
lynx examplewebsite.com
|
||||
```
|
||||
|
||||
在这里,你只需要将示例网站替换成你想要访问的资源即可。
|
||||
|
||||
如果你想找其他 Linux 发行版的软件包,可以查看他们的[官网资源][9]。
|
||||
|
||||
#### 3、Links2
|
||||
|
||||
![][10]
|
||||
|
||||
Links2 是一款有趣的基于文本的浏览器,你可以在你的终端上轻松使用,用户体验良好。它提供了一个很好的界面,你启动它后,只要输入网址就可以了。
|
||||
|
||||
![][11]
|
||||
|
||||
值得注意的是,主题将取决于你的终端设置,我设置为“黑绿色”主题,因此你看到的就是这个。当你以命令行浏览器的方式启动它后,你只需要按任意键就会出现 URL 提示,或者按 `Q` 键退出。它相当好用,可以渲染大多数网站的文字。
|
||||
|
||||
与 Lynx 不同的是,你没有接受或拒绝 cookie 的功能。除此之外,它似乎工作的还不错。
|
||||
|
||||
**如何安装 Links2?**
|
||||
|
||||
正如你所期望的,你会发现它在大多数默认的仓库中都有。对于 Ubuntu,你可以在终端输入以下命令来安装它:
|
||||
|
||||
```
|
||||
sudo apt install links2
|
||||
```
|
||||
|
||||
如果你想在其他 Linux 发行版上安装它,你可以参考它的[官方网站][12]获取软件包或文档。
|
||||
|
||||
#### 4、eLinks
|
||||
|
||||
![][13]
|
||||
|
||||
eLinks 类似于 Links2,但它已经不再维护了。你仍然可以在各种发行版的默认仓库中找到它,因此,我把它保留在这个列表中。
|
||||
|
||||
它不会与你的系统终端主题相融合。所以,如果你需要的话,作为一个没有“黑暗”模式的文本型浏览器,这可能不是一个漂亮的体验。
|
||||
|
||||
**如何安装 eLinks?**
|
||||
|
||||
在 Ubuntu 上,安装它很容易。你只需要在终端中输入以下内容:
|
||||
|
||||
```
|
||||
sudo apt install elinks
|
||||
```
|
||||
|
||||
对于其他 Linux 发行版,你应该可以在标准软件仓库中找到它。但是,如果你在软件仓库中找不到它,你可以参考[官方安装说明][14]。
|
||||
|
||||
### 总结
|
||||
|
||||
在终端上运行的基于文本的 Web 浏览器并不多,这并不奇怪。一些项目,如 [Browsh][15],试图呈现一个现代的 Linux 命令行浏览器,但在我这里它不能工作。
|
||||
|
||||
虽然像 `curl` 和 `wget` 这样的工具允许你[从 Linux 命令行下载文件][16],但这些基于终端的 Web 浏览器提供了额外的功能。
|
||||
|
||||
除了命令行浏览器之外,如果你想在终端上玩玩,也可以尝试一些[Linux 命令行游戏][17]。
|
||||
|
||||
对于 Linux 终端上的文本型 Web 浏览器,你有什么看法?欢迎在下面的评论中告诉我你的想法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/terminal-web-browsers/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/brave-web-browser/
|
||||
[2]: https://itsfoss.com/install-chromium-ubuntu/
|
||||
[3]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/10/w3m-google.jpg
|
||||
[4]: https://duckduckgo.com/
|
||||
[5]: https://itsfoss.com/review-googler-linux/
|
||||
[6]: https://github.com/tats/w3m
|
||||
[7]: https://itsfoss.com/aur-arch-linux/
|
||||
[8]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/10/lynx-terminal.jpg
|
||||
[9]: https://lynx.invisible-island.net/lynx-resources.html
|
||||
[10]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/10/links2-terminal.jpg
|
||||
[11]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/10/links2-terminal-welcome.jpg
|
||||
[12]: http://links.twibright.com/download.php
|
||||
[13]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/10/elinks-terminal.jpg
|
||||
[14]: http://elinks.or.cz/documentation/installation.html
|
||||
[15]: https://www.brow.sh/
|
||||
[16]: https://itsfoss.com/download-files-from-linux-terminal/
|
||||
[17]: https://itsfoss.com/best-command-line-games-linux/
|
||||
@@ -0,0 +1,126 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12865-1.html)
|
||||
[#]: subject: (5 new sudo features you need to know in 2020)
|
||||
[#]: via: (https://opensource.com/article/20/10/sudo-19)
|
||||
[#]: author: (Peter Czanik https://opensource.com/users/czanik)
|
||||
|
||||
2020 年 5 个新 sudo 功能
|
||||
======
|
||||
|
||||
> 从集中会话记录、chroot 支持到 Python API,sudo 1.9 提供了许多新功能。
|
||||
|
||||

|
||||
|
||||
当你想在 [POSIX 系统][2]上执行一个操作时,最安全的方法之一就是使用 `sudo` 命令。与以 root 用户身份登录并执行命令可能是个危险的操作不同,`sudo` 授予任何被系统管理员[指定为 “sudoer”][3]的用户临时权限,来执行通常受限制的活动。
|
||||
|
||||
几十年来,这个系统帮助 Linux、Unix 和 macOS 系统免受愚蠢的错误和恶意攻击,它是当今所有主要 Linux 发行版的默认管理机制。
|
||||
|
||||
当在 2020 年 5 月发布 sudo 1.9 时,它带来了许多新功能,包括集中收集会话记录,支持 `sudo` 内的 chroot,以及 Python API。如果你对其中的任何一项感到惊讶,请阅读我的文章,了解一些 [sudo 鲜为人知的功能][4]。
|
||||
|
||||
`sudo` 不仅仅是一个管理命令的前缀。你可以微调权限,记录终端上发生的事情,使用插件扩展`sudo`,在 LDAP 中存储配置,进行广泛的日志记录,以及更多。
|
||||
|
||||
1.9.0 版本和后续的小版本增加了各种新功能(我将在下面介绍),包括:
|
||||
|
||||
* 一个集中收集 `sudo` 会话记录的记录服务
|
||||
* 审计插件 API
|
||||
* 审批插件 API
|
||||
* Python 对插件的支持
|
||||
* `sudo` 内置 chroot 和 CWD 支持(从 1.9.3 开始)
|
||||
|
||||
### 哪里可以得到 sudo 1.9?
|
||||
|
||||
大多数的 Linux 发行版仍然封装了上一代的 `sudo`(1.8 版本),并且在长期支持(LTS)的发行版中会保持这个版本数年。据我所知,提供了最完整的 sudo 1.9 包的 Linux 发行版是 openSUSE[Tumbleweed][5],它是一个滚动发行版,而且该 `sudo` 包的子包中有 Python 支持。最近的 [Fedora][6] 版本包含了 sudo 1.9,但没有 Python 支持。[FreeBSD Ports][7] 有最新的 `sudo` 版本,如果你自己编译 `sudo` 而不是使用软件包,你可以启用 Python 支持。
|
||||
|
||||
如果你喜欢的 Linux 发行版还没有包含 sudo 1.9,请查看 [sudo 二进制页面][8]来查看是否有现成的包可以用于你的系统。这个页面还提供了一些商用 Unix 变种的软件包。
|
||||
|
||||
像往常一样,在你开始试验 `sudo` 设置之前,*确保你知道 root 密码*。是的,即使在 Ubuntu 上也是如此。有一个临时的“后门”是很重要的;如果没有这个后门,如果出了问题,你就必须得黑掉自己的系统。记住:语法正确的配置并不意味着每个人都可以在该系统上通过 `sudo` 做任何事情!
|
||||
|
||||
### 记录服务
|
||||
|
||||
记录服务可以集中收集会话记录。与本地会话记录存储相比,这有很多优势:
|
||||
|
||||
* 更方便地在一个地方进行搜索,而不是访问各个机器来寻找记录
|
||||
* 即使在发送机器停机的情况下也可以进行记录
|
||||
* 本地用户若想掩盖其轨迹,不能删除记录
|
||||
|
||||
为了快速测试,你可以通过非加密连接向记录服务发送会话。我的博客中包含了[说明][9],可以在几分钟内完成设置。对于生产环境,我建议使用加密连接。有很多可能性,所以请阅读最适合你的环境的[文档][10]。
|
||||
|
||||
### 审计插件 API
|
||||
|
||||
新的审计插件 API 不是一个用户可见的功能。换句话说,你不能从 `sudoers` 文件中配置它。它是一个 API,意味着你可以从插件中访问审计信息,包括用 Python 编写的插件。你可以用很多不同的方式来使用它,比如当一些有趣的事情发生时,从 `sudo` 直接发送事件到 Elasticsearch 或日志即服务(LaaS)上。你也可以用它来进行调试,并以任何你喜欢的格式将其他难以访问的信息打印到屏幕上。
|
||||
|
||||
根据你使用它的方式,你可以在 `sudo` 插件手册页(针对 C 语言)和 `sudo` Python 插件手册中找到它的文档。在 `sudo` 源代码中可以找到 [Python 代码示例][11],在我的博客上也有一个[简化的例子][12]。
|
||||
|
||||
### 审批插件 API
|
||||
|
||||
审批插件 API 可以在命令执行之前加入额外的限制。这些限制只有在策略插件成功后才会运行,因此你可以有效地添加额外的策略层,而无需更换策略插件,进而无需更换 `sudoers`。可以定义多个审批插件,而且所有插件都必须成功,命令才能执行。
|
||||
|
||||
与审计插件 API 一样,你可以从 C 和 Python 中使用它。我博客上记录的[示例 Python 代码][13]是对该 API 的一个很好的介绍。一旦你理解了它是如何工作的,你就可以扩展它来将 `sudo` 连接到工单系统,并且只批准有相关开放工单的会话。你也可以连接到人力资源数据库,这样只有当班的工程师才能获得管理权限。
|
||||
|
||||
### Python 对插件的支持
|
||||
|
||||
尽管我不是程序员,但我最喜欢的 sudo 1.9 新特性是 Python 对插件的支持。你可以用 Python 也能使用 C 语言调用大部分 API。幸运的是,`sudo` 对性能不敏感,所以运行速度相对较慢的 Python 代码对 `sudo` 来说不是问题。使用 Python 来扩展 `sudo` 有很多优势:
|
||||
|
||||
* 更简单、更快速的开发
|
||||
* 不需要编译;甚至可以通过配置管理分发代码
|
||||
* 许多 API 没有现成的 C 客户端,但有 Python 代码
|
||||
|
||||
除了审计和审批插件 API 之外,还有一些其他的 API,你可以用它们做一些非常有趣的事情。
|
||||
|
||||
通过使用策略插件 API,你可以取代 `sudo` 策略引擎。请注意,你将失去大部分的 `sudo` 功能,而且没有基于 `sudoers` 的配置。这在小众情况下还是很有用的,但大多数时候,最好还是继续使用 `sudoers`,并使用审批插件 API 创建额外的策略。如果你想尝试一下,我的 [Python 插件介绍][14]提供了一个非常简单的策略:只允许使用 `id` 命令。再次确认你知道 root 密码,因为一旦启用这个策略,它就会阻止任何实际使用 `sudo` 的行为。
|
||||
|
||||
使用 I/O 日志 API,你可以访问用户会话的输入和输出。这意味着你可以分析会话中发生了什么,甚至在发现可疑情况时终止会话。这个 API 有很多可能的用途,比如防止数据泄露。你可以监控屏幕上的关键字,如果数据流中出现任何关键字,你可以在关键字出现在用户的屏幕上之前中断连接。另一种可能是检查用户正在输入的内容,并使用这些数据来重建用户正在输入的命令行。例如,如果用户输入 `rm -fr /`,你可以在按下回车键之前就断开用户的连接。
|
||||
|
||||
组插件 API 允许非 Unix 组的查找。在某种程度上,这与审批插件 API 类似,因为它也扩展了策略插件。你可以检查一个用户是否属于一个给定的组,并在后面的配置部分基于此采取行动。
|
||||
|
||||
### chroot 和 CWD 支持
|
||||
|
||||
`sudo` 的最新功能是支持 chroot 和改变工作目录(CWD),这两个选项都不是默认启用的,你需要在 `sudoers` 文件中明确启用它们。当它们被启用时,你可以调整目标目录或允许用户指定使用哪个目录。日志反映了这些设置何时被使用。
|
||||
|
||||
在大多数系统中,chroot 只对 root 用户开放。如果你的某个用户需要 chroot,你需要给他们 root 权限,这比仅仅给他们 chroot 权限要大得多。另外,你可以通过 `sudo` 允许访问 chroot 命令,但它仍然允许漏洞,他们可以获得完全的权限。当你使用 `sudo` 内置的 chroot 支持时,你可以轻松地限制对单个目录的访问。你也可以让用户灵活地指定根目录。当然,这可能会导致灾难(例如,`sudo --chroot / -s`),但至少事件会被记录下来。
|
||||
|
||||
当你通过 `sudo` 运行一个命令时,它会将工作目录设置为当前目录。这是预期的行为,但可能有一些情况下,命令需要在不同的目录下运行。例如,我记得使用过一个应用程序,它通过检查我的工作目录是否是 `/root` 来检查我的权限。
|
||||
|
||||
### 尝试新功能
|
||||
|
||||
希望这篇文章能启发你仔细研究一下 sudo 1.9。集中会话记录比在本地存储会话日志更加方便和安全。chroot 和 CWD 支持为你提供了额外的安全性和灵活性。而使用 Python 来扩展 `sudo`,可以很容易地根据你的环境来定制 `sudo`。你可以通过使用最新的 Linux 发行版或 `sudo` 网站上的即用型软件包来尝试这些新功能。
|
||||
|
||||
如果你想了解更多关于 sudo 的信息,这里有一些资源:
|
||||
|
||||
* [Sudo 官网][15]
|
||||
* [Sudo 博客][16]
|
||||
* [Sudo on Twitter][17]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/10/sudo-19
|
||||
|
||||
作者:[Peter Czanik][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/czanik
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/tools_osyearbook2016_sysadmin_cc.png?itok=Y1AHCKI4 (Wratchet set tools)
|
||||
[2]: https://opensource.com/article/19/7/what-posix-richard-stallman-explains
|
||||
[3]: https://opensource.com/article/17/12/using-sudo-delegate
|
||||
[4]: https://opensource.com/article/19/10/know-about-sudo
|
||||
[5]: https://software.opensuse.org/distributions/tumbleweed
|
||||
[6]: https://getfedora.org/
|
||||
[7]: https://www.freebsd.org/ports/
|
||||
[8]: https://www.sudo.ws/download.html#binary
|
||||
[9]: https://blog.sudo.ws/posts/2020/03/whats-new-in-sudo-1.9-recording-service/
|
||||
[10]: https://www.sudo.ws/man/sudo_logsrvd.man.html#EXAMPLES
|
||||
[11]: https://github.com/sudo-project/sudo/blob/master/plugins/python/example_audit_plugin.py
|
||||
[12]: https://blog.sudo.ws/posts/2020/06/sudo-1.9-using-the-new-audit-api-from-python/
|
||||
[13]: https://blog.sudo.ws/posts/2020/08/sudo-1.9-using-the-new-approval-api-from-python/
|
||||
[14]: https://blog.sudo.ws/posts/2020/01/whats-new-in-sudo-1.9-python/
|
||||
[15]: https://www.sudo.ws/
|
||||
[16]: https://blog.sudo.ws/
|
||||
[17]: https://twitter.com/sudoproject
|
||||
90
published/20201106 Reclaim hard-drive space with LVM.md
Normal file
90
published/20201106 Reclaim hard-drive space with LVM.md
Normal file
@@ -0,0 +1,90 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12864-1.html)
|
||||
[#]: subject: (Reclaim hard-drive space with LVM)
|
||||
[#]: via: (https://fedoramagazine.org/reclaim-hard-drive-space-with-lvm/)
|
||||
[#]: author: (Troy Curtis Jr https://fedoramagazine.org/author/troycurtisjr/)
|
||||
|
||||
使用 LVM 扩展卷空间
|
||||
======
|
||||
|
||||

|
||||
|
||||
LVM 是一个逻辑卷管理工具,包括分配磁盘、条带化、镜像和调整逻辑卷的大小。它在 Fedora 安装中被普遍使用(在 BTRFS 作为默认文件系统之前是 LVM + Ext4)。但是你是否曾经遇到过启动系统时,GNOME 提示 home 卷几乎没有空间了!幸运的是,很有可能有一些空间在另一个卷中,而未被使用,可以用于重新分配。下面就来看看如何用 LVM 回收硬盘空间。
|
||||
|
||||
在卷之间轻松重新分配空间的关键是[逻辑卷管理器(LVM)][2]。Fedora 32 及以前的系统默认使用 LVM 来划分磁盘空间。这种技术类似于标准的硬盘分区,但 LVM 更加灵活。LVM 不仅可以实现灵活的卷大小管理,还可以实现一些高级功能,比如读写快照、在多个硬盘上进行数据条带化或镜像、将高速硬盘作为慢速硬盘的缓存等等。所有这些高级选项可能会让人有点不知所措,但调整卷的大小很简单的。
|
||||
|
||||
### LVM 基础
|
||||
|
||||
**卷组**(VG)作为 LVM 系统中的主要容器。默认情况下,Fedora 只定义了一个卷组,但你可以根据需要定义多个卷组。实际的硬盘和硬盘分区被添加到卷组中作为**物理卷**(PV)。物理卷会将可用的空间添加到卷组中。一个典型的 Fedora 安装有一个格式化的启动分区,其余的硬盘是一个配置为 LVM 物理卷的分区。
|
||||
|
||||
从这个可用空间池中,卷组分配了一个或多个**逻辑卷**(LV)。这些卷类似于硬盘分区,但没有磁盘上连续空间的限制。LVM 的逻辑卷甚至可以跨越多个设备!就像硬盘分区一样,逻辑卷有一个定义的大小,可以包含任何文件系统,然后可以挂载到特定的目录。
|
||||
|
||||
### 需要什么
|
||||
|
||||
在 gnome-disks 应用中确认系统使用 LVM ,并确保其他卷中有可用的空间。如果没有可以从另一个卷中回收的空间,这个指南就没有用。还需要一个 [Fedora 临场 CD/USB][3]。任何需要收缩的文件系统都必须卸载。从<ruby>临场<rt>Live</rt></ruby>镜像运行,可以让硬盘上的所有卷保持未挂载状态,甚至包括像 `/` 和 `/home` 这样的重要目录。
|
||||
|
||||
![Use gnome-disks to verify free space][4]
|
||||
|
||||
### 一句话警告
|
||||
|
||||
按照这个指南,应该不会丢失任何数据,但它确实会使用一些非常底层和强大的命令。一个错误可能会破坏硬盘上的所有数据。所以要先备份磁盘上的所有数据!
|
||||
|
||||
### 调整 LVM 卷的大小
|
||||
|
||||
开始时,启动 Fedora 临场镜像并在对话框中选择 “Try Fedora”。接下来,使用 “Run Command” 启动 “blivet-gui” 应用(按 `Alt-F2`,输入 `blivet-gui`,然后按回车)。选择左侧 “LVM” 下的卷组。逻辑卷在右边。
|
||||
|
||||
![Explore logical volumes in blivet-gui][5]
|
||||
|
||||
逻辑卷标签由卷组名称和逻辑卷名称组成。在本例中,卷组是 `fedora_localhost-live`,分配了 `home`、`root` 和 `swap` 逻辑卷。要找到完整的卷,选择每一个卷,点击“齿轮”图标,然后选择 “resize”。调整大小对话框中的滑块表示卷的允许大小。左边的最小值是文件系统中已经使用的空间,所以这是最小可能的尺寸大小(不删除数据)。右边的最大值是基于卷组中的最大可用空间。
|
||||
|
||||
![Resize dialog in blivet-gui][6]
|
||||
|
||||
灰色的 “resize” 选项意味着该卷已经满了,而且卷组中没有可用空间。
|
||||
|
||||
现在可以更改大小了!查看所有的卷,就像上面的截图那样,找到一个有足够空间的卷。并像上面的截图那样,在所有的卷中找到一个有大量额外空间的卷。向左移动滑块来设置新的大小。腾出足够的空间对整个卷有用,但仍然要为未来的数据增长留出足够的空间。否则,这个卷将是下一个被填满的卷。
|
||||
|
||||
点击 “resize”,注意卷列表中出现了一个新项目:“free space”。现在选择这次要调整的卷,并将滑块一直向右移动。按 “resize” 键,并查看新改进的卷的布局。然而,硬盘驱动器上的任何东西现在都还没有改变。点击“勾选”选项将更改提交到磁盘。
|
||||
|
||||
![Review changes in blivet-gui][7]
|
||||
|
||||
查看更改的摘要,如果一切看起来都是正确的,点击 “Ok” 继续。等待 “blivet-gui” 完成。现在重新启动回到 Fedora,可以使用之前被充满的卷上的新空间了。
|
||||
|
||||
### 为未来计划
|
||||
|
||||
要知道任何特定卷在未来需要多少空间是很困难的。与其立即分配所有可用的空闲空间,不如考虑在卷组中留出空闲空间。事实上,Fedora Server 默认在卷组中保留空间。当一个卷处于在线和使用中时,扩展卷是可能的。不需要临场镜像或重启。当一个卷几乎满的时候,可以使用部分可用空间轻松扩展卷并继续工作。遗憾的是,默认的磁盘管理器 gnome-disks 不支持 LVM 卷的大小调整,所以安装 [blivet-gui][8] 作为图形化管理工具。另外,还有一个简单的终端命令来扩展卷:
|
||||
|
||||
```
|
||||
lvresize -r -L +1G /dev/fedora_localhost-live/root
|
||||
```
|
||||
|
||||
### 总结
|
||||
|
||||
用 LVM 回收硬盘空间只是 LVM 功能的表面。大多数人,特别是在桌面中,可能不需要更高级的功能。然而,当需要的时候,LVM 就在那里,尽管它的实现可能会变得有点复杂。从 [Fedora 33][10] 开始,[BTRFS][9] 是默认的文件系统,没有 LVM。BTRFS 可以更容易管理,同时对于大多数常见的使用来说也足够灵活。查看最近 [Fedora Magazine 关于 BTRFS 的文章][11]了解更多。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/reclaim-hard-drive-space-with-lvm/
|
||||
|
||||
作者:[Troy Curtis Jr][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/troycurtisjr/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2020/11/lvm-resize-816x345.jpg
|
||||
[2]: http://sourceware.org/lvm2/
|
||||
[3]: https://getfedora.org/en/workstation/download/
|
||||
[4]: https://fedoramagazine.org/wp-content/uploads/2020/11/gnome-disks.png
|
||||
[5]: https://fedoramagazine.org/wp-content/uploads/2020/11/blivet-overview.png
|
||||
[6]: https://fedoramagazine.org/wp-content/uploads/2020/11/blivet-resize-1024x525.png
|
||||
[7]: https://fedoramagazine.org/wp-content/uploads/2020/11/blivet-summary-1024x525.png
|
||||
[8]: https://fedoraproject.org/wiki/Blivet-gui
|
||||
[9]: https://fedoramagazine.org/btrfs-coming-to-fedora-33/
|
||||
[10]: https://fedoramagazine.org/whats-new-fedora-33-workstation/
|
||||
[11]: https://fedoramagazine.org/btrfs-snapshots-backup-incremental/
|
||||
@@ -1,46 +1,40 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12839-1.html)
|
||||
[#]: subject: (What I love about the newest GNOME desktop)
|
||||
[#]: via: (https://opensource.com/article/20/11/new-gnome)
|
||||
[#]: author: (Jim Hall https://opensource.com/users/jim-hall)
|
||||
|
||||
我对最新的 GNOME 桌面的喜爱之处
|
||||
我喜欢最新的 GNOME 桌面
|
||||
======
|
||||
看看 GNOME 3.38 桌面的最新功能。
|
||||
![Digital images of a computer desktop][1]
|
||||
|
||||
> 看看 GNOME 3.38 桌面最重要的新功能。
|
||||
|
||||

|
||||
|
||||
Fedora 33 [刚出来][2],我就马上安装了它。在这个新版 Linux 发行版的众多功能中,其中之一是最新的 GNOME 桌面。GNOME 3.38 于 2020 年 9 月发布,我很喜欢它。
|
||||
|
||||
### 我为什么喜欢 GNOME 3.38?
|
||||
|
||||
GNOME 3.38 [发布说明][3]中列出了这次更新中的一些重大的新功能。其中,如果你是新用户的话,新用户的欢迎页面得到了重大的改版,现在更加容易使用,并且提供了更多有用的信息。
|
||||
GNOME 3.38 [发布说明][3]中列出了这次更新中的一些重大的新功能。其中,新用户的欢迎页面有了重大改版,现在更加容易使用,如果你是新用户的话,它提供了更多有用的信息。
|
||||
|
||||
![The new "Welcome GNOME"][4]
|
||||
|
||||
([GNOME][5], [CC BY-SA 4.0][6])
|
||||
|
||||
我还喜欢在 GNOME 应用概览中拖动来重新排列应用图标的功能。这让我在 GNOME 下组织我一直使用的应用变得轻而易举。你甚至可以将图标拖放在一起,并自动将它们放入文件夹。
|
||||
我还喜欢在 GNOME 应用概览中拖动来重新排列应用图标的功能。这让我在 GNOME 下组织我一直使用的应用变得轻而易举。你甚至可以将图标拖放到一起,并自动将它们放入一个文件夹。
|
||||
|
||||
![GNOME 3.38 Application Overview][7]
|
||||
|
||||
([GNOME][5], [CC BY-SA 4.0][6])
|
||||
|
||||
我的家人在不同的时区,更新后的 GNOME 时钟使得添加新的世界时钟变得更加容易,所以当我给家人打电话时,我不必弄清楚现在是什么时间。他们是提前一个小时还是晚了一个小时?我只需查看 GNOME 时钟,就能一目了然地看到每个人的当地时间。另外,虽然我并不经常使用闹钟功能,但我喜欢我可以自己设置铃声持续时间和每个闹钟的默认”打盹“时间。
|
||||
我的家人在不同的时区,更新后的 GNOME 时钟使得添加新的世界时钟变得更加容易,所以当我给家人打电话时,我不必弄清楚现在是什么时间,他们是早一个小时还是晚一个小时?我只需查看 GNOME 时钟,就能一目了然地看到每个人的当地时间。另外,虽然我并不经常使用闹钟功能,但我喜欢我可以自己设置铃声持续时间和每个闹钟的默认“打盹”时间。
|
||||
|
||||
![Adding a new world clock in GNOME Clocks][8]
|
||||
|
||||
([GNOME][5], [CC BY-SA 4.0][6])
|
||||
|
||||
除了所有的功能更新之外,GNOME 3.38 中最大的改进是性能。正如 GNOME 开发者 Emmanuele Bassi [今年早些时候的解释][9]:“GNOME 中的每个人都为使速度更快而做了很多工作,即使是在树莓派等更有限的系统上运行的人。为了让 GNOME 表现得更好,大家做了很多工作。因为人们真的很关心它”。而这一点在新版本中体现得淋漓尽致!GNOME 桌面感觉反应更灵敏。
|
||||
除了所有这些功能更新之外,GNOME 3.38 中最大的改进是性能。正如 GNOME 开发者 Emmanuele Bassi [今年早些时候的解释][9]:“GNOME 中的每个人都为使速度更快而做了很多工作,即使是在树莓派等这样受限的系统上运行的人也是如此。为了让 GNOME 表现得更好,大家做了很多工作。因为人们真的很关心它”。而这一点在新版本中体现得淋漓尽致!GNOME 桌面感觉反应更灵敏。
|
||||
|
||||
![Applications running on GNOME 3.38][10]
|
||||
|
||||
([GNOME][5], [CC BY-SA 4.0][6])
|
||||
|
||||
作为我的咨询和培训业务的一部分,我经常在几个开放的应用之间切换,包括 LibreOffice、GIMP、Inkscape、一个网络浏览器等。在 GNOME 3.38 中,启动一个新的应用或在开放应用之间切换感觉更快。
|
||||
作为我的咨询和培训业务的一部分,我经常在几个打开的应用之间切换,包括 LibreOffice、GIMP、Inkscape、Web 浏览器等。在 GNOME 3.38 中,启动一个新的应用或在打开的应用之间切换感觉更快。
|
||||
|
||||
### 除了一件事
|
||||
|
||||
@@ -48,14 +42,10 @@ GNOME 3.38 [发布说明][3]中列出了这次更新中的一些重大的新功
|
||||
|
||||
![GNOME Screenshot tool][11]
|
||||
|
||||
(Jim Hall, [CC BY-SA 4.0][6])
|
||||
|
||||
当我浏览用户界面或电脑屏幕时,我自然会像阅读书籍或杂志那样浏览:从左到右,从上到下。当我使用新的屏幕截图工具进行屏幕截图时,我从左上角开始,然后进行选择。大多数时候,我只需要改变选区的捕捉区域,所以我点击那个按钮,然后寻找截图的按钮。但我总是要花点时间才能找到左上角的**截图**按钮。它并不在窗口的底部,也不是我希望找到它的地方。
|
||||
|
||||
![GNOME Screenshot tool][12]
|
||||
|
||||
(Jim Hall, [CC BY-SA 4.0][6])
|
||||
|
||||
到目前为止,这似乎是我在 GNOME 3.38 中唯一的烦恼。总的来说,我对新的 GNOME 感到非常兴奋。我希望你也是!
|
||||
|
||||
要了解更多关于 GNOME 3.38 的信息,请访问 [GNOME 网站][13]或阅读 [GNOME 3.38 公告][5]。
|
||||
@@ -67,7 +57,7 @@ via: https://opensource.com/article/20/11/new-gnome
|
||||
作者:[Jim Hall][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
112
published/20201111 Using Fedora 33 with Microsoft-s WSL2.md
Normal file
112
published/20201111 Using Fedora 33 with Microsoft-s WSL2.md
Normal file
@@ -0,0 +1,112 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12845-1.html)
|
||||
[#]: subject: (Using Fedora 33 with Microsoft’s WSL2)
|
||||
[#]: via: (https://fedoramagazine.org/wsl-fedora-33/)
|
||||
[#]: author: (Jim Perrin https://fedoramagazine.org/author/jperrin/)
|
||||
|
||||
通过微软的 WSL2 使用 Fedora 33
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
如果你像我一样,你可能会发现自己因为各种原因而运行 Windows,无论是因为工作还是游戏。当然,你可以在虚拟机或容器中运行 Fedora,但这些并不像 Windows 的 Linux 子系统(WSL)那样容易融合到普通的 Windows 体验中。通过 WSL 使用 Fedora 可以让你将这两种环境融合在一起,创造一个奇妙的开发环境。
|
||||
|
||||
### 先决条件
|
||||
|
||||
为了达成这一目标,你需要一些基本条件。你应该运行 Windows 10,并且已经安装了 WSL2。如果没有,请查看[微软文档说明][4],完成后再回来这里。微软建议为了简单起见,将 WSL2 设置为发行版的默认设置。本指南假设你已经这样做了。
|
||||
|
||||
接下来,你将需要一些解压 xz 压缩文件的方法。你可以用另一个基于 WSL 的发行版来解压,或者使用 [7zip][5]。
|
||||
|
||||
### 下载 Fedora 33 rootfs
|
||||
|
||||
由于 Fedora 并没有提供实际的 rootfs 存档,所以我们将借用一个用于生成 Dockerhub 容器镜像的存档。你需要从 fedora-cloud 的 GitHub 仓库下载该 [tar.xz 文件][6] 。一旦你有了这个 tar.xz 文件,解压它,但不要展开 tar 包。你会得到一个类似 `fedora-33-时间标签.tar` 的文件。有了这个文件,你就可以构建镜像了。
|
||||
|
||||
### 组合 WSL Fedora 的构建版本
|
||||
|
||||
我喜欢使用 `c:\distros` 目录,但你可以选择几乎任何你想要的位置。无论你选择什么目录,在你导入该构建版本之前,确保其顶层路径存在。现在打开一个 CMD 或 Powershell 提示符,因为是时候导入了:
|
||||
|
||||
```
|
||||
wsl.exe --import Fedora-33 c:\distros\Fedora-33 $HOME\Downloads\fedora-33.tar
|
||||
```
|
||||
|
||||
你会看到 Fedora-33 显示在 WSL 的列表当中:
|
||||
|
||||
```
|
||||
PS C:\Users\jperrin> wsl.exe -l -v
|
||||
NAME STATE VERSION
|
||||
Fedora-33 Stopped 2
|
||||
```
|
||||
|
||||
下面,你就可以开始在 WSL 中摆弄 Fedora 了,但我们还需要做一些事情来使它真正成为一个有用的 WSL 发行版。
|
||||
|
||||
```
|
||||
wsl -d Fedora-33
|
||||
```
|
||||
|
||||
这将以 root 用户的身份启动 Fedora 的 WSL 实例。下面,你将安装一些核心包并设置一个新的默认用户。你还需要配置 `sudo`,否则你将无法在以后需要安装其他东西时轻松提升权限。
|
||||
|
||||
```
|
||||
dnf update
|
||||
dnf install wget curl sudo ncurses dnf-plugins-core dnf-utils passwd findutils
|
||||
```
|
||||
|
||||
`wslutilites` 使用 `curl` 和 `wget` 来实现与 VS Code 的集成,所以它们很有用。由于你需要使用 COPR 仓库,你需要增加 `dnf` 功能。
|
||||
|
||||
### 添加你的用户
|
||||
|
||||
现在是时候添加你的用户,并将其设置为默认用户。
|
||||
|
||||
```
|
||||
useradd -G wheel 用户名
|
||||
passwd 用户名
|
||||
```
|
||||
|
||||
现在,你已经创建了你的用户名,并添加了密码,确保它们可以工作。退出 WSL 实例,并再次启动它,这次指定用户名。你还要测试 `sudo`,并检查你的 uid。
|
||||
|
||||
```
|
||||
wsl -d Fedora-33 -u 用户名
|
||||
$id -u
|
||||
1000
|
||||
$ sudo cat /etc/shadow
|
||||
```
|
||||
|
||||
假设一切正常,你现在已经准备好在 Windows 中为你的 Fedora 环境设置默认用户。要做到这一点,请退出 WSL 实例并回到 Powershell 中。这个 Powershell 单行代码可以正确配置你的用户:
|
||||
|
||||
```
|
||||
Get-ItemProperty Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss\\*\ DistributionName | Where-Object -Property DistributionName -eq Fedora-33 | Set-ItemProperty -Name DefaultUid -Value 1000
|
||||
```
|
||||
|
||||
现在你应该可以再次启动 WSL,而不需要指定就可以成为自己的用户而不是 root。
|
||||
|
||||
### 自定义!
|
||||
|
||||
至此,你已经有了可以在 WSL 中运行的基本 Fedora 33 环境,但它还没有 Windows 集成的部分。如果你想要这个,有一个 COPR 仓库可以启用。如果你选择添加这部分,你就可以直接在 shell 里面运行 Windows 应用,也可以轻松地将你的 Linux 环境与 VS Code 集成。需要注意的是,COPR 并没有得到 Fedora 基础架构的官方支持。使用该软件包,风险自担。
|
||||
|
||||
```
|
||||
dnf copr enable trustywolf/wslu
|
||||
```
|
||||
|
||||
现在你可以去配置终端、设置一个 Python 开发环境,或者其它你想使用 Fedora 33 的方式。享受吧!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/wsl-fedora-33/
|
||||
|
||||
作者:[Jim Perrin][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/jperrin/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2020/11/wsl-fedora33-816x345.jpg
|
||||
[2]: https://unsplash.com/@matthias_heil?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[3]: https://unsplash.com/s/photos/windows?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[4]: https://docs.microsoft.com/en-us/windows/wsl/install-win10
|
||||
[5]: https://www.7-zip.org/download.html
|
||||
[6]: https://github.com/fedora-cloud/docker-brew-fedora/tree/33/x86_64
|
||||
@@ -1,28 +1,28 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12856-1.html)
|
||||
[#]: subject: (How to Install Google Chrome on Fedora [Beginner’s Tutorial])
|
||||
[#]: via: (https://itsfoss.com/install-google-chrome-fedora/)
|
||||
[#]: author: (Dimitrios Savvopoulos https://itsfoss.com/author/dimitrios/)
|
||||
|
||||
如何在 Fedora 上安装 Google Chrome 浏览器(入门教程)
|
||||
如何在 Fedora 上安装 Google Chrome 浏览器
|
||||
======
|
||||
|
||||

|
||||
|
||||
Fedora 的默认网页浏览器是 Firefox。尽管它是一个优秀的网络浏览器,你可能更喜欢流行的 Google Chrome 浏览器。
|
||||
|
||||
如果你想知道如何在 Fedora 上安装 Google Chrome 浏览器,让我告诉你两种安装 Google Chrome 浏览器的方法:图形化法和命令行法。
|
||||
如果你想知道如何在 Fedora 上安装 Google Chrome 浏览器,让我告诉你两种安装 Google Chrome 浏览器的方式:图形化方式和命令行方式。
|
||||
|
||||
* [图形化方法 1:通过启用 Fedora 第三方仓库从软件中心安装 Chrom e浏览器][1] 。
|
||||
* [图形化方法 2:从谷歌浏览器网站下载 RPM 文件][2]
|
||||
* [命令行方法:从 Fedora 第三方仓库安装 Chrome,一切使用命令(与 GUI 方法 1 相同)][3]。
|
||||
* [图形化方式 1:通过启用 Fedora 第三方仓库从软件中心安装 Chrome 浏览器][1]
|
||||
* [图形化方式 2:从谷歌浏览器网站下载 RPM 文件][2]
|
||||
* [命令行方式:从 Fedora 第三方仓库安装 Chrome,一切使用命令(与 GUI 方式 1 相同)][3]
|
||||
|
||||
这全取决于你喜欢哪种方式。你在 [Fedora][4] 上的 Google Chrome 浏览器都将通过这三种方式的系统更新获取定期更新。
|
||||
|
||||
|
||||
这全取决于你喜欢哪种方法。你在 [Fedora][4] 上的 Google Chrome 浏览器都将通过这三种方法的系统更新获取定期更新。
|
||||
|
||||
### 方法 1:在 Fedora 中从软件中心安装 Google Chrome
|
||||
### 方式 1:在 Fedora 中从软件中心安装 Google Chrome
|
||||
|
||||
Fedora 提供了一个第三方仓库,其中包含了一些流行的专有软件、图形驱动程序。Google Chrome 就是其中之一。
|
||||
|
||||
@@ -38,16 +38,15 @@ Fedora 提供了一个第三方仓库,其中包含了一些流行的专有软
|
||||
|
||||
![Step 3: Install Chrome Fedora][7]
|
||||
|
||||
Can it be any easier than this? I don’t think either :)
|
||||
还有比这更简单的吗?我不这么认为 :)
|
||||
还有比这更简单的吗?我觉得没有。
|
||||
|
||||
### 方法 2:在 Fedora 上从 Chrome 网站安装 Google Chrome
|
||||
### 方式 2:在 Fedora 上从 Chrome 网站安装 Google Chrome
|
||||
|
||||
如果你不想启用第三方仓库,也没关系。你不必这样做。你可以从 Chrome 的网站上下载 RPM 文件,双击并安装它。
|
||||
|
||||
访问 Google Chrome 的网站,点击下载按钮。
|
||||
|
||||
[Get Google Chrome][8]
|
||||
- [获取 Google Chrome][8]
|
||||
|
||||
![][9]
|
||||
|
||||
@@ -59,11 +58,11 @@ Can it be any easier than this? I don’t think either :)
|
||||
|
||||
![][11]
|
||||
|
||||
这是超级简单的,对吧?让我们来看看有点复杂的方法(如果你不是一个终端爱好者)。
|
||||
这是超级简单的,对吧?让我们来看看有点复杂的方式(如果你不是一个终端爱好者)。
|
||||
|
||||
### 方法 3:使用命令行在 Fedora 上安装 Chrome
|
||||
### 方式 3:使用命令行在 Fedora 上安装 Chrome
|
||||
|
||||
首先,你需要添加额外的 Fedora 仓库(你在方法 1 中看到的):
|
||||
首先,你需要添加额外的 Fedora 仓库(你在方式 1 中看到的):
|
||||
|
||||
```
|
||||
sudo dnf install fedora-workstation-repositories
|
||||
@@ -83,20 +82,18 @@ sudo dnf config-manager --set-enabled google-chrome
|
||||
sudo dnf install google-chrome-stable
|
||||
```
|
||||
|
||||
你会看到一个导入 GPG 密钥的警告,输入 y 继续。
|
||||
你会看到一个导入 GPG 密钥的警告,输入 `y` 继续。
|
||||
|
||||
![][13]
|
||||
|
||||
你正在添加 Google Chrome 仓库。这个软件包来自这个仓库,它直接来自 Google。
|
||||
|
||||
#### 总结
|
||||
### 总结
|
||||
|
||||
即使你使用命令行,在 Fedora 上安装 Google chrome 也相当简单。除了第三方仓库的部分,这和[在 Ubuntu 上安装 Chrome][14] 差不多。
|
||||
|
||||
现在你已经安装好了,你可能会想[查看我们的 Google Chrome 键盘快捷键列表][15]来更快地使用浏览器。
|
||||
|
||||
不要忘记订阅,获取关于 Fedora 的最新消息和教程,如果你有任何问题,请在下方留言。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/install-google-chrome-fedora/
|
||||
@@ -104,7 +101,7 @@ via: https://itsfoss.com/install-google-chrome-fedora/
|
||||
作者:[Dimitrios Savvopoulos][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12847-1.html)
|
||||
[#]: subject: (How to Install and Use Etcher on Linux for Making Live Linux USB)
|
||||
[#]: via: (https://itsfoss.com/install-etcher-linux/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
如何在 Linux 上安装和使用 Etcher 来制作 Linux 临场 USB
|
||||
======
|
||||
|
||||

|
||||
|
||||
> Etcher 是一款流行的 USB 烧录应用,可用于创建可启动的 Linux USB。让我来告诉你如何安装它,以及如何使用它来制作一个 Linux 临场盘。
|
||||
|
||||
### Etcher:一个用于在 SD 卡和 USB 驱动器中烧录 Linux ISO 的开源工具
|
||||
|
||||
Etcher 是一个由 [Balena][1] 开发的开源项目,来用于为树莓派烧录 SD 卡。事实上,我们在[如何在 SD 卡上安装 Raspbian OS][2] 的教程中就使用了它。
|
||||
|
||||
它不仅仅局限于 SD 卡,你还可以使用 Etcher 来[制作一个可启动的 USB 驱动器][3],我们就通过它的帮助在 Linux 中制作了一个 [Manjaro 的临场 USB][4]。
|
||||
|
||||
自首次发布以来,Etcher 就以其整洁的界面和简单的使用方式引起了人们的注意。
|
||||
|
||||
![][5]
|
||||
|
||||
在本文中,我将重点介绍帮助你在 Linux 上安装 Etcher 的步骤。然后,我还将展示如何使用它。在这之前,让我先给大家介绍一下它的功能。
|
||||
|
||||
### Etcher 的功能
|
||||
|
||||
* 在烧录前验证驱动器
|
||||
* 漂亮的用户界面
|
||||
* 自动检测 USB 驱动器/SD 卡,防止电脑上的硬盘被擦除。
|
||||
* 跨平台支持(Windows、macOS 和 Linux)。
|
||||
* 快速烧录
|
||||
* 简单的三步过程
|
||||
|
||||
理论上,你已经有了在 SD 卡和 USB 驱动器上烧录操作系统镜像所需的一切。同样令人激动的是,根据他们的[路线图][6],他们计划增加对多个设备的同步写入支持。
|
||||
|
||||
### 在 Linux 上安装 Etcher
|
||||
|
||||
要开始使用,你需要从它的官方网站上下载它提供的 AppImage 文件(适用于任何 Linux 发行版)。
|
||||
|
||||
你只需要前往它的[主页][7],并根据你的系统(32 位/64 位)下载一个程序:
|
||||
|
||||
![][8]
|
||||
|
||||
在我的例子中,我下载了 Ubuntu 的 64 位 AppImage 文件。你可以通过我们的指南来了解[在 Linux 上使用 AppImage文件][9],但我会让你先知道下一步需要做什么。
|
||||
|
||||
你需要给文件执行权限,你可以右击**AppImage 文件 -> 属性**来实现。
|
||||
|
||||
![][10]
|
||||
|
||||
接下来,点击权限选项卡下的“**允许作为程序执行**”,如下图所示。
|
||||
|
||||
![][11]
|
||||
|
||||
现在,只需双击 AppImage 文件即可启动 Etcher!
|
||||
|
||||
这应该可以在任何 Linux 发行版上运行。在任何情况下,如果你想从源码构建或者直接使用 .rpm 或 .deb 文件安装,你也可以前往它的 [Github 发布页][12]找到 RPM、DEB 和源码。
|
||||
|
||||
你也可以参考我们的[在 Ubuntu 中使用 deb 文件][13]来安装应用。
|
||||
|
||||
> 注意!
|
||||
>
|
||||
> 我们注意到,当你使用 Etcher 创建 Linux 发行版的临场 USB 时,它会使 USB 处于明显的不可使用状态,即它只有几 MB 的空闲空间,并且不能直接格式化。在 Linux 上,你可以[使用磁盘工具手动删除分区,然后格式化它][14]。
|
||||
|
||||
### 在 Linux 上使用 Etcher
|
||||
|
||||
只需三步就可以开始使用 Etcher。在你启动它之后,根据屏幕上的提示应该是清晰的,但为了给你一个好的开始,以下是你要做的事情:
|
||||
|
||||
**步骤 1:** 选择合适的 ISO 镜像文件或你需要烧录的文件的 URL(如下图所示)。
|
||||
|
||||
![][15]
|
||||
|
||||
**步骤 2:** 接下来,你需要选择目标设备。它会自动检测并高亮显示可移动设备,以防止你选择任何内部存储位置。
|
||||
|
||||
![][16]
|
||||
|
||||
在这里,我连接了一个 USB 驱动器,我也选择了它(如下图所示)。
|
||||
|
||||
![][17]
|
||||
|
||||
**步骤 3:** 现在,你所有需要做的就是烧录镜像并等待它成功完成。
|
||||
|
||||
![][18]
|
||||
|
||||
这是进度的样子:
|
||||
|
||||
![][19]
|
||||
|
||||
完成了!
|
||||
|
||||
![][20]
|
||||
|
||||
- [下载 balenaEtcher][7]
|
||||
|
||||
### 总结
|
||||
|
||||
Etcher 是一个有用的工具,可以为 SD 卡和 USB 驱动器烧录操作系统镜像。我倾向于主要使用它来创建临场 USB 驱动器来测试 Linux 发行版,我对它很满意。
|
||||
|
||||
你更喜欢用什么来创建可启动驱动器?你是否已经尝试过 Etcher?请在下面的评论中告诉我你的想法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/install-etcher-linux/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.balena.io/
|
||||
[2]: https://itsfoss.com/tutorial-how-to-install-raspberry-pi-os-raspbian-wheezy/
|
||||
[3]: https://itsfoss.com/create-bootable-ubuntu-usb-drive-mac-os/
|
||||
[4]: https://itsfoss.com/create-live-usb-manjaro-linux/
|
||||
[5]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/10/etcher-mxlinux-2.png?resize=800%2C518&ssl=1
|
||||
[6]: https://github.com/balena-io/etcher/milestones
|
||||
[7]: https://www.balena.io/etcher
|
||||
[8]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/etcher-official-site-download.png?resize=800%2C580&ssl=1
|
||||
[9]: https://itsfoss.com/use-appimage-linux/
|
||||
[10]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/balena-etcher-permission.jpg?resize=800%2C378&ssl=1
|
||||
[11]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/balena-etcher-execute.jpg?resize=800%2C445&ssl=1
|
||||
[12]: https://github.com/balena-io/etcher/releases/tag/v1.5.109
|
||||
[13]: https://itsfoss.com/install-deb-files-ubuntu/
|
||||
[14]: https://itsfoss.com/cant-format-usb-disk/
|
||||
[15]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/balena-etcher-select.jpg?resize=800%2C521&ssl=1
|
||||
[16]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/etcher-select-target.jpg?resize=800%2C509&ssl=1
|
||||
[17]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/etcher-target-device.jpg?resize=800%2C521&ssl=1
|
||||
[18]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/etcher-flash.jpg?resize=800%2C516&ssl=1
|
||||
[19]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/etcher-flashing.jpg?resize=800%2C510&ssl=1
|
||||
[20]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/etcher-flash-complete.jpg?resize=800%2C507&ssl=1
|
||||
@@ -0,0 +1,283 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (frogOAO)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12854-1.html)
|
||||
[#]: subject: (How to Install Fedora in VirtualBox [With Steps for USB, Clipboard and Folder Sharing])
|
||||
[#]: via: (https://itsfoss.com/install-fedora-in-virtualbox/)
|
||||
[#]: author: (Dimitrios Savvopoulos https://itsfoss.com/author/dimitrios/)
|
||||
|
||||
如何在 VirtualBox 中安装 Fedora
|
||||
======
|
||||
|
||||
如果你对 Fedora Linux 感兴趣,这有几种方式可以尝试它。
|
||||
|
||||
最简单还不影响你操作系统的方式是 [制作 Fedora 的 USB 临场启动盘][1]。
|
||||
|
||||
> **LCTT 译注**:
|
||||
>
|
||||
> 在 Linux 发行版的使用方式上,有一种可以无需安装而通过光盘或 USB 存储棒直接在计算机上启动完整的 Linux 操作系统的方式,这种方式称之为 “Live” 方式,如 Live CD、Live USB。
|
||||
>
|
||||
> 通常,Live 一词并不翻译,不过,我认为,除了英文缩写和部分历史原因造成直接使用的英文单词,大部分场景都应该使用本地化的语言来描述,否则,中英文混杂的港台式中文,实在有些不伦不类;抑或,外文翻译本身就不存在意义了。
|
||||
>
|
||||
> 因此,对于 “Live” 一词如何翻译,我们也颇费心思。这个词,在维基百科中文中,被翻译为“[自生系统](https://zh.wikipedia.org/wiki/Live_CD)”,在某些场景下偶见 “现场”、“临场” 等翻译。考虑到 Live CD/USB 的特性,我认为翻译为 “临场” 比较好。
|
||||
>
|
||||
> 于此抛出愚见,希望得到大家的积极反馈。wxy@LCTT
|
||||
|
||||
另一种方式是安装 VirtualBox 利用虚拟化技术来尝试 Fedora。这样,你可以在你的操作系统上像使用应用程序一样使用 Fedora。
|
||||
|
||||
通过这种方式,你可以执行更彻底的测试,而不会搞乱当前的操作系统。
|
||||
|
||||
你甚至可以复制你的虚拟环境,并在其他系统上重新安装它。听起来方便吗?让我来教你怎么做。
|
||||
|
||||
### 在 VirtualBox 上安装 Fedora
|
||||
|
||||
![][2]
|
||||
|
||||
让我们分步在 Oracle VirtualBox 上安装 Fedora。
|
||||
|
||||
#### 步骤一:安装 VirtualBox
|
||||
|
||||
如果你的系统还没有安装 VirtualBox,你可以从官方网站下载。你可以找到 Windows、MacOs 和 Linux 的说明。 [Ubuntu 用户可以参考这个关于安装 VirtualBox 的详细教程。][3]
|
||||
|
||||
![][4]
|
||||
|
||||
- [下载 VirtualBox][5]
|
||||
|
||||
#### 步骤二: 下载 Fedora ISO
|
||||
|
||||
如果你不熟悉 Fedora,那么这些镜像你需要知道。
|
||||
|
||||
[Fedora IoT][6] 是用于可扩展基础设施的,[Fedora workstation][7] 是一个带有一组面向普通 GNOME 桌面环境中的桌面工具的镜像。[Fedora server][8] 顾名思义,是为服务器或数据中心定制的。
|
||||
|
||||
如果 GNOME 不是你的首选,你可以下载一个带有替代桌面环境的[定制版][9] Fedora 桌面。对于本教程,我选择了带有 GNOME 桌面环境的[Fedora 33][10]。
|
||||
|
||||
- [下载 Fedora][11]
|
||||
|
||||
#### 步骤三: 创建一个空虚拟机并对其进行配置
|
||||
|
||||
要成功安装和运行 Fedora,至少需要 20GB 磁盘空间和 2GB RAM。不过,为了获得更流畅的用户体验,建议增加一倍。在此基础上,我将创建并配置虚拟机。
|
||||
|
||||
开启 Virtual Box 点击 “New”。
|
||||
|
||||
![创建一个新的虚拟机][12]
|
||||
|
||||
需要注意,最重要的选项是 **将类型设置为 Linux ,版本设置为 Fedora (64-bit)**。如果你在名称提示符处开始输入 “Fedora”,VirtualBox 将自动为你选择正确的设置。虽然名字不一定非得是 Fedora,它可以是任何你喜欢的。
|
||||
|
||||
*如果你只能访问 32 位版本,那么你需要在 BIOS 上启用虚拟化技术,如果你有一个 AMD CPU,它被称为 SVM。最坏的情况是你的 CPU 不支持虚拟化技术。如果你不确定,先检查这个。
|
||||
|
||||
如果你的设置和我类似,点击 “create” 按钮。
|
||||
|
||||
![命名你的虚拟机,并未它指定至少 3 GB RAM][13]
|
||||
|
||||
如前所述,至少需要 20GB 的磁盘空间才能安装 Fedora。我的系统上有 32GB 的内存,所以我分配了 8GB 内存。3 GB 的内存应该也没问题。
|
||||
|
||||
顺便说下内存的使用,只有在运行虚拟机时,虚拟机才会使用内存。否则,它将可用于常规使用。
|
||||
|
||||
确保其余设置与示例匹配,并点击 “Create” 按钮。
|
||||
|
||||
![以 VDI 格式分配 15-20 GB 的磁盘空间][14]
|
||||
|
||||
在你点击虚拟机的 Start 按钮之前,你需要加载如下所示的 ISO [光驱]。
|
||||
|
||||
![将 Fedora ISO 添加到光驱存储中][15]
|
||||
|
||||
因为你的虚拟硬盘是空的,虚拟机将从这个 ISO 启动。可以把它看作是使用临场 USB 或磁盘安装 Linux。
|
||||
|
||||
![在设置中将 ISO 添加为光驱][16]
|
||||
|
||||
然后,如果你有一个多核 CPU,建议为虚拟机分配 2 个或更多的核。你可以在 “System” 选项卡下找到 CPU 核心。配置系统时,单击 “OK” 并启动虚拟机。
|
||||
|
||||
![可选:分配 CPU 核数][17]
|
||||
|
||||
配置好所有内容后,单击 “Start” 按钮开始安装。
|
||||
|
||||
#### 步骤四:在 VirtualBox 中安装 Fedora。
|
||||
|
||||
如果你正确地遵循了这个过程,那么当你启动虚拟机时,你将直接从 ISO 文件启动。当你看到类似下面的屏幕时,选择 “Start Fedora”,并按回车键。
|
||||
|
||||
![Fedora 运行在虚拟机的临场环境中][18]
|
||||
|
||||
要启动安装对话框,单击 “Install To Hard Drive”。
|
||||
|
||||
![点击 “install to hard drive”][19]
|
||||
|
||||
在你继续安装之前,有必要定义你的键盘布局、你的时区以及最终安装操作系统的位置。
|
||||
|
||||
![选择键盘布局、日期和时间,然后是安装目标位置][20]
|
||||
|
||||
分区过程很简单。你像前面的 VDI 那样划分一些空闲空间。它应该被自动识别。
|
||||
|
||||
选择你的磁盘并将存储配置设置为 “Automatic”。单击 “Done” 进入上一个对话框。
|
||||
|
||||
![磁盘应该会自动识别][21]
|
||||
|
||||
一旦你配置完了上面的,点击 “Begin Installation”。
|
||||
|
||||
![开始 Fedora 的安装][22]
|
||||
|
||||
现在只需等待 5 - 6 分钟即可完成安装。安装完成后,点击 “Finish installation” 按钮。
|
||||
|
||||
最后一步,需要关闭系统的电源。如果你不熟悉 GNOME 桌面环境,你可以如下这样做。
|
||||
|
||||
![安装后关闭 Fedora 临场环境][23]
|
||||
|
||||
你必须手动卸载在初始步骤中加载的 ISO 文件。
|
||||
|
||||
![从光驱中移走 Fedora ISO][24]
|
||||
|
||||
下一次使用 Fedora 启动虚拟机时,系统将提示你为 Fedora Linux 创建用户帐户并设置密码。
|
||||
|
||||
### 使用 VirtualBox Guest Additions 的附加功能,如剪贴板共享,文件夹共享等
|
||||
|
||||
[Guest Additions][25] 设计为在<ruby>访客<rt>guest</rt></ruby>操作系统安装后安装在虚拟机中。它们包含对客户操作系统进行优化的设备驱动程序和系统应用程序,以获得更好的性能和可用性。
|
||||
|
||||
Guest Additions ISO 文件被安装为虚拟 CD-ROM 以便安装。
|
||||
|
||||
这是一个简单的过程。只需单击设备选项卡,然后单击 “Insert Guest Additions CD image”。
|
||||
|
||||
![][26]
|
||||
|
||||
当提示单击 “Download” 时,系统将弹出下载 Guest Additions 镜像界面。
|
||||
|
||||
![安装 VirtualBox Guest Additions][27]
|
||||
|
||||
#### 共享剪贴板
|
||||
|
||||
有时候,你需要在虚拟机和<ruby>宿主机<rt>host</rt></ruby>操作系统之间移动一些内容。共享剪贴板/拖放支持将允许你在一个平台上复制项目,并将它们粘贴到另一个平台上。
|
||||
|
||||
要启用此功能,请在 VirtualBox 主页上选择 “Settings”,并按照下面的说明操作。“Bidirectional” 的选项是最方便的。
|
||||
|
||||
![启用访客和宿主系统间的剪贴板共享][28]
|
||||
|
||||
#### 共享文件夹
|
||||
|
||||
有两种类型的分享:
|
||||
|
||||
* 永久共享,与虚拟机设置一起保存。
|
||||
* 暂时共享,当虚拟机关闭时就会消失。可以使用 VirtualBox 管理器中的复选框创建暂时共享。
|
||||
|
||||
在本教程中,我将创建一个永久共享文件夹。在 VM 设置中添加你想要共享的宿主机系统文件夹,并选择你想要在 VM 中出现的名称。
|
||||
|
||||
![][29]
|
||||
|
||||
下次启动虚拟机时,该文件夹应该显示为网络驱动器。
|
||||
|
||||
![][30]
|
||||
|
||||
#### 更好的视频支持
|
||||
|
||||
虽然 Oracle VirtualBox 提供了具有基本功能的虚拟显卡,但访客系统添加的自定义视频驱动程序为你提供了超高和非标准的视频模式,以及视频加速。
|
||||
|
||||
使用 Guest Additions,操作系统的分辨率将随着你调整计算机上的 VirtualBox 窗口而动态调整大小。
|
||||
|
||||
最后,Guest Additions 可以利用你的计算机的显卡。如果你是一名游戏玩家或在 WM 中使用高效软件,这就会产生巨大的改变。
|
||||
|
||||
#### USB 和网络设备共享
|
||||
|
||||
有了 VirtualBox,用户就可以使用一个功能齐全的操作系统,而不必在不同的硬件上进行设置。然而,在宿主机和访客机器之间共享 USB 和网络设备并不像想的那样简单。
|
||||
|
||||
要访问 USB 设备,你将需要安装 [VirtualBox 扩展包][31]。
|
||||
|
||||
![安装 VirtualBox 扩展包][32]
|
||||
|
||||
**下面这些仅对 Linux**,因为我使用的是 Linux。
|
||||
|
||||
为了使 VirtualBox 能够访问 USB 子系统,运行 VirtualBox 的用户(在宿主机系统上)必须属于 `vboxuser` 组。为此,打开一个终端并发出以下命令:
|
||||
|
||||
```
|
||||
sudo usermod -aG vboxusers 'your username'
|
||||
```
|
||||
|
||||
运行该命令后,你应该注销并重新登录,或者重新启动主机。
|
||||
|
||||
在这一步,插入你的 U 盘,通过你的 VM 设置,你应该能够找到并添加介质,如例子中所示。
|
||||
|
||||
![][33]
|
||||
|
||||
当你下次启动虚拟机,你的 USB 将是可访问的。
|
||||
|
||||
![][34]
|
||||
|
||||
### 额外提示:保存并导出虚拟机,以便以后可以在任何系统上使用它
|
||||
|
||||
你可能想在另一台计算机上使用虚拟机,或者是时候构建一台新机器了,并且你需要保持虚拟机的原样。只需几个简单的步骤,就可以轻松地导出当前设置并将其导入到另一台机器。
|
||||
|
||||
在 VirtualBox 主面板上,单击 “file”、“Export Appliance”。如果你喜欢键盘快捷键,你可以简单地点击 `Ctrl+E`。
|
||||
|
||||
![][35]
|
||||
|
||||
选择要导出的虚拟机,然后单击 “Next”。
|
||||
|
||||
![][36]
|
||||
|
||||
“Format” 选项需要注意一下。有三种不同的选项:<ruby>开放虚拟化格式<rt>Open Virtualization Format</rt></ruby> 0.9、1.0 和 2.0 ,可以是 ovf 或 ova 扩展名。
|
||||
|
||||
使用 ovf 扩展名,会分别写入几个文件,而 ova 扩展名则将所有文件合并到一个开放虚拟化格式归档文件中。
|
||||
|
||||
默认格式 OVF 1.0 应该没问题。
|
||||
|
||||
![][37]
|
||||
|
||||
要完成该过程,单击 “Next”,然后在下一个对话框中单击 “Export”。
|
||||
|
||||
### 总结
|
||||
|
||||
通过使用虚拟机,你不仅可以测试操作系统,还可以部署与物理机器同等重要的功能完整的系统。如今,硬件已经变得如此强大和廉价,它的大部分功能都没有被利用。
|
||||
|
||||
通过虚拟化技术,你可以使用这些浪费的资源。对物理机器的需求减少了,因此能源消耗也减少了。你可以从硬件和降低运行成本两方面省钱。
|
||||
|
||||
在大规模服务环境中,服务器虚拟化更多的是一种基本需求,而不是一种高级概念。
|
||||
|
||||
我希望本教程对你在 VirtualBox 中安装 Fedora Linux 有帮助。如果你遇到任何问题,请在评论中告诉我。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/install-fedora-in-virtualbox/
|
||||
|
||||
作者:[Dimitrios Savvopoulos][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[frogOAO](https://github.com/frogOAO)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/dimitrios/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/create-fedora-live-usb-ubuntu/
|
||||
[2]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/install-fedora-in-virtualbox.png?resize=800%2C450&ssl=1
|
||||
[3]: https://itsfoss.com/install-virtualbox-ubuntu/
|
||||
[4]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/05/download-virtulabox.jpg?resize=799%2C294&ssl=1
|
||||
[5]: https://www.virtualbox.org/
|
||||
[6]: https://getfedora.org/en/iot/
|
||||
[7]: https://getfedora.org/en/workstation/
|
||||
[8]: https://getfedora.org/en/server/
|
||||
[9]: https://spins.fedoraproject.org/
|
||||
[10]: https://itsfoss.com/fedora-33/
|
||||
[11]: https://getfedora.org/
|
||||
[12]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/10/0.-create-a-new-vm.png?resize=800%2C550&ssl=1
|
||||
[13]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/10/1-create-vm-fedora.png?resize=800%2C533&ssl=1
|
||||
[14]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/10/2-fedora-vm-disk.png?resize=800%2C533&ssl=1
|
||||
[15]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/fedora-vm-settings-iso.png?resize=800%2C640&ssl=1
|
||||
[16]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/3-fedora-vm-settings2.png?resize=800%2C600&ssl=1
|
||||
[17]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/10/4-fedora-vm-cpu.png?resize=800%2C533&ssl=1
|
||||
[18]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/6-fedora-vm-boot.png?resize=800%2C600&ssl=1
|
||||
[19]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/10/7-fedora-vm-install-1.png?resize=800%2C622&ssl=1
|
||||
[20]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/10/9-fedora-vm-partitioning-2.png?resize=800%2C706&ssl=1
|
||||
[21]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/10-fedora-vm-hdd.png?resize=732%2C645&ssl=1
|
||||
[22]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/12-fedora-vm-installation-1.png?resize=800%2C706&ssl=1
|
||||
[23]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/15-power-off-fedora-gnome.png?resize=800%2C706&ssl=1
|
||||
[24]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/remove-fedora-iso-from-optical-drive.png?resize=800%2C589&ssl=1
|
||||
[25]: https://www.virtualbox.org/manual/ch04.html
|
||||
[26]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/16-Fedora-vm-guest-additions.png?resize=800%2C706&ssl=1
|
||||
[27]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/17-Fedora-vm-guest-additions.png?resize=800%2C686&ssl=1
|
||||
[28]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/19-fedora-vm-shared-clipboard-2.png?resize=800%2C650&ssl=1
|
||||
[29]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/20-fedora-vm-shared-folders-1.png?resize=800%2C650&ssl=1
|
||||
[30]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/22-fedora-vm-shared-folders2-1.png?resize=800%2C547&ssl=1
|
||||
[31]: https://download.virtualbox.org/virtualbox/6.1.16/Oracle_VM_VirtualBox_Extension_Pack-6.1.16.vbox-extpack
|
||||
[32]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/21.-fedora-vm-extension-pack.png?resize=800%2C600&ssl=1
|
||||
[33]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/25.-fedora-vm-usb-1.png?resize=800%2C527&ssl=1
|
||||
[34]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/26.-fedora-vm-usb-1.png?resize=800%2C578&ssl=1
|
||||
[35]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/23.-fedora-vm-export.png?resize=800%2C600&ssl=1
|
||||
[36]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/24.-fedora-vm-export-1.png?resize=800%2C545&ssl=1
|
||||
[37]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/25.-fedora-vm-export-800x545.png?resize=800%2C545&ssl=1
|
||||
115
published/20201116 Podman with capabilities on Fedora.md
Normal file
115
published/20201116 Podman with capabilities on Fedora.md
Normal file
@@ -0,0 +1,115 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12859-1.html)
|
||||
[#]: subject: (Podman with capabilities on Fedora)
|
||||
[#]: via: (https://fedoramagazine.org/podman-with-capabilities-on-fedora/)
|
||||
[#]: author: (shiwanibiradar https://fedoramagazine.org/author/shiwanibiradar/)
|
||||
|
||||
在 Fedora 中结合权能使用 Podman
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
容器化是一项蓬勃发展的技术。在不久的将来,多达百分之七十五的全球组织可能会运行某种类型的容器化技术。由于广泛使用的技术更容易成为黑客攻击的目标,因此保护容器的安全就显得尤为重要。本文将演示如何使用 POSIX <ruby>[权能][2]<rt>Capability</rt></ruby> 来保护 Podman 容器的安全。Podman 是 RHEL8 中默认的容器管理工具。
|
||||
|
||||
### 确定 Podman 容器的权限模式
|
||||
|
||||
容器以特权模式或无特权模式运行。在特权模式下,[容器的 uid 0 被映射到宿主机的 uid 0][3]。对于某些情况,无特权的容器[缺乏对宿主机资源的充分访问能力][4]。但不管其操作模式如何,包括<ruby>强制访问控制<rt>Mandatory Access Control</rt></ruby>(MAC:如 apparmor、SELinux 等)、seccomp 过滤器、删除<ruby>权能<rt>Capability</rt></ruby>、命名空间等在内的技术有助于确保容器的安全。
|
||||
|
||||
要从容器外部确定特权模式:
|
||||
|
||||
```
|
||||
$ podman inspect --format="{{.HostConfig.Privileged}}" <container id>
|
||||
```
|
||||
|
||||
如果上面的命令返回 `true`,那么容器在特权模式下运行。如果返回 `false`,那么容器在非特权模式下运行。
|
||||
|
||||
要从容器内部确定特权模式:
|
||||
|
||||
```
|
||||
$ ip link add dummy0 type dummy
|
||||
```
|
||||
|
||||
如果该命令允许你创建一个接口,那么你运行的是一个特权容器,否则你运行的是一个非特权容器。
|
||||
|
||||
### 权能
|
||||
|
||||
命名空间隔离了容器的进程,使其无法任意访问宿主机的资源,也无法访问在同一宿主机上运行的其他容器的资源。然而,在**特权**容器内的进程仍然可以做一些事情,如改变 IP 路由表、跟踪任意进程和加载内核模块。<ruby>权能<rt>Capability</rt></ruby>允许人们对容器内的进程可以访问或更改的资源施加更细微的限制,即使容器在特权模式下运行也一样。权能还允许人们为无特权的容器分配它本来不会拥有的特权。
|
||||
|
||||
例如,如果要将 `NET_ADMIN` 功能添加到一个无特权的容器中,以便在容器内部创建一个网络接口,你可以用下面的参数运行 `podman`:
|
||||
|
||||
```
|
||||
[root@vm1 ~]# podman run -it --cap-add=NET_ADMIN centos
|
||||
[root@b27fea33ccf1 /]# ip link add dummy0 type dummy
|
||||
[root@b27fea33ccf1 /]# ip link
|
||||
```
|
||||
|
||||
上面的命令演示了在一个无特权的容器中创建一个 `dummy0` 接口。如果没有 `NET_ADMIN` 权能,非特权容器将无法创建接口。上面的命令演示了如何将一个权能授予一个无特权的容器。
|
||||
|
||||
目前,大约有 [39 种权能][5]可以被授予或拒绝。特权容器默认会被授予许多权能。建议从特权容器中删除不需要的权能,以使其更加安全。
|
||||
|
||||
要从容器中删除所有权能:
|
||||
|
||||
```
|
||||
$ podman run -it -d --name mycontainer --cap-drop=all centos
|
||||
```
|
||||
|
||||
列出一个容器的权能:
|
||||
|
||||
```
|
||||
$ podman exec -it 48f11d9fa512 capsh --print
|
||||
```
|
||||
|
||||
上述命令显示没有向容器授予任何权能。
|
||||
|
||||
请参考 `capabilities` 手册页以获取完整的权能列表:
|
||||
|
||||
```
|
||||
$ man capabilities
|
||||
```
|
||||
|
||||
可以使用 `capsh` 命令来列出目前拥有的权能:
|
||||
|
||||
```
|
||||
$ capsh --print
|
||||
```
|
||||
|
||||
作为另一个例子,下面的命令演示了如何从容器中删除 `NET_RAW` 权能。如果没有 `NET_RAW` 权能,就不能从容器中 `ping` 互联网上的服务器。
|
||||
|
||||
```
|
||||
$ podman run -it --name mycontainer1 --cap-drop=net_raw centos
|
||||
>>> ping google.com (will output error, operation not permitted)
|
||||
```
|
||||
|
||||
最后一个例子,如果你的容器只需要 `SETUID` 和 `SETGID` 权能,你可以删除所有权能,然后只重新添加这两个权能来实现这样的权限设置。
|
||||
|
||||
```
|
||||
$ podman run -d --cap-drop=all --cap-add=setuid --cap-add=setgid fedora sleep 5 > /dev/null; pscap | grep sleep
|
||||
```
|
||||
|
||||
上面的 `pscap` 命令会显示容器被授予的权能。
|
||||
|
||||
我希望你喜欢这个关于如何使用权能来保护 Podman 容器的简短探索。
|
||||
|
||||
谢谢!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/podman-with-capabilities-on-fedora/
|
||||
|
||||
作者:[shiwanibiradar][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/shiwanibiradar/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2018/10/podman-816x345.jpg
|
||||
[2]: https://www.linuxjournal.com/magazine/making-root-unprivileged
|
||||
[3]: https://linuxcontainers.org/lxc/security/#privileged-containers
|
||||
[4]: https://github.com/containers/podman/blob/master/rootless.md
|
||||
[5]: https://man7.org/linux/man-pages/man7/capabilities.7.html
|
||||
@@ -0,0 +1,249 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12851-1.html)
|
||||
[#]: subject: (Unlock encrypted disks on Linux automatically)
|
||||
[#]: via: (https://opensource.com/article/20/11/nbde-linux)
|
||||
[#]: author: (Curt Warfield https://opensource.com/users/rcurtiswarfield)
|
||||
|
||||
自动解锁 Linux 上的加密磁盘
|
||||
======
|
||||
|
||||
> 通过使用网络绑定磁盘加密(NBDE),无需手动输入密码即可打开加密磁盘。
|
||||
|
||||

|
||||
|
||||
从安全的角度来看,对敏感数据进行加密以保护其免受窥探和黑客的攻击是很重要的。<ruby>Linux 统一密钥设置<rt>Linux Unified Key Setup</rt></ruby>([LUKS][2])是一个很好的工具,也是 Linux 磁盘加密的通用标准。因为它将所有相关的设置信息存储在分区头部中,所以它使数据迁移变得简单。
|
||||
|
||||
要使用 LUKS 配置加密磁盘或分区,你需要使用 [cryptsetup][3] 工具。不幸的是,加密磁盘的一个缺点是,每次系统重启或磁盘重新挂载时,你都必须手动提供密码。
|
||||
|
||||
然而,<ruby>网络绑定磁盘加密<rt>Network-Bound Disk Encryption</rt></ruby>(NBDE) 可以在没有任何用户干预的情况下自动安全地解锁加密磁盘。它可以在一些 Linux 发行版中使用,包括从 Red Hat Enterprise Linux 7.4、CentOS 7.4 和 Fedora 24 开始,以及之后的后续版本。
|
||||
|
||||
NBDE 采用以下技术实现:
|
||||
|
||||
* [Clevis 框架][4]:一个可插拔的框架工具,可自动解密和解锁 LUKS 卷
|
||||
* [Tang 服务器][5]:用于将加密密钥绑定到网络状态的服务
|
||||
|
||||
Tang 向 Clevis 客户端提供加密密钥。据 Tang 的开发人员介绍,这为密钥托管服务提供了一个安全、无状态、匿名的替代方案。
|
||||
|
||||
由于 NBDE 使用客户端-服务器架构,你必须同时配置客户端和服务器。你可以在你的本地网络上使用一个虚拟机作为 Tang 服务器。
|
||||
|
||||
### 服务器安装
|
||||
|
||||
用 sudo 安装 Tang:
|
||||
|
||||
```
|
||||
sudo yum install tang -y
|
||||
```
|
||||
|
||||
启用 Tang 服务器:
|
||||
|
||||
```
|
||||
sudo systemctl enable tangd.socket --now
|
||||
```
|
||||
|
||||
Tang 服务器工作在 80 端口,需加入到 firewalld 防火墙。添加相应的 firewalld 规则:
|
||||
|
||||
|
||||
```
|
||||
sudo firewall-cmd --add-port=tcp/80 --perm
|
||||
sudo firewall-cmd --reload
|
||||
```
|
||||
|
||||
现在安装好了服务器。
|
||||
|
||||
### 客户端安装
|
||||
|
||||
在本例中,假设你已经添加了一个名为 `/dev/vdc` 的新的 1GB 磁盘到你的系统中。
|
||||
|
||||
使用 `fdisk` 或 `parted` 创建主分区:
|
||||
|
||||
```
|
||||
sudo fdisk /dev/vdc
|
||||
```
|
||||
|
||||
完成以下步骤来安装客户端:
|
||||
|
||||
```
|
||||
Welcome to fdisk (util-linux 2.23.2).
|
||||
|
||||
Changes will remain in memory only, until you decide to write them.
|
||||
Be careful before using the write command.
|
||||
|
||||
Device does not contain a recognized partition table
|
||||
Building a new DOS disklabel with disk identifier 0x4a6812d4.
|
||||
|
||||
Command (m for help):
|
||||
```
|
||||
|
||||
输入 `n` 来创建新的分区:
|
||||
|
||||
```
|
||||
Partition type:
|
||||
p primary (0 primary, 0 extended, 4 free)
|
||||
e extended
|
||||
Select (default p):
|
||||
```
|
||||
|
||||
按下**回车**键选择主分区:
|
||||
|
||||
|
||||
```
|
||||
Using default response p
|
||||
Partition number (1-4, default 1):
|
||||
```
|
||||
|
||||
按下回车键选择默认分区号:
|
||||
|
||||
```
|
||||
First sector (2048-2097151, default 2048):
|
||||
Using default value 2048
|
||||
Last sector, +sectors or +size{K,M,G} (2048-2097151, default 2097151):
|
||||
```
|
||||
|
||||
按回车键选择最后一个扇区:
|
||||
|
||||
```
|
||||
Using default value 2097151
|
||||
Partition 1 of type Linux and of size 1023 MiB is set
|
||||
|
||||
Command (m for help): wq
|
||||
```
|
||||
|
||||
输入 `wq` 保存更改并退出 `fdisk`:
|
||||
|
||||
```
|
||||
The partition table has been altered!
|
||||
|
||||
Calling ioctl() to re-read partition table.
|
||||
Syncing disks.
|
||||
```
|
||||
|
||||
运行 `partprobe` 通知系统分区表的变化:
|
||||
|
||||
```
|
||||
sudo partprobe
|
||||
```
|
||||
|
||||
使用 `sudo` 安装 cryptsetup 软件包:
|
||||
|
||||
```
|
||||
sudo yum install cryptsetup -y
|
||||
```
|
||||
|
||||
使用 `cryptsetup luksFormat` 命令对磁盘进行加密。当提示时,你需要输入大写的 `YES`,并输入密码来加密磁盘:
|
||||
|
||||
```
|
||||
sudo cryptsetup luksFormat /dev/vdc1
|
||||
WARNING!
|
||||
========
|
||||
This will overwrite data on /dev/vdc1 irrevocably.
|
||||
|
||||
Are you sure? (Type uppercase yes):
|
||||
|
||||
Enter passphrase for /dev/vdc1:
|
||||
Verify passphrase:
|
||||
```
|
||||
|
||||
使用 `cryptsetup luksOpen` 命令将加密的分区映射到一个逻辑设备上。例如,使用 `encryptedvdc1` 作为名称。你还需要再次输入密码:
|
||||
|
||||
```
|
||||
sudo cryptsetup luksOpen /dev/vdc1 encryptedvdc1
|
||||
Enter passphrase for /dev/vdc1:
|
||||
```
|
||||
|
||||
加密分区现在在 `/dev/mapper/encryptedvdc1` 中可用。
|
||||
|
||||
在加密的分区上创建一个 XFS 文件系统:
|
||||
|
||||
```
|
||||
sudo mkfs.xfs /dev/mapper/encryptedvdc1
|
||||
```
|
||||
|
||||
创建一个挂载加密分区的目录:
|
||||
|
||||
```
|
||||
sudo mkdir /encrypted
|
||||
```
|
||||
|
||||
使用 `cryptsetup luksClose` 命令锁定分区:
|
||||
|
||||
```
|
||||
cryptsetup luksClose encryptedvdc1
|
||||
```
|
||||
|
||||
使用 `sudo` 安装 Clevis 软件包:
|
||||
|
||||
```
|
||||
sudo yum install clevis clevis-luks clevis-dracut -y
|
||||
```
|
||||
|
||||
修改 `/etc/crypttab`,在启动时打开加密卷:
|
||||
|
||||
```
|
||||
sudo vim /etc/crypttab
|
||||
```
|
||||
|
||||
增加以下一行:
|
||||
|
||||
```
|
||||
encryptedvdc1 /dev/vdc1 none _netdev
|
||||
```
|
||||
|
||||
修改 `/etc/fstab`,在重启时或启动时自动挂载加密卷:
|
||||
|
||||
```
|
||||
sudo vim /etc/fstab
|
||||
```
|
||||
|
||||
增加以下一行:
|
||||
|
||||
```
|
||||
/dev/mapper/encryptedvdc1 /encrypted xfs _netdev 1 2
|
||||
```
|
||||
|
||||
在这个例子中,假设 Tang 服务器的 IP 地址是 `192.168.1.20`。如果你喜欢,也可以使用主机名或域名。
|
||||
|
||||
运行以下 `clevis` 命令:
|
||||
|
||||
```
|
||||
sudo clevis bind luks -d /dev/vdc1 tang '{"url":"http://192.168.1.20"}'
|
||||
The advertisement contains the following signing keys:
|
||||
|
||||
rwA2BAITfYLuyNiIeYUMBzkhk7M
|
||||
|
||||
Do you wish to trust these keys? [ynYN] Y
|
||||
Enter existing LUKS password:
|
||||
```
|
||||
|
||||
输入 `Y` 接受 Tang 服务器的密钥,并提供现有的 LUKS 密码进行初始设置。
|
||||
|
||||
通过 `systemctl` 启用 `clevis-luks-askpass.path`,以防止非根分区被提示输入密码。
|
||||
|
||||
```
|
||||
sudo systemctl enable clevis-luks-askpass.path
|
||||
```
|
||||
|
||||
客户端已经安装完毕。现在,每当你重启服务器时,加密后的磁盘应该会自动解密,并通过 Tang 服务器取回密钥进行挂载。
|
||||
|
||||
如果 Tang 服务器因为任何原因不可用,你需要手动提供密码,才能解密和挂载分区。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/nbde-linux
|
||||
|
||||
作者:[Curt Warfield][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/rcurtiswarfield
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/security-lock-password.jpg?itok=KJMdkKum (Lock)
|
||||
[2]: https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup
|
||||
[3]: https://gitlab.com/cryptsetup/cryptsetup
|
||||
[4]: https://github.com/latchset/clevis
|
||||
[5]: https://github.com/latchset/tang
|
||||
@@ -0,0 +1,95 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12858-1.html)
|
||||
[#]: subject: (LazPaint: A Free & Open Source Paint.NET Alternative)
|
||||
[#]: via: (https://itsfoss.com/lazpaint/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
LazPaint:一个自由开源的 Paint.NET 替代品
|
||||
======
|
||||
|
||||

|
||||
|
||||
> LazPaint 是一款开源 Paint.NET 替代品,支持跨平台。它是一个轻量级的程序,拥有一堆快速编辑图像的基本选项。下面是 LazPaint 的概述。
|
||||
|
||||
### LazPaint:Linux 下的开源 Paint.NET 替代品
|
||||
|
||||
![][1]
|
||||
|
||||
如果你喜欢使用工具来快速编辑和处理图像和截图,你可能听说过 [Paint.NET][2],但它只适用于 Windows 系统。
|
||||
|
||||
它是一个流行的小工具,可以完成很多基本的编辑任务,同时还有一堆可用的选项。你可能知道一些[图像编辑工具][3],但 Paint.NET 是一个相当受欢迎的选择,因为对于一个普通用户来说,它易于使用,且没有任何臃肿的功能。
|
||||
|
||||
[LazPaint][4]作为 Linux、Windows 和 macOS 上 Paint.NET 的令人印象深刻的开源替代品而出现。它提供了操作图像所需的大部分基本功能,同时又易于使用。
|
||||
|
||||
![][5]
|
||||
|
||||
由于它是跨平台的应用,即使你不使用 Linux 系统,你仍然可以以自由开源工具使用它,这并非没有意义。现在,让我们看一下它提供的一些功能。
|
||||
|
||||
### LazPaint 的功能
|
||||
|
||||
![][6]
|
||||
|
||||
正如我前面提到的,LazPaint 提供了一堆必要的功能。在这里,我将列出关键的部分,这可以帮助你决定是否需要它。然而,我建议你去探索它,以了解更多关于它的信息。
|
||||
|
||||
* 支持所有主要的文件格式(包括分层位图和 3D 文件)
|
||||
* 选区工具、裁剪选区、选区笔、反转选区
|
||||
* 支持导出到 [Krita][7]
|
||||
* 以各种质量设置对图像进行重新采样
|
||||
* 运动模糊、自定义模糊、径向模糊和像素化工具
|
||||
* 可以移除透明度和扁平化图像
|
||||
* 旋转和翻转图像
|
||||
* 将图像转换为负片
|
||||
* 能够调整画布的大小
|
||||
* 变形工具(透视)
|
||||
* 高级绘图工具
|
||||
* 设置工作区颜色
|
||||
* 黑暗主题
|
||||
* 支持脚本功能
|
||||
* 具有基本管理选项的层支持
|
||||
* 层效果
|
||||
* 过滤器
|
||||
* 灰度效果
|
||||
* 能够启用/禁用工具栏或将其添加到 Dock 上
|
||||
|
||||
### 在 Linux 上安装 LazPaint
|
||||
|
||||
你应该可以在你的官方软件仓库中找到它,通过你的默认软件包管理器来安装它,但要获得最新版本,你需要下载 .deb 文件,或者在非 Debian 的发行版上从源码编译它。
|
||||
|
||||
我希望有一个可以在每个 Linux 发行版上获得最新的版本的 Flatpak 软件包,但目前还没有。
|
||||
|
||||
它也适用于 Windows 和 macOS。你会发现 Windows 还有一个便携版,可以派上用场。
|
||||
|
||||
- [LazPaint][4]
|
||||
|
||||
### 关于 LazPaint 的总结
|
||||
|
||||
我发现它真的很容易使用,以各种质量设置来重新采样(或调整大小)图像绝对是一个加分项。如果你已经安装了它,你一定注意到,它不需要大量的存储空间,总体上是一个轻量级的程序。
|
||||
|
||||
它的速度很快,我在快速测试中的大部分功能都相当好用,没有任何问题。
|
||||
|
||||
你觉得 LazPaint 作为 Paint.NET 的替代品怎么样?请在下面的评论中告诉我你的想法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/lazpaint/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/lazpaint.jpg?resize=800%2C397&ssl=1
|
||||
[2]: https://www.getpaint.net
|
||||
[3]: https://itsfoss.com/image-applications-ubuntu-linux/
|
||||
[4]: https://lazpaint.github.io/
|
||||
[5]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/lazpaint-screenshot-2.png?resize=800%2C481&ssl=1
|
||||
[6]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/lazpaint-screenshot.jpg?resize=800%2C484&ssl=1
|
||||
[7]: https://krita.org/en
|
||||
[9]: https://itsfoss.com/drawing-app/
|
||||
@@ -0,0 +1,89 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12869-1.html)
|
||||
[#]: subject: (How to Increase Disk Size of Your Existing Virtual Machines in VirtualBox)
|
||||
[#]: via: (https://itsfoss.com/increase-disk-size-virtualbox/)
|
||||
[#]: author: (Dimitrios Savvopoulos https://itsfoss.com/author/dimitrios/)
|
||||
|
||||
如何在 VirtualBox 中增加现有虚拟机的磁盘大小
|
||||
======
|
||||
|
||||
下面是你迟早会遇到的情况。
|
||||
|
||||
你在 [VirtualBox][1] 中安装了一个或多个操作系统。在创建这些虚拟操作系统的同时,你还在 VirtualBox 中为它们创建了虚拟硬盘。
|
||||
|
||||
你指定了虚拟磁盘的最大大小,比如说 15 或 20GB,但现在使用了一段时间后,你发现你的虚拟机已经没有空间了。
|
||||
|
||||
虽然[在 Ubuntu 和其他操作系统上有释放磁盘空间的方法][2],但更稳健的处理方式是增加 VirtualBox 中创建的虚拟机的磁盘大小。
|
||||
|
||||
是的,你可以在 VirtualBox 中扩大虚拟硬盘,即使在创建之后也可以。虽然这是一个安全且经过测试的过程,但我们强烈建议你在执行这样的操作之前,先创建一个虚拟机的备份。
|
||||
|
||||
### 如何扩大 VirtualBox 磁盘大小
|
||||
|
||||
![][3]
|
||||
|
||||
我将向你展示如何在 VirtualBox 中以图形和命令行(对于 Linux 极客)方式调整磁盘大小。这两种方法都很简单直接。
|
||||
|
||||
#### 方法 1:在 VirtualBox 中使用虚拟媒体管理器
|
||||
|
||||
VirtualBox 6 增加了一个调整虚拟磁盘大小的图形化选项。你可以在 VirtualBox 主页的文件选项卡中找到它。
|
||||
|
||||
进入 “File -> Virtual Media Manager”:
|
||||
|
||||
![][4]
|
||||
|
||||
在列表中选择一个虚拟机,然后使用 “Size” 滑块或输入你需要的大小值。完成后点击 “Apply”。
|
||||
|
||||
![][5]
|
||||
|
||||
请记住,虽然你增加了虚拟磁盘的大小,但**如果你的空间是动态分配的,那么实际的分区大小仍然不变**。
|
||||
|
||||
#### 方法 2:使用 Linux 命令行增加 VirtualBox 磁盘空间
|
||||
|
||||
如果你使用 Linux 操作系统作为宿主机,在宿主机中打开终端并输入以下命令来调整 VDI 的大小:
|
||||
|
||||
```
|
||||
VBoxManage modifymedium "/path_to_vdi_file" --resize <megabytes>
|
||||
```
|
||||
|
||||
在你按下回车执行命令后,调整大小的过程应该马上结束。
|
||||
|
||||
> 注意事项
|
||||
>
|
||||
> VirtualBox 早期版本命令中的 `*modifyvdi` 和 `modifyhd` 命令也支持,并在内部映射到 `modifymedium` 命令。
|
||||
|
||||
![][6]
|
||||
|
||||
如果你不确定虚拟机的保存位置,可以在 VirtualBox 主页面点击 “Files -> Preferences” 或使用键盘快捷键 `Ctrl+G` 找到默认位置。
|
||||
|
||||
![][7]
|
||||
|
||||
### 总结
|
||||
|
||||
就我个人而言,我更喜欢在每个 Linux 发行版上使用终端来扩展磁盘,图形化选项是最新的 VirtualBox 版本的一个非常方便的补充。
|
||||
|
||||
这是一个简单快捷的小技巧,但对 VirtualBox 基础知识是一个很好的补充。如果你觉得这个小技巧很有用,可以看看 [VirtualBox 客户端增强包][8]的几个功能。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/increase-disk-size-virtualbox/
|
||||
|
||||
作者:[Dimitrios Savvopoulos][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/dimitrios/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.virtualbox.org/
|
||||
[2]: https://itsfoss.com/free-up-space-ubuntu-linux/
|
||||
[3]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/enlarge-disk-size-virtualbox.png?resize=800%2C450&ssl=1
|
||||
[4]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/1-virtual-box-media-manager.png?resize=800%2C600&ssl=1
|
||||
[5]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/2-virtual-box-increase-disc-space.png?resize=800%2C505&ssl=1
|
||||
[6]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/3-virtual-box-increase-disc-space-terminal.png?resize=800%2C600&ssl=1
|
||||
[7]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/4-virtual-box-preferences.png?resize=800%2C450&ssl=1
|
||||
[8]: https://itsfoss.com/install-fedora-in-virtualbox/
|
||||
@@ -0,0 +1,113 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12866-1.html)
|
||||
[#]: subject: (Compare Files and Folders Graphically in Linux With Meld)
|
||||
[#]: via: (https://itsfoss.com/meld-gui-diff/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
|
||||
使用 Meld 在 Linux 中以图形方式比较文件和文件夹
|
||||
======
|
||||
|
||||

|
||||
|
||||
如何比较两个相似的文件来检查差异?答案显而易见,就是[使用 Linux 中的 diff 命令][1]。
|
||||
|
||||
问题是,并不是每个人都能自如地在 Linux 终端中比较文件,而且 `diff` 命令的输出可能会让一些人感到困惑。
|
||||
|
||||
以这个 `diff` 命令的输出为例:
|
||||
|
||||
![][2]
|
||||
|
||||
这里肯定涉及到一个学习曲线。然而,如果你使用的是桌面 Linux,你可以使用 [GUI][3] 应用来轻松比较两个文件是否有任何差异。
|
||||
|
||||
有几个 Linux 中的 GUI 差异比较工具。我将在本周的 Linux 应用亮点中重点介绍我最喜欢的工具 Meld。
|
||||
|
||||
### Meld:Linux(及 Windows)下的可视化比较和合并工具
|
||||
|
||||
通过 [Meld][4],你可以将两个文件并排比较。不仅如此,你还可以对文件进行相应的修改。这是你在大多数情况下想做的事情,对吗?
|
||||
|
||||
![File Comparison][5]
|
||||
|
||||
Meld 还能够比较目录,并显示哪些文件是不同的。它还会显示而文件是新的或是缺失的。
|
||||
|
||||
![Directory Comparison][6]
|
||||
|
||||
你也可以使用 Meld 进行三向比较。
|
||||
|
||||
![Three Way File Comparison][7]
|
||||
|
||||
图形化的并排比较在很多情况下都有帮助。如果你是开发人员,你可以用它来了解代码补丁。Meld 还支持版本控制系统,如 Git、[Mercurial][8]、[Subversion][9] 等。
|
||||
|
||||
### Meld 的功能
|
||||
|
||||
![][10]
|
||||
|
||||
开源的 Meld 工具具有以下主要功能:
|
||||
|
||||
* 进行双向和三向差异比较
|
||||
* 就地编辑文件,差异比较立即更新
|
||||
* 在差异和冲突之间进行导航
|
||||
* 通过插入、更改和冲突相应地标示出全局和局部差异,使其可视化
|
||||
* 使用正则文本过滤来忽略某些差异
|
||||
* 语法高亮显示
|
||||
* 比较两个或三个目录,看是否有新增加、缺失和更改的文件
|
||||
* 将一些文件排除在比较之外
|
||||
* 支持流行的版本控制系统,如 Git、Mercurial、Bazaar 和 SVN
|
||||
* 支持多种国际语言
|
||||
* 开源 GPL v2 许可证
|
||||
* 既可用于 Linux,也可用于 Windows
|
||||
|
||||
### 在 Linux 上安装 Meld
|
||||
|
||||
Meld 是一个流行的应用程序,它在大多数 Linux 发行版的官方仓库中都有。
|
||||
|
||||
检查你的发行版的软件中心,看看 Meld 是否可用。
|
||||
|
||||
![Meld In Ubuntu Software Center][11]
|
||||
|
||||
另外,你也可以使用你的发行版的命令行包管理器来安装 Meld。在 [Ubuntu 上,它可以在 Universe 仓库中找到][12],并且可以[使用 apt 命令安装][13]:
|
||||
|
||||
```
|
||||
sudo apt install meld
|
||||
```
|
||||
|
||||
你可以在 GNOME 的 GitLab 仓库中找到 Meld 的源码:
|
||||
|
||||
[Meld Source Code][14]
|
||||
|
||||
### 它值得使用吗?
|
||||
|
||||
我知道[大多数现代开源编辑器][15]都有这个功能,但有时你只是想要一个简单的界面,而不需要安装额外的附加软件来比较文件。Meld 就为你提供了这样的功能。
|
||||
|
||||
你是否使用一些其他工具来检查文件之间的差异?是哪种工具呢?如果你用过 Meld,你有什么经验?请在评论区分享你的意见。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/meld-gui-diff/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/abhishek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://linuxhandbook.com/diff-command/
|
||||
[2]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/diff-command-complicated-output.png?resize=795%2C551&ssl=1
|
||||
[3]: https://itsfoss.com/gui-cli-tui/
|
||||
[4]: https://meldmerge.org
|
||||
[5]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/file-comaprison-in-Linux-with-meld.png?resize=800%2C498&ssl=1
|
||||
[6]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/directory-comparison-in-Linux-with_meld.png?resize=800%2C497&ssl=1
|
||||
[7]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/three-way-file-comaprison-with-meld-in-linux.png?resize=800%2C466&ssl=1
|
||||
[8]: https://www.mercurial-scm.org/
|
||||
[9]: https://subversion.apache.org/
|
||||
[10]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/meld-visual-diff.png?resize=786%2C455&ssl=1
|
||||
[11]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/Meld-in-Ubuntu-Software-Center.png?resize=800%2C384&ssl=1
|
||||
[12]: https://itsfoss.com/ubuntu-repositories/
|
||||
[13]: https://itsfoss.com/apt-command-guide/
|
||||
[14]: https://gitlab.gnome.org/GNOME/meld
|
||||
[15]: https://itsfoss.com/best-modern-open-source-code-editors-for-linux/
|
||||
@@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (MATRIXKOO)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (mengxinayan)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
@@ -59,7 +59,7 @@ via: https://opensource.com/article/20/10/influence-open-source
|
||||
|
||||
作者:[Joshua Pearce][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
译者:[萌新阿岩](https://github.com/mengxinayan)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Got something to say? How to get started writing)
|
||||
[#]: via: (https://opensource.com/article/20/11/how-write-article)
|
||||
[#]: author: (Jen Wike Huger https://opensource.com/users/jen-wike)
|
||||
|
||||
Got something to say? How to get started writing
|
||||
======
|
||||
A community manager and editor shares her inspiration and tips for
|
||||
finding and sharing your expertise with others.
|
||||
![A person writing.][1]
|
||||
|
||||
Well, I suppose after all this talk of how to find your story and then write your story, I should make a post about how to do just that. I've broken it down into three sections: how to find your story, how to write your story, and how to share it and get it published.
|
||||
|
||||
During the All Things Open virtual event this year, I was invited to share my tips, and now you can watch that. It's about 20 minutes with some questions and commentary at the end.
|
||||
|
||||
You may have a clear reason why you want to write, or you may need some prodding. My belief is that we all have something valuable to share. Really. And the reasons are made clear in the survey answers in [this document][2]. One reason that resonates with many in the tech world is "because my manager wants me to," which could lead to a promotion or increased thought leadership in your field. Another great one for those working on an open source project is, "it is an act of giving back to the community... with the simultaneous goal of getting your name out in the community and building connections for other career opportunities."
|
||||
|
||||
### How to find your story
|
||||
|
||||
Do your homework, but this time hopefully it's a bit more fun and a bit less time-consuming. By all means, take the afternoon or the week to complete [this worksheet][3], but if you have an hour during work, this can fit into your busy schedule. Although I'm happy to take a look and help guide you once you get started, no one is grading your responses. They're yours, and their only goal is to get you closer to that elusive article. Whether it's your first, or your 100th, we all have reasons why it can be difficult to write.
|
||||
|
||||
The [worksheet][3] asks a variety of questions in a "choose your own adventure" type way. You can answer all of the questions, or skip to the parts that interest you most. It starts with asking:
|
||||
|
||||
* What do you do at your job?
|
||||
* What are you passionate about?
|
||||
* What communities are you or do you want to be a part of?
|
||||
|
||||
|
||||
|
||||
After you complete the worksheet to your liking, take a break. A few minutes, a few hours or days, and go back to it. What jumps off the page and still rings true? Perhaps it's now plainly obvious what your article should be about. If you still need a way to prioritize your choices, label each one with one of these time-based categories:
|
||||
|
||||
* Easy to write (you know this topic backward and forwards)
|
||||
* Quick to write (explaining is fast and a short read)
|
||||
* Hard to write (you may need to think through the process and list out many details)
|
||||
* Time-consuming to write (this may take some additional research in addition to being highly detailed)
|
||||
|
||||
|
||||
|
||||
### How to write an article
|
||||
|
||||
First, sit down and make yourself write an outline. I know, I know... boring! But this can save you a lot of time. Once you've landed on an outline that works for you and your topic, once you sit down and start writing, there's a better chance you'll get into the flow, following your outline, and knock it out in less time than you imagined. And in an amount of time that feels good to you and gives you a good feeling about writing, especially again and again.
|
||||
|
||||
Then, share it with a friend or an editor. Friends can be a quick and easy outlet, especially if they are of the writer sort. And, I encourage you to send it to an editor if you have a particular publication in mind for where you'd like to try to get it published. While you wait, buff up on your writing by taking a look at [a solid style guide][4].
|
||||
|
||||
Once you get to a place where you feel ready to get writing, review the format of an article and identify who your audience is. The format of an introduction that describes what the article is about and what the reader will learn, the body of the article focused on walking the reader logically through the steps or phases with straightforward headers, and a conclusion that gives final thoughts and a summary.
|
||||
|
||||
I like to write using a shareable document for easy collaboration and editing with others and editors.
|
||||
|
||||
### How to get your article published
|
||||
|
||||
First, decide whether you want to self-publish, on your own blog or a place like Medium, or if you want to get your article published on a publication like Opensource.com or Linux Today.
|
||||
|
||||
If you're reaching out to a publication, try to find information about how they would like you to submit your article. Some have webforms, some want you to simply send them an email. Some, like us, [have both][5]. Let them know who you are, what you wrote about, and perhaps why you wrote about it.
|
||||
|
||||
For example: My name is Jen Wike Huger. I'm a community manager and editor for Opensource.com, so my expertise is writing and working with authors. My article is about how to find your story, writing, and getting published.
|
||||
|
||||
### Wrapping up
|
||||
|
||||
The slide deck, worksheet, survey answers, and style guides for writing are [on GitHub][6].
|
||||
|
||||
The slides are from the All Things Open presentation. The worksheet is to help you decide what to write about, to find your story. The survey answers will inspire you and answer the question: Why should I write about what I know anyway? And the style guides will help you before and during the actual writing process, covering grammar, formatting, and more.
|
||||
|
||||
There are a ton more details baked into every part of this, so if you have specific questions, I welcome them in the comments, via email, or on Twitter.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/how-write-article
|
||||
|
||||
作者:[Jen Wike Huger][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/jen-wike
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003784_02_os.comcareers_resume_rh1x.png?itok=S3HGxi6E (A person writing.)
|
||||
[2]: https://github.com/JenWike/getpublished/blob/main/Why%20write_.txt
|
||||
[3]: https://github.com/JenWike/getpublished/blob/main/Worksheet_%20How%20to%20find%20your%20story.odt
|
||||
[4]: https://github.com/JenWike/getpublished/blob/main/styleguides
|
||||
[5]: https://opensource.com/how-submit-article
|
||||
[6]: https://github.com/JenWike/getpublished/
|
||||
@@ -0,0 +1,85 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (4 questions about AI ethics and how open source can help)
|
||||
[#]: via: (https://opensource.com/article/20/11/ai-ethics)
|
||||
[#]: author: (Sahana Sreeram https://opensource.com/users/sahanasreeram01gmailcom)
|
||||
|
||||
4 questions about AI ethics and how open source can help
|
||||
======
|
||||
Open source resources could provide effective solutions to some key
|
||||
ethical considerations for artificial intelligence.
|
||||
![A robot arm illustration][1]
|
||||
|
||||
As a high school student, I've become very interested in artificial intelligence (AI), which is emerging as one of the most impactful innovations of recent times. This past summer, I was selected for the [AI4ALL][2] program, where we learned how to develop AI systems using Python.
|
||||
|
||||
For my final project, I created an object-detection program and integrated it with a virtual drone simulation. Throughout the project, I was able to use open source frameworks, including [TensorFlow][3], [Keras][4], [Scikit-learn][5], and [PyTorch][6], to aid in developing the object-detection machine learning (ML) algorithm process.
|
||||
|
||||
By doing this project and using other open source frameworks like [Linux][7], [Apache Kafka][8], and [ElasticSearch][9], I realized the impact of open source technologies on AI system development. Access to these powerful, flexible technologies enables people to experiment with and develop AI systems.
|
||||
|
||||
I discovered another important aspect of AI when I attended a seminar at [William & Mary][10] about AI and ethics. As we discussed some of the ethical concerns surrounding AI systems, I started wondering: How do I make sure that the systems I'm developing are ethical?
|
||||
|
||||
To answer my question, I interviewed three experts: [Alon Kaufman][11], PhD, CEO of Duality Technologies; [Iria Giuffrida][12], PhD, a law professor at William & Mary; and an executive in the fintech industry (name kept confidential upon request). I am very grateful to these experts for giving me their valuable time, fueling my curiosity, and inspiring me with their journeys in this field.
|
||||
|
||||
### How important of a role does ethics currently play in AI systems?
|
||||
|
||||
As more advances are made with AI, society is starting to appreciate the importance of ethical implications. However, the discussions about ethical values in AI system development are still an academic exercise, Dr. Kaufman says. Today, much of AI, and especially ML models, remains a "black box" because advanced algorithms and complex AI technologies (such as deep learning) produce models that are not self-explainable. Without having explainable AI/ML models, it's hard to introduce ethical considerations into the conversation.
|
||||
|
||||
For Dr. Kaufman, the industry's focus today is on data security and protection. As more smart technology is developed, it's getting easier to acquire data. The large amounts of data handled in AI systems make them vulnerable to cyber breaches.
|
||||
|
||||
While it is certainly vital to build data protection measures for AI systems, it is becoming critical to shift the focus to other ethical implications, such as privacy and machine bias.
|
||||
|
||||
### Is ethical AI development a good goal for the future, or is it wishful thinking?
|
||||
|
||||
The short answer is that it is a reasonable goal to create ethical AI systems, but it will take time.
|
||||
|
||||
"Ethics" is a difficult concept to define. One approach is to look at ethics through a three-pronged methodology: security, privacy, and fairness. Most of the industry is now focused on security, and a practical next step could be to address the issues of privacy and ensuring data anonymity. "Privacy-enhancing technologies, such as secure computing and [synthetic data][13] could offer assistance in this process," explains Dr. Kaufman. Only after finding solutions to the security and privacy areas of ethics is it reasonable to venture into machine fairness and bias.
|
||||
|
||||
There are many factors to consider in the development of unbiased AI. "The first step is the deployment of active-learning models into society, followed by the actual development of [fair systems][14]," says the fintech industry expert. He explains that when ML equipped with active learning is deployed, society's own biases are often imposed on the model, even unknowingly, creating very flawed systems. When developers create AI systems, their preconceived notions must never be injected into the system code, says Dr. Kaufman. These are some of the key areas that must be addressed in developing unbiased models.
|
||||
|
||||
### How early should students be exposed to ethical considerations in AI/ML?
|
||||
|
||||
It's increasingly important to learn not only about computer science principles but also about how to build ethical models. Professor Giuffrida says computer scientists and AI developers have not explicitly been trained to think about the ethics behind their systems. This is why the development of bias-proof systems cannot be a linear process, she says; they must go through multiple review levels to minimize injecting bias in the machine process.
|
||||
|
||||
Professor Giuffrida emphasizes that AI development should be treated as an interdisciplinary study, meaning that it is not just developers who are in charge of creating accurate and ethical systems—that's an enormous responsibility to put on one group. But introducing ethical concepts to aspiring AI engineers at a foundational level could accelerate building sustainable, functional, and ethical systems.
|
||||
|
||||
### Will ethics come at the expense of innovation?
|
||||
|
||||
This was the main question I kept coming back to throughout the interviews. During the AI4ALL course, we explored the recent [Genderify fiasco][15], which was AI software intended to identify a user's gender based on several data points, including name, email address, and username. When launched for public use, the results were highly inaccurate—for example, the name "Meghan Smith" was assigned female, but "Dr. Meghan Smith" was assigned male. These biases led to the service's failure. More comprehensive ethical reviews and tests conducted before launch could make this type of product successful, at least initially.
|
||||
|
||||
All three experts voiced the idea that ethical boundaries are becoming necessary. According to the fintech executive, "Reasonable ethical constraints will not limit innovation—companies must eventually figure out how to innovate within these boundaries." In this fashion, ethical considerations could increase sustainability and success for a product—rather than putting a complete stop to AI development. Venture capitalist Rob Toews offered an interesting perspective on [regulating AI][16], and I recommend this article if you want to learn more about this topic.
|
||||
|
||||
Ultimately, introducing ethics into pure AI is a daunting but necessary step to secure AI's viability in our world. Open source resources could provide effective solutions to some key ethical considerations, including comprehensive system testing. For example, the [AI Fairness 360][17] open source toolkit by IBM assesses discrimination and biases in ML models. Open source communities have the ability to develop tools like this to provide greater coverage and support for ethical AI systems. In the meantime, I believe it is my generation's responsibility to build bridges between creating revolutionary AI technologies and considering ethical implications that will stand the test of time.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/ai-ethics
|
||||
|
||||
作者:[Sahana Sreeram][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/sahanasreeram01gmailcom
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/robot_arm_artificial_ai.png?itok=8CUU3U_7 (A robot arm illustration)
|
||||
[2]: https://ai-4-all.org/
|
||||
[3]: https://www.tensorflow.org/
|
||||
[4]: https://keras.io/
|
||||
[5]: https://scikit-learn.org/stable/
|
||||
[6]: https://pytorch.org/
|
||||
[7]: https://www.linux.org/
|
||||
[8]: https://kafka.apache.org/
|
||||
[9]: https://www.elastic.co/
|
||||
[10]: https://www.wm.edu/
|
||||
[11]: https://www.linkedin.com/in/alon-kaufman-24067b154/
|
||||
[12]: https://law2.wm.edu/faculty/bios/fulltime/igiuffrida.php
|
||||
[13]: https://en.wikipedia.org/wiki/Synthetic_data
|
||||
[14]: https://en.wikipedia.org/wiki/Fairness_(machine_learning)
|
||||
[15]: https://www.theverge.com/2020/7/29/21346310/ai-service-gender-verification-identification-genderify
|
||||
[16]: https://www.forbes.com/sites/robtoews/2020/06/28/here-is-how-the-united-states-should-regulate-artificial-intelligence/?sh=1c242ebc7821
|
||||
[17]: https://aif360.mybluemix.net/
|
||||
@@ -0,0 +1,87 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Comparing the similarities and differences between inner source and open source)
|
||||
[#]: via: (https://opensource.com/article/20/11/inner-source)
|
||||
[#]: author: (Nithya Ruff https://opensource.com/users/nithyaruff)
|
||||
|
||||
Comparing the similarities and differences between inner source and open source
|
||||
======
|
||||
Open source principles can be applied within a company to access the
|
||||
benefits of collaborative development. Here's how.
|
||||
![two women kanban brainstorming and brainmapping with post-it notes on a whiteboard ][1]
|
||||
|
||||
Open source software (OSS) has been around since the 1990s and has thrived, quickly growing to become mainstream. It is now more well understood around the world than it has ever been before. Some refer to it as FOSS to highlight the Freedom part of open source (Free and Open Source Software). And in 2014, at OSCON, the term "inner source" was debuted, and people started talking about how to use the principles of open source, but inside of a company. It raised several questions for those unfamiliar with the term, which I hope to answer with this article. For example, what is similar about the two, what is different, the company roles involved in the two, is inner source taking the energy away from open source, etc. These are all fair questions, and as my organization practices both and is involved in both movements, I want to take some time to share insight with this audience as a developer, as a company, and as an open source enthusiast.
|
||||
|
||||
There are two principal elements that make open source successful. The first is that it is licensed under OSS licenses that promote and support free distribution of the source with the binaries for people to use any way they want. When GPL (General Public License) was introduced in the 1990s, it was revolutionary—no charge, source included, and no restriction on use. That helped proliferate open source projects like Linux and allowed rapid innovation.
|
||||
|
||||
The other particularly essential element is the way open source software grows and develops. It happens through a community of people who are most often not in the same organization or geographic location. They come together because they believe in the solution or mission of the project. Because these people came from different development cultures but needed to work on common projects, they evolved norms for working together, such as how they communicate with each other, how decisions are made, and how to review new submissions. This codification of how disparate teams work without being in the same organization is unique and powerful. This type of development is known as "collaborative development."
|
||||
|
||||
Not all communities are effective, but the ones who figure out how to work together often have some common elements:
|
||||
|
||||
* Governance: They work out how the project will govern itself—decisions, roles, reviews, meetings, mission, budgets, organization structures, etc.
|
||||
|
||||
* Communication: They figure out how to work with people across time zones, across cultures, and organizations. For example, documenting decisions on a mailing list vs. live discussions. Providing people with 24 to 48 hours to review and respond to a question or decision is another good practice established to allow people in different zones and different work situations to collaborate.
|
||||
|
||||
* Common tools: Review and communication are imperative to development. Tools such as GitLab and GitHub build in collaborative practices to enable working across teams.
|
||||
|
||||
* Architecture: Projects are often architected for maximum engagement into components, API (Application Programming Interface), sub-systems so that not everyone needs to know everything, or they don’t change the whole project when they make changes.
|
||||
|
||||
|
||||
|
||||
|
||||
Both in response to digital challenges as well as changing customer expectations, enterprises outside of the tech vendor space, in particular, have been transforming how they build products and services as well as how they engage with their customers. And with the 2020 COVID-19 pandemic, many companies and organizations have gone virtual and fast-tracked their digital transformation plans to meet changing customer and market needs. And some accelerated their plans to capture new opportunities and support changes in how customers consumed their services. Teams that relied on physical proximity, hallway conversations, and other elements of development were faced with a need to change how they worked. Many of them realized that they could turn to the collaborative development model of open source for examples of how to work remotely and effectively.
|
||||
|
||||
Even before the COVID-19 pandemic, because of early digital transformation plans, companies had already begun adopting and working with open source and had realized the benefits of open innovation. The need to go faster, reduce costs, breakdown silos across the company, and reuse vs. reinvent has created a spur to do more collaborative development or open source-style community development inside the company walls.
|
||||
|
||||
The benefits of collaborative development can be applied in many ways:
|
||||
|
||||
* Collaboration among remote and geographically distributed organizations
|
||||
|
||||
* Creating a more open and collaborative culture inside a company
|
||||
|
||||
* Creating communities around common interests and common problems
|
||||
|
||||
|
||||
|
||||
|
||||
The traditional way companies develop software inside companies is quite different from the open source collaborative model. Because of how budgets, organization structures, and incentives work, teams work in silos, are top-driven, and have no incentive to share and collaborate across the organization. Teams often report to the same organization, resulting in low documentation of decisions and low leverage of experts across the company.
|
||||
|
||||
Many organizations have been experimenting with collaborative development for some time. At Comcast, for example, teams called it enterprise source. But then the term "inner source" was created by Tim O’Reilly, founder, CEO, and publisher at O’Reilly publishing in 2001. (This [interview][2] with Tim is a remarkable story of how he came to coin this term). He talks about how the modularity of code and the access to source was a huge driver for collaboration, even more than the license itself. He calls it the "Architecture of Participation." Soon after, in 2015, Danese Cooper, who was running the OSPO (Open Source Program Office) at PayPal at that time, [introduced this term][3] at OSCON. She also shared what PayPal had been doing inside the company to break down silos and to create collaboration. The [InnerSource Commons][4] non-profit foundation was also established to allow people to collaborate on their experiences, patterns, and best practices. Here is a more formal definition of inner source:
|
||||
|
||||
> "Inner source is an adaptation of open source practices to code that remains proprietary and can be seen only within a single organization, or a small set of collaborating organizations. Thus, inner source is a historical development drawing on the open source movement along with other trends in software."
|
||||
>
|
||||
> —From [_Adopting InnerSource_][5], O’Reilly Publications
|
||||
|
||||
The biggest similarities between open source and inner source involve the collaborative development model. Working across teams inside an organization on common source code is a culture change for a traditional enterprise. Both versions of it need sponsorship and support from the top to thrive inside an organization.
|
||||
|
||||
The biggest differences are what motivates one to start an inner source project over an open source project. The often-repeated wisdom of open source communities is that people get into it because they have an "itch to scratch." Often, trying to solve a technical issue is the reason that they start a new project. With inner source, there may be more of an organization-wide reason to start opening their code and collaborating with other teams. One main reason is to enable another team to work more effectively with the platform or to reduce a duplicate effort. Some organizations have chosen a default approach of opening all repositories for anyone in the company to see and use or collaborate on. One huge driver has been to stage it as an inner source project before fully open sourcing it. This allows the team to hone a good collaboration strategy and practice before open sourcing.
|
||||
|
||||
I like the model that PayPal used—having inner source and open source be a part of the same organization. There are shared practices, skills, and tools that can be used across the two. At Comcast, both practices live in the Open Source Program Office. The inner source team has built a guild with members of architecture, security, and leadership to develop the practice and governance of our inner source projects. You can listen to Comcast Open Source Program Manager and InnerSource leader Brittany Istenes [talk][6] to hear more about what we did with the guild and scaling inner source back from the InnerSource Commons Fall 2020 Summit.
|
||||
|
||||
While some people criticize the inner source movement and say that it has distracted from the open source movement, it has actually accelerated open source collaborative practices inside organizations. While most companies use open source, few were deeply engaged in communities or understood how open collaboration works. The fact that the collaborative development model can be used inside a company to do product or organizational work has led to a deeper understanding and better development practices at Comcast. I see a natural growth from this to more contributions and more engagement with open source communities as teams feel more confident in engaging through their inner source work.
|
||||
|
||||
No matter what you call it—inner source, enterprise source, collaborative development—more collaboration inside the company is a particularly good thing. Better development practices, documentation, onboarding, and mentoring are often direct results. If you are interested in more information, check out [innersourcecommons.org][7] for great talks from several companies practicing inner source, including Comcast. I believe that inner source is the next phase of open source development.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/inner-source
|
||||
|
||||
作者:[Nithya Ruff][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/nithyaruff
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/whiteboard-brainstorming-brainmapping-design-thinking-postits-kanban.png?itok=Is2Tg1Jk (Brainstorming with post-it notes on a whiteboard)
|
||||
[2]: https://www.youtube.com/watch?v=2HR0D8_tKoA&t=573s
|
||||
[3]: https://www.youtube.com/watch?v=r4QU1WJn9f8
|
||||
[4]: https://innersourcecommons.org/
|
||||
[5]: https://www.oreilly.com/library/view/adopting-innersource/9781492041863/ch01.html
|
||||
[6]: https://www.youtube.com/watch?v=RenQ8B7aX84
|
||||
[7]: http://innersourcecommons.org
|
||||
@@ -0,0 +1,90 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Why failure should be normalized and how to do it)
|
||||
[#]: via: (https://opensource.com/article/20/11/normalize-failure)
|
||||
[#]: author: (Lisa Seelye https://opensource.com/users/lisa)
|
||||
|
||||
Why failure should be normalized and how to do it
|
||||
======
|
||||
"Everybody is perfect, except you." This toxic thought can creep in and
|
||||
ruin your confidence. Here's how to normalize failure during the
|
||||
learning process and remember that everyone makes mistakes.
|
||||
![failure sign at a party, celebrating failure][1]
|
||||
|
||||
All of your heroes have failures under their belts—from minor mistakes to major disasters. Nobody knows how to do everything automatically, and the process of learning is usually a messy one. So why is the perception that everyone but you knows what they’re doing so common? Why do we externalize our successes but internalize our failures?
|
||||
|
||||
How does it make you feel when you struggle to learn something new, then see another person take their Jira card away and return at the end of the sprint with something fully fleshed out and working, gushing about it at the demo? Sure, you closed your card too, but it was really hard! There was a new algorithm, a new programming language, a new system all to be learned. How did she make it look so effortless?
|
||||
|
||||
The truth is, she might have struggled with the same issues you did and wondered how you made it look so effortless!
|
||||
|
||||
### Failure is normal, healthy, and invisible
|
||||
|
||||
Whether we call them mistakes, bad assumptions, or some other euphemism, it's hard not to judge ourselves or expect better of ourselves, especially compared to other people.
|
||||
|
||||
My background is largely in Linux systems administration, and in this line of work, it is often a matter of "when" and not "if" we will have a production service disruption. Those service disruptions can happen for various reasons—sometimes it's because a person made a mistake. Setting aside the discussion around controls to mitigate human error, we can see plain as day that I, Lisa Seelye, made a mistake that directly caused a production problem.
|
||||
|
||||
Whenever a group of sysadmins gets together, we usually end up talking about our work, and inevitably, we get around to stories of production service disruptions that we’ve been a part of (or caused). It’s cathartic to hear how badly other people have messed up and then look around and see that we are all human and making mistakes is part of that.
|
||||
|
||||
I feel that this kind of sharing is vital to the success of people in the information technology sector.
|
||||
|
||||
### Why should we share?
|
||||
|
||||
In addition to sharing our mistakes in order to normalize them, I also believe that it is equally important to share our learning processes—this is both to drive home the idea that we all start somewhere and that learning is often filled with failures and misconceptions.
|
||||
|
||||
As an individual, I need to remind myself that it may only appear that my peers return from a week working on a card with a fully fleshed-out solution. Reality may, in fact, be that they don’t understand the requirements, the codebase, the language, the algorithms needed, etc. Either way, it’s a logical fallacy to believe they do not face these challenges because of the appearance of the final product.
|
||||
|
||||
### But why should we share?
|
||||
|
||||
We should share our learning experiences because we all benefit from hearing about the challenges other people face and how they overcome them. If the Jira card wasn’t clear, then we can do better. If the algorithm wasn’t clear, then maybe education can be done around it.
|
||||
|
||||
Most importantly, we need to normalize that it’s okay not to know everything, that it’s okay to still be learning, and to ask for help. Setting an example for new or more junior engineers is important. In our industry, we deal with extremely complex systems that can interact with one another in strange or unexpected ways. In many cases, it is simply not possible for one person to know everything. Being open about our learning processes and our mistakes can lead to tighter bonding.
|
||||
|
||||
Do new engineers on your team have the set expectation that it’s okay to interrupt and ask questions? Saying it on day one is easy, but practicing the value is another thing. How are approachability and openness demonstrated in your team?
|
||||
|
||||
### My learning opportunities
|
||||
|
||||
It could be very easy to title this section "my mistakes" and then rattle off all the times I’ve made mistakes, but that doesn’t quite illustrate the point. I recognize these mistakes, but they’re also events that expanded the understanding of my craft. While I didn’t set out to intentionally do any of these things, I certainly learned from them.
|
||||
|
||||
I have accidentally dropped (deleted) a customer’s database. It was lucky for everyone that it was a beta-phase database and no further harm was done. I learned a valuable lesson that day: be very watchful of what code is doing, and be careful about what environment you are working in.
|
||||
|
||||
One day, while performing routine maintenance with an odd DNS setup, I accidentally broke the ability for customers to provide credit card information to the secure site. We had two "payments" DNS records that served to override a wildcard DNS record, and I assumed that the second "payments" record was still present. It wasn’t. And then the wildcard record took over, and the DNS started behaving like "payments" wasn’t special at all anymore. Of course, I had no idea this was happening at all—it wasn’t until my maintenance was over that I learned of the folly.
|
||||
|
||||
Customers weren’t able to provide payment information for almost two hours! I learned my lesson, though: when there is something special about a particular configuration, be sure to make sure it stays special throughout its lifetime. When DNS gets involved, all kinds of things can break.
|
||||
|
||||
Before I started speaking at conferences, I was an attendee, and I watched talks online. Pivoting to speaking myself, I was worried that I’d say too many "umms" and "uhs" and that my jokes would fall flat. The speakers I enjoyed over the years seemed to not have those problems at all, while I was unpolished.
|
||||
|
||||
But once I got up on stage, I found that my perception had changed. I had practiced my talk with an audience and listened to their feedback—turns out I had a little polish. In front of the audience, I did misspeak and not say something exactly how I wanted, but it didn’t matter. What I didn’t realize from my vantage point in the audience is that the audience wants the speaker to succeed, and the speaker can shift directions in their talk without the audience knowing.
|
||||
|
||||
I certainly have made and continue to make those sounds, and I have even had to correct major factual information the night before a talk, but the audience never knows. The audience sees what I show them and, because they want me to succeed, they forgive my "umms" and "uhs."
|
||||
|
||||
I admit that I am not perfect. I ship bugs, and I try to learn from them.
|
||||
|
||||
### How to share
|
||||
|
||||
Sharing the difficulties we’ve encountered along the learning process or in our day to day career is important, though just as important is how they are shared. I share the things I’ve learned (the hard way) with frankness and no self-judgment. It is in this spirit that I think we should all share. I’m not a bad person because I’ve made mistakes, and neither are you.
|
||||
|
||||
How, then, should we share? Who is the audience?
|
||||
|
||||
In the midst of a production service disruption, like with the DNS payment situation above, there’s no room for coyness or hiding anything. The most important thing is to make key stakeholders aware and then rally to fix the situation. The audience is first internal—your team, business leaders, the support team. Next, the audience is outward-facing—the customers. It is wise to involve communications experts when crafting that outward message.
|
||||
|
||||
When sharing with a junior engineer, we need to normalize the learning process. People aren’t born knowing how pointers in C work, so we all need to learn what the pitfalls of pointers are. It’s okay to need to learn new skills at any skill level, and it’s also okay to need to reinforce those skills. The message we send should be free of judgment.
|
||||
|
||||
So write a blog post, make a Twitter thread, share frustrations in Slack channels, ask for help. Together we can dismiss the myth that everybody's perfect, except you.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/normalize-failure
|
||||
|
||||
作者:[Lisa Seelye][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/lisa
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/fail_failure_celebrate.png?itok=LbvDAEZF (failure sign at a party, celebrating failure)
|
||||
@@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (robsean)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (alim0x)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Getting started with Emacs)
|
||||
[#]: via: (https://opensource.com/article/20/3/getting-started-emacs)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
Getting started with Emacs
|
||||
======
|
||||
10 tips for diving into the world of this useful group of open source
|
||||
text editors.
|
||||
![Computer keyboard typing][1]
|
||||
|
||||
Many people say they want to learn [Emacs][2], but many of them shy away after the briefest encounter. It's not because Emacs is bad or even that complex. The problem, I believe, is that people don't actually want to learn Emacs; they want to be comfortable with Emacs traditions. They want to understand the arcane keyboard shortcuts and unfamiliar terminology. They want to use Emacs as they believe it's "meant to be used."
|
||||
|
||||
I sympathize with this because that's how I felt about Emacs. I thought that all true Emacs users only ran it inside a terminal, and never used arrow keys or menus, much less a mouse. That's a great way to discourage yourself from getting started with Emacs. There are enough unique .emacs config files out there to prove that if there's one common strain among Emacs users, it's that everyone uses Emacs differently.
|
||||
|
||||
Learning Emacs is easy. It's loving Emacs that's hard. To love Emacs, you have to discover the features it has that you've been looking for, sometimes without knowing you've been missing them. And that takes experience.
|
||||
|
||||
The only way to get that experience is to start at the beginning—by actively using Emacs. Here are ten tips to help you figure out what works best for you.
|
||||
|
||||
### Start with the GUI
|
||||
|
||||
One of the greatest things about Emacs (and its friendly competitor, [Vim][3], too) is that it can be run in a terminal, which is useful when you SSH into a server, but not very significant on computers built within the last 15 years or so. The GUI version of Emacs can be run on extremely [low-powered devices][4], and it has lots of pragmatic features that both novice and experienced users can appreciate.
|
||||
|
||||
For example, if you don't know how to copy a word with just keyboard shortcuts in Emacs, the Edit menu's Copy, Cut, and Paste selections provide the path of least resistance. There's no reason to punish yourself for choosing Emacs. Use its menus, use your mouse to select regions and click in-buffer buttons, and don't let unfamiliarity stand in your way of being productive.
|
||||
|
||||
![Emacs slackware][5]
|
||||
|
||||
These features are built into Emacs because users use them. You should use them when you need them and work your way up to the obscure commands you think you might need when you eventually use Emacs over SSH on a VT100 terminal with no Alt or arrow keys.
|
||||
|
||||
### Get used to the terminology
|
||||
|
||||
Emacs has special terms for its UI elements. The evolution of personal computing didn't build upon the same terms, so many are relatively foreign to the modern computer user, and others are the same but have different meanings. Here are some of the most common terms:
|
||||
|
||||
* Frame: In Emacs, the frame is what modern computing calls a "window."
|
||||
* Buffer: A buffer is a communication channel for Emacs. It may serve as a command-line for an Emacs process, or a shell, or just the contents of a file.
|
||||
* Window: A window is your view into a buffer.
|
||||
* Mini-buffer: The primary command-line, located at the bottom of the Emacs window.
|
||||
|
||||
|
||||
|
||||
![Emacs tutorial map][6]
|
||||
|
||||
### Making sense of Emacs modifier keys
|
||||
|
||||
On a PC keyboard, the Ctrl key is referred to as C, and the Alt key is referred to as M. These aren't the C and M keys, and because they're always paired with an accompanying letter or symbol key, they're easy to recognize in the documentation.
|
||||
|
||||
For example, C-x means Ctrl+X in modern keyboard notation, and M-x is Alt+X. You press the keys together just as you do when you're cutting text from any application.
|
||||
|
||||
There's another level of keyboard shortcuts, though, quite unlike anything on modern computers. Sometimes, a keyboard shortcut isn't just one key combo and instead consists of a series of key presses.
|
||||
|
||||
For instance, C-x C-f means to press Ctrl+X as usual, and then Ctrl+C as usual.
|
||||
|
||||
Sometimes, a keyboard shortcut has a mixture of key types. The combo C-x 3 means to press Ctrl+X as usual, and then the number 3 key.
|
||||
|
||||
The way Emacs can do these fancy power combos is because certain keys put Emacs into a special command mode. If you press C-X (that's Ctrl+X), you're telling Emacs to enter an idle state, waiting for a second key or keyboard shortcut.
|
||||
|
||||
Emacs documentation, both official and unofficial, is full of keyboard shortcuts. Practice mentally translating C to Ctrl and M to Alt, and all those docs will make a lot more sense to you.
|
||||
|
||||
### Alternate shortcuts for cut, copy, and paste
|
||||
|
||||
Canonically, copying text is performed with a series of keyboard shortcuts that depend on how you want to copy or cut.
|
||||
|
||||
For instance, you can cut a whole word with M-d (Emacs lingo for Alt+d), or a whole line with C-k (Ctrl+K), or a highlighted region with M-m (Alt+M). You can get used to that if you want, but if you like Ctrl+C and Ctrl+X and Ctrl-V, then you can use those instead.
|
||||
|
||||
Enabling modern cut-copy-paste requires activating a feature called CUA (Common User Access). To activate CUA, click on the Options menu and select Use CUA Keys. With this enabled, C-c copies highlighted text, C-x cuts highlighted text, and C-v pastes text. This mode is only actually active when you've selected text, so you can still learn the usual C-x and C-c bindings that Emacs normally uses.
|
||||
|
||||
### It's OK to share
|
||||
|
||||
Emacs is an application and has no awareness of your feelings or loyalty towards it. If you want to use Emacs only for tasks that "feel" right for Emacs, and different editor (like Vim) for other tasks, you can do that.
|
||||
|
||||
Your interactions with an application influence how you work, so if the pattern of keypresses required in Emacs doesn't agree with a specific task, then don't force yourself to use Emacs for that task. Emacs is just one of many open source tools available to you, and there's no reason to limit yourself to just one tool.
|
||||
|
||||
### Explore new functions
|
||||
|
||||
Most of what Emacs does is an elisp function that can be invoked from a menu selection, keyboard shortcut, or in some cases, a specific event. All functions can be executed from the mini-buffer (the command-line at the bottom of the Emacs frame). You could, in theory, even navigate your cursor by typing in functions like **forward-word** and **backward-word** and **next-line** and **previous-line**, and so on. It would be unbearably inefficient, but that's the kind of direct access to the code you're running. In a way, Emacs is its own API.
|
||||
|
||||
You can find out about new functions by reading about Emacs on community blogs, or you can take a more direct approach and use the describe-function function. To get help on any function, press M-x (that's Alt+X) and then type describe-function, and then press Return or Enter. You are prompted for a function name, and then shown a description of that function.
|
||||
|
||||
You can get a list of all available functions by typing M-x (Alt+X), followed by ?.
|
||||
|
||||
You can also get pop-up descriptions of functions as you type them by pressing M-x and then typing **auto-complete-mode**, and then pressing Return or Enter. With this mode active, as you type any Emacs function into your document, you're offered auto-completion options, along with a description of the function.
|
||||
|
||||
![Emacs function][7]
|
||||
|
||||
When you find a useful function and use it, Emacs tells you the keyboard binding for it, if one is set. If one doesn't exist, you can assign one yourself by opening your $HOME/.emacs configuration file and entering a keyboard shortcut assignment. The syntax is global-set-key, followed by the keyboard shortcut you want to use, followed by the function you want to invoke.
|
||||
|
||||
For example, to assign the screenwriter-slugline function to a keyboard binding:
|
||||
|
||||
|
||||
```
|
||||
`(global-set-key (kbd “C-c s”) 'screenwriter-slugline)`
|
||||
```
|
||||
|
||||
Reload your configuration file, and the keyboard shortcut is available to you:
|
||||
|
||||
|
||||
```
|
||||
`M-x load-file ~/.emacs`
|
||||
```
|
||||
|
||||
### Panic button
|
||||
|
||||
As you use Emacs and try new functions, you're bound to start invoking something you didn't mean to invoke. The universal panic button in Emacs is C-g (that's Ctrl+G).
|
||||
I remember this by associating G with GNU, and I imagine I'm calling upon GNU to rescue me from a poor decision, but feel free to make up your own mnemonic.
|
||||
|
||||
If you press C-g a few times, the Emacs mini-buffer returns to a latent state, pop-up windows are hidden, and you're back to the safety of a plain old boring text editor.
|
||||
|
||||
### Ignore the keyboard shortcuts
|
||||
|
||||
There are too many potential keyboard shortcuts to summarize them all here, much less for you ever to hope to memorize. That's by design. Emacs is meant to be customized, and when people write plugins for Emacs, they get to define their own special keyboard shortcuts.
|
||||
|
||||
The idea isn't to memorize all shortcuts right away. Your goal, instead, is to get comfortable using Emacs. The more comfortable you become in Emacs, the more you'll get tired of resorting to the menu bar all the time, and you'll start to memorize the combos important to you.
|
||||
|
||||
Everyone has their own favorite shortcuts based on what they typically do in Emacs. Someone who spends all day writing code in Emacs may know all the keyboard shortcuts for running a debugger or for launching language-specific modes, but know nothing about Org-mode or Artist-mode. It's natural, and it's fine.
|
||||
|
||||
### Practice Emacs when you use Bash
|
||||
|
||||
One advantage to knowing Emacs keyboard shortcuts is that many of them also apply in Bash:
|
||||
|
||||
* C-a—go to the beginning of a line
|
||||
* C-e—go to the end of a line
|
||||
* C-k—cut the whole line
|
||||
* M-f—go forward a word
|
||||
* M-b—go back a word
|
||||
* M-d—cut a word
|
||||
* C-y—yank back (paste) the most recently cut content
|
||||
* M-Shift-U—capitalize a word
|
||||
* C-t—swap two characters (for example, sl becomes ls)
|
||||
|
||||
|
||||
|
||||
There are many more examples, and it an make your interactions with your Bash terminal faster than you ever imagined.
|
||||
|
||||
### Packages
|
||||
|
||||
Emacs has a built-in package manager to help you discover new plugins. Its package manager contains modes to help you edit specific types of text (for instance, if you edit JSON files frequently, you might try ejson-mode), embedded applications, themes, spellchecking options, linters, and more. This is where Emacs has the potential to become crucial to your daily computing; once you find a great Emacs package, you may not be able to live without it.
|
||||
|
||||
![Emacs emoji][8]
|
||||
|
||||
You can browse packages by pressing M-x (that's Alt+X) and then typing **package-list-packages** command and then pressing Return or Enter. The package manager updates its cache each time you launch it, so be patient the first time you use it while it downloads a list of available packages. Once loaded, you can navigate with your keyboard or mouse (remember, Emacs is a GUI application). Each package name is a button, so either move your cursor over it and press Return or just click it with your mouse. You can read about the package in the new window that appears in your Emacs frame, and then install it with the Install button.
|
||||
|
||||
Some packages need special configuration, which is sometimes listed in its description, but other times require you to visit the package's home page to read more about it. For example, the auto-complete package ac-emoji installs easily but requires you to have a symbol font defined. It works either way, but you only see the corresponding emoji if you have the font installed, and you might not know that unless you visit its homepage.
|
||||
|
||||
### Tetris
|
||||
|
||||
Emacs has games, believe it or not. There's Sudoku, quizzes, minesweeper, a just-for-fun psychotherapist, and even Tetris. These aren't particularly useful, but interacting with Emacs on any level is great practice, and games are a great way to maximize your time spent in Emacs.
|
||||
|
||||
![Emacs tetris][9]
|
||||
|
||||
Tetris is also how I was introduced to Emacs in the first place, so of all versions of the game, it's the Emacs version that's truly my favorite.
|
||||
|
||||
### Using Emacs
|
||||
|
||||
GNU Emacs is popular because it's impossibly flexible and highly extensible. People get so accustomed to Emacs keyboard shortcuts that they habitually try to use them in all other applications, and they build applications into Emacs, so they never have to leave in the first place. If you want Emacs to play an important role in your computing life, the ultimate key is to embrace the unknown and start using Emacs. Stumble through it until you've discovered how to make it work for you, and then settle in for 40 years of comfort.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/3/getting-started-emacs
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/keyboaord_enter_writing_documentation.jpg?itok=kKrnXc5h (Computer keyboard typing)
|
||||
[2]: https://opensource.com/downloads/emacs-cheat-sheet
|
||||
[3]: https://opensource.com/downloads/cheat-sheet-vim
|
||||
[4]: https://opensource.com/article/17/2/pocketchip-or-pi
|
||||
[5]: https://opensource.com/sites/default/files/uploads/emacs-slackware.jpg (Emacs slackware)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/emacs-tutorial-map.png (Emacs tutorial map)
|
||||
[7]: https://opensource.com/sites/default/files/uploads/emacs-function.jpg (Emacs function)
|
||||
[8]: https://opensource.com/sites/default/files/uploads/emacs-emoji_0.jpg (Emacs emoji)
|
||||
[9]: https://opensource.com/sites/default/files/uploads/emacs-tetris.jpg (Emacs tetris)
|
||||
182
sources/tech/20200508 Metaphors in man pages.md
Normal file
182
sources/tech/20200508 Metaphors in man pages.md
Normal file
@@ -0,0 +1,182 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Metaphors in man pages)
|
||||
[#]: via: (https://jvns.ca/blog/2020/05/08/metaphors-in-man-pages/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
Metaphors in man pages
|
||||
======
|
||||
|
||||
This morning I was watching a [great talk by Maggie Appleton][1] about metaphors. In the talk, she explains the difference between a “figurative metaphor” and a “cognitive metaphor”, and references this super interesting book called [Metaphors We Live By][2] which I immediately got and started reading.
|
||||
|
||||
Here’s an example from “Metaphors We Live By” of a bunch of metaphors we use for ideas:
|
||||
|
||||
* ideas as **food**: “_raw_ facts”, “_half-baked_ ideas”, “_swallow_ that claim”, “_spoon-feed_ our students”, “_meaty_ part of the paper”, “that idea has been _fermenting_ for years”
|
||||
* ideas as **people**: “the theory of relativity _gave birth_ to an enormous number of ideas”, “whose _brainchild_ was that”, “those ideas _died off_ in the middle ages”, “cognitive psychology is in its _infancy_“
|
||||
* ideas as **products**: “we’ve _generated_ a lot of ideas this week”, “it needs to be _refined_”, “his _intellectual productivity_ has decreased in recent years”
|
||||
* ideas as **commodities**: “he won’t _buy_ that”, “that’s a _worthless_ idea”, “she has _valuable_ ideas”
|
||||
* ideas as **resources**: “he _ran out_ of ideas”, “let’s _pool_ our ideas”, “that idea will _go a long way_“
|
||||
* ideas as **cutting instruments**: “that’s an _incisive_ idea”, “that _cuts right to the heart_ of the matter”, “he’s _sharp_“
|
||||
* ideas as **fashions**: “that idea _went out of style_ years ago”, “marxism is _fashionable_ in western europe”, “berkeley is a center of _avant-garde_ thought”, “semiotics has become quite _chic_“
|
||||
|
||||
|
||||
|
||||
There’s a [long list of more English metaphors here][3], including many metaphors from the book.
|
||||
|
||||
I was surprised that there were so many different metaphors for ideas, and that we’re using metaphors like this all the time in normal language.
|
||||
|
||||
### let’s look for metaphors in man pages!
|
||||
|
||||
Okay, let’s get to the point of this blog post, which is just a small fun exploration – there aren’t going to be any Deep Programming Insights here.
|
||||
|
||||
I went through some of the examples of metaphors in Metaphors To Live By and grepped all the man pages on my computer for them.
|
||||
|
||||
### processes as people
|
||||
|
||||
This is one of the richer categories – a lot of different man pages seem to agree that processes are people, or at least alive in some way.
|
||||
|
||||
* Hangup detected on controlling terminal or **death** of controlling process (`man 7 signal`)
|
||||
* can access the local **agent** through the forwarded connection (`man ssh_config`)
|
||||
* If the exit of the process causes a process group to become **orphaned** (`man exit`)
|
||||
* If a parent process terminates, then its **“zombie” children** (if any) (`man wait`)
|
||||
* … send SIGHUP to the **parent** process of the client (`man tmux`)
|
||||
* Otherwise, it **“runs” to catch up** or waits (`man mplayer`)
|
||||
* However, Git does not (and it should not) change tags **behind users back** (`man git-tag`)
|
||||
* will **listen** forever for a connection (`man nc_openbsd`)
|
||||
* this monitor scales badly with the number of files being **observed** (`man fswatch`)
|
||||
* If you try to use the **birth** time of a reference file (`man file`)
|
||||
* a program **died** due to a fatal signal (`man xargs`)
|
||||
* protocol version in the TLS **handshake** (`man curl`)
|
||||
* it will **look for** a debug object at… (`man valgrind`)
|
||||
|
||||
|
||||
|
||||
### data as food
|
||||
|
||||
* “Apparently some digital cameras get **indigestion** if you feed them a CF card) (`man mkfs`)
|
||||
* “Send packets using **raw** ethernet frames or IP packets” (`man nmap`)
|
||||
* “the above example can be thought of as a maximizing repeat that must **swallow** everything it can” (`man pcrepattern`)
|
||||
* “This will allow you to **feed** newline-delimited name=value pairs to the script on’ (`man CGI`)
|
||||
|
||||
|
||||
|
||||
### data as objects
|
||||
|
||||
* Kill the tmux server and clients and **destroy** all sessions (`tmux`)
|
||||
* Each command will produce one **block** of output on standard output. (`man tmux`)
|
||||
* “HTTPS guarantees that the password will not **travel** in the clear” (`man Net::SSLeay`)
|
||||
* “way to **pack** more than one certificate into an ASN.1 structure” (`man gpgsm`)
|
||||
|
||||
|
||||
|
||||
### processes as machines/objects
|
||||
|
||||
* “This is **fragile**, subject to change, and thus should not be relied upon” (`man ps`)
|
||||
* “This is useful if you have to use **broken** DNS” (`man aria2c`)
|
||||
* “This provides good safety measures, but **breaks down** when” (`man git-apply`)
|
||||
* “debugfs is a debugging tool. It has **rough edges**!” (`man debugfs`)
|
||||
|
||||
|
||||
|
||||
### containers
|
||||
|
||||
There are LOTS of containers: directories, files, strings, caches, queues, buffers, etc.
|
||||
|
||||
* can exploit that to **get out** of the chroot directory (`man chroot`)
|
||||
* “The file **containing** the RFC 4648 Section 5 base64url encoded 128-bit secret key”
|
||||
* “Keys must start with a lowercase character and **contain** only hyphens”
|
||||
* “just specify an **empty** string” (`man valgrind`)
|
||||
* “the cache is **full** and a new page that isn’t cached becomes visible” (`man zathurarc`)
|
||||
* “Number of table **overflows**” (`man lnstat`)
|
||||
* “likely **overflow** the buffer” (`man g++`)
|
||||
|
||||
|
||||
|
||||
### resources
|
||||
|
||||
There are also lots of kinds of resources: bandwidth, TCP sockets, session IDs, stack space, memory, disk space.
|
||||
|
||||
* This is not recommended and **wastes** bitrate (`man bitrate`)
|
||||
* corruption or **lost** data if the system crashes (`man btree`)
|
||||
* you don’t want Wget to **consume** the entire available bandwidth (`man wget`)
|
||||
* Larger values will be slower and cause x264 to **consume** more memory (`man mplayer`)
|
||||
* the resulting file can **consume** some disk space (`man socat`)
|
||||
* attempting to **reuse** SSL session-ID (`man curl`)
|
||||
* This option controls stack space **reuse** (`man gcc`)
|
||||
* Keep the TCP socket open between queries and **reuse** it rather than creating a new TCP socket (`man dig`)
|
||||
* the maximum value will easily **eat up** three extra gigabytes or so of memory (`man valgrind`)
|
||||
|
||||
|
||||
|
||||
### orientation (up, down, above, below)
|
||||
|
||||
* Send the escape character to the **frontend** (`man qemu-system`)
|
||||
* Note that TLS 1.3 is only supported by a subset of TLS **backends** (`man curl`)
|
||||
* This option may be useful if you are **behind** a router (`man mplayer`)
|
||||
* When a file that exists on the **lower** layer is renamed (`man rename`)
|
||||
* Several of the socket options should be handled at **lower** levels (`man getsockopt`)
|
||||
* while still performing such **higher** level functionality (`man nmap`)
|
||||
* This is the same string passed **back to** the front end (`man sudo_plugin`)
|
||||
* On Linux, `futimens` is a library function implemented **on top** of the `utimensat` system call (`man futimens`)
|
||||
|
||||
|
||||
|
||||
### buildings
|
||||
|
||||
Limits as rooms/buildings (which have floors, and ceilings, which you hit) are kind of fun:
|
||||
|
||||
* the kernel places a **floor** of 32 pages on this size limit (`man execve`)
|
||||
* This specifies a **ceiling** to which the process’s nice value can be raised (`man getrlimit`)
|
||||
* If this limit is **hit** the search is aborted (`man gcc`)
|
||||
* these libraries are used as the **foundation** for many of the libraries (`man Glib`)
|
||||
|
||||
|
||||
|
||||
### money / wealth
|
||||
|
||||
* This is a very **expensive** operation for large projects, so use it with caution (`man git-log`)
|
||||
* Note that since this operation is very I/O **expensive** (`man git-filter-branch`)
|
||||
* provides a **rich** interface for scripts to print disk layouts (`man fdisk`)
|
||||
* The number of times the softirq handler function terminated per second because its **budget** was consumed (`man sar.sysstat`)
|
||||
* the extra **cost** depends a lot on the application at hand (`man valgrind`)
|
||||
|
||||
|
||||
|
||||
### more miscellaneous metaphors
|
||||
|
||||
here are some more I found that didn’t fit into any of those categories yet.
|
||||
|
||||
* when a thread is created under glibc, just one **big** lock is used for all thread setup (`man valgrind`)
|
||||
* will likely **drop** the connection (`man x11vnc`)
|
||||
* on all **paths** from the load to the function entry (`man gcc`)
|
||||
* it is a very good idea to **wipe** filesystem signatures, data, etc. before (`man cryptsetup`)
|
||||
* they will be **embedded** into the document
|
||||
* the client should automatically **follow** referrals returned
|
||||
* even if there exist mappings that **cover** the whole address space requested (`man mremap`)
|
||||
* when a network interface **disappears** (`man systemd-resolve`)
|
||||
|
||||
|
||||
|
||||
### we’re all using metaphors all the time
|
||||
|
||||
I found a lot more metaphors than I expected, and most of them are just part of how I’d normally talk about a program. Interesting!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2020/05/08/metaphors-in-man-pages/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.youtube.com/watch?v=K8MF3aDg-bM&feature=youtu.be&t=14991
|
||||
[2]: https://www.goodreads.com/book/show/34459.Metaphors_We_Live_By
|
||||
[3]: https://metaphor.icsi.berkeley.edu/pub/en/index.php/Category:Metaphor
|
||||
236
sources/tech/20200617 What happens when you update your DNS.md
Normal file
236
sources/tech/20200617 What happens when you update your DNS.md
Normal file
@@ -0,0 +1,236 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (What happens when you update your DNS?)
|
||||
[#]: via: (https://jvns.ca/blog/how-updating-dns-works/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
What happens when you update your DNS?
|
||||
======
|
||||
|
||||
I’ve seen a lot of people get confused about updating their site’s DNS records to change the IP address. Why is it slow? Do you really have to wait 2 days for everything to update? Why do some people see the new IP and some people see the old IP? What’s happening?
|
||||
|
||||
So I wanted to write a quick exploration of what’s happening behind the scenes when you update a DNS record.
|
||||
|
||||
### how DNS works: recursive vs authoritative DNS servers
|
||||
|
||||
First, we need to explain a little bit about DNS. There are 2 kinds of DNS servers: **authoritative** and **recursive**.
|
||||
|
||||
**authoritative** DNS servers (also known as **nameservers**) have a database of IP addresses for each domain they’re responsible for. For example, right now an authoritative DNS server for github.com is ns-421.awsdns-52.com. You can ask it for github.com’s IP like this;
|
||||
|
||||
```
|
||||
dig @ns-421.awsdns-52.com github.com
|
||||
```
|
||||
|
||||
**recursive** DNS servers, by themselves, don’t know anything about who owns what IP address. They figure out the IP address for a domain by asking the right authoritative DNS servers, and then cache that IP address in case they’re asked again. 8.8.8.8 is a recursive DNS server.
|
||||
|
||||
When people visit your website, they’re probably making their DNS queries to a recursive DNS server. So, how do recursive DNS servers work? Let’s see!
|
||||
|
||||
### how does a recursive DNS server query for github.com?
|
||||
|
||||
Let’s go through an example of what a recursive DNS server (like 8.8.8.8) does when you ask it for an IP address (A record) for github.com. First – if it already has something cached, it’ll give you what it has cached. But what if all of its caches are expired? Here’s what happens:
|
||||
|
||||
**step 1**: it has IP addresses for the root DNS servers hardcoded in its source code. You can see this in [unbound’s source code here][1]. Let’s say it picks `198.41.0.4` to start with. Here’s the [official source][2] for those hardcoded IP addresses, also known as a “root hints file”.
|
||||
|
||||
**step 2**: Ask the root nameservers about `github.com`.
|
||||
|
||||
We can roughly reproduce what happens with `dig`. What this gives us is a new authoritative nameserver to ask: a nameserver for `.com`, with the IP `192.5.6.30`.
|
||||
|
||||
```
|
||||
$ dig @198.41.0.4 github.com
|
||||
...
|
||||
com. 172800 IN NS a.gtld-servers.net.
|
||||
...
|
||||
a.gtld-servers.net. 172800 IN A 192.5.6.30
|
||||
...
|
||||
```
|
||||
|
||||
The details of the DNS response are a little more complicated than that – in this case, there’s an authority section with some NS records and an additional section with A records so you don’t need to do an extra lookup to get the IP addresses of those nameservers.
|
||||
|
||||
(in practice, 99.99% of the time it’ll already have the address of the `.com` nameservers cached, but we’re pretending we’re really starting from scratch)
|
||||
|
||||
**step 3**: Ask the `.com` nameservers about `github.com`.
|
||||
|
||||
```
|
||||
$ dig @192.5.6.30 github.com
|
||||
...
|
||||
github.com. 172800 IN NS ns-421.awsdns-52.com.
|
||||
ns-421.awsdns-52.com. 172800 IN A 205.251.193.165
|
||||
...
|
||||
```
|
||||
|
||||
We have a new IP address to ask! This one is the nameserver for `github.com`.
|
||||
|
||||
**step 4**: Ask the `github.com` nameservers about `github.com`.
|
||||
|
||||
We’re almost done!
|
||||
|
||||
```
|
||||
$ dig @205.251.193.165 github.com
|
||||
|
||||
github.com. 60 IN A 140.82.112.4
|
||||
```
|
||||
|
||||
Hooray!! We have an `A` record for `github.com`! Now the recursive nameserver has `github.com`’s IP address and can return it back to you. And it could do all of this by only hardcoding a few IP addresses: the addresses of the root nameservers.
|
||||
|
||||
### how to see all of a recursive DNS server’s steps: `dig +trace`
|
||||
|
||||
When I want to see what a recursive DNS server would do when resolving a domain, I run
|
||||
|
||||
```
|
||||
$ dig @8.8.8.8 +trace github.com
|
||||
```
|
||||
|
||||
This shows all the DNS records that it requests, starting at the root DNS servers – all the 4 steps that we just went through.
|
||||
|
||||
### let’s update some DNS records!
|
||||
|
||||
Now that we know the basics of how DNS works, let’s update some DNS records and see what happens.
|
||||
|
||||
When you update your DNS records, there are two main options:
|
||||
|
||||
1. keep the same nameservers
|
||||
2. change nameservers
|
||||
|
||||
|
||||
|
||||
### let’s talk about TTLs
|
||||
|
||||
We’ve forgotten something important though! TTLs! You know how we said earlier that the recursive DNS server will cache records until they expire? The way it decides whether the record should expire is by looking at its **TTL** or “time to live”.
|
||||
|
||||
In this example, the TTL for the A record github’s nameserver returns for its DNS record is `60`, which means 60 seconds:
|
||||
|
||||
```
|
||||
$ dig @205.251.193.165 github.com
|
||||
|
||||
github.com. 60 IN A 140.82.112.4
|
||||
```
|
||||
|
||||
That’s a pretty short TTL, and _in theory_ if everybody’s DNS implementation followed the [DNS standard][3] it means that if Github decided to change the IP address for `github.com`, everyone should get the new IP address within 60 seconds. Let’s see how that plays out in practice
|
||||
|
||||
### option 1: update a DNS record on the same nameservers
|
||||
|
||||
First, I updated my nameservers (Cloudflare) to have a new DNS record: an A record that maps `test.jvns.ca` to `1.2.3.4`.
|
||||
|
||||
```
|
||||
$ dig @8.8.8.8 test.jvns.ca
|
||||
test.jvns.ca. 299 IN A 1.2.3.4
|
||||
```
|
||||
|
||||
This worked immediately! There was no need to wait at all, because there was no `test.jvns.ca` DNS record before that could have been cached. Great. But it looks like the new record is cached for ~5 minutes (299 seconds).
|
||||
|
||||
So, what if we try to change that IP? I changed it to `5.6.7.8`, and then ran the same DNS query.
|
||||
|
||||
```
|
||||
$ dig @8.8.8.8 test.jvns.ca
|
||||
test.jvns.ca. 144 IN A 1.2.3.4
|
||||
```
|
||||
|
||||
Hmm, it seems like that DNS server has the `1.2.3.4` record still cached for another 144 seconds. Interestingly, if I query `8.8.8.8` multiple times I actually get inconsistent results – sometimes it’ll give me the new IP and sometimes the old IP, I guess because 8.8.8.8 actually load balances to a bunch of different backends which each have their own cache.
|
||||
|
||||
After I waited 5 minutes, all of the `8.8.8.8` caches had updated and were always returning the new `5.6.7.8` record. Awesome. That was pretty fast!
|
||||
|
||||
### you can’t always rely on the TTL
|
||||
|
||||
As with most internet protocols, not everything obeys the DNS specification. Some ISP DNS servers will cache records for longer than the TTL specifies, like maybe for 2 days instead of 5 minutes. And people can always hardcode the old IP address in their /etc/hosts.
|
||||
|
||||
What I’d expect to happen in practice when updating a DNS record with a 5 minute TTL is that a large percentage of clients will move over to the new IPs quickly (like within 15 minutes), and then there will be a bunch of stragglers that slowly update over the next few days.
|
||||
|
||||
### option 2: updating your nameservers
|
||||
|
||||
So we’ve seen that when you update an IP address without changing your nameservers, a lot of DNS servers will pick up the new IP pretty quickly. Great. But what happens if you change your nameservers? Let’s try it!
|
||||
|
||||
I didn’t want to update the nameservers for my blog, so instead I went with a different domain I own and use in the examples for the [HTTP zine][4]: `examplecat.com`.
|
||||
|
||||
Previously, my nameservers were set to dns1.p01.nsone.net. I decided to switch them over to Google’s nameservers – `ns-cloud-b1.googledomains.com` etc.
|
||||
|
||||
When I made the change, my domain registrar somewhat ominiously popped up the message – “Changes to examplecat.com saved. They’ll take effect within the next 48 hours”. Then I set up a new A record for the domain, to make it point to `1.2.3.4`
|
||||
|
||||
Okay, let’s see if that did anything
|
||||
|
||||
```
|
||||
$ dig @8.8.8.8 examplecat.com
|
||||
examplecat.com. 17 IN A 104.248.50.87
|
||||
```
|
||||
|
||||
No change. If I ask a different DNS server, it knows the new IP:
|
||||
|
||||
```
|
||||
$ dig @1.1.1.1 examplecat.com
|
||||
examplecat.com. 299 IN A 1.2.3.4
|
||||
```
|
||||
|
||||
but 8.8.8.8 is still clueless. The reason 1.1.1.1 sees the new IP even though I just changed it 5 minutes ago is presumably that nobody had ever queried 1.1.1.1 about examplecat.com before, so it had nothing in its cache.
|
||||
|
||||
### nameserver TTLs are much longer
|
||||
|
||||
The reason that my registrar was saying “THIS WILL TAKE 48 HOURS” is that the TTLs on NS records (which are how recursive nameservers know which nameserver to ask) are MUCH longer!
|
||||
|
||||
The new nameserver is definitely returning the new IP address for `examplecat.com`
|
||||
|
||||
```
|
||||
$ dig @ns-cloud-b1.googledomains.com examplecat.com
|
||||
examplecat.com. 300 IN A 1.2.3.4
|
||||
```
|
||||
|
||||
But remember what happened when we queried for the `github.com` nameservers, way back?
|
||||
|
||||
```
|
||||
$ dig @192.5.6.30 github.com
|
||||
...
|
||||
github.com. 172800 IN NS ns-421.awsdns-52.com.
|
||||
ns-421.awsdns-52.com. 172800 IN A 205.251.193.165
|
||||
...
|
||||
```
|
||||
|
||||
172800 seconds is 48 hours! So nameserver updates will in general take a lot longer to expire from caches and propagate than just updating an IP address without changing your nameserver.
|
||||
|
||||
### how do your nameservers get updated?
|
||||
|
||||
When I update the nameservers for `examplecat.com`, what happens is that he `.com` nameserver gets a new `NS` record with the new domain. Like this:
|
||||
|
||||
```
|
||||
dig ns @j.gtld-servers.net examplecat.com
|
||||
|
||||
examplecat.com. 172800 IN NS ns-cloud-b1.googledomains.com
|
||||
```
|
||||
|
||||
But how does that new NS record get there? What happens is that I tell my **domain registrar** what I want the new nameservers to be by updating it on the website, and then my domain registrar tells the `.com` nameservers to make the update.
|
||||
|
||||
For `.com`, these updates happen pretty fast (within a few minutes), but I think for some other TLDs the TLD nameservers might not apply updates as quickly.
|
||||
|
||||
### your program’s DNS resolver library might also cache DNS records
|
||||
|
||||
One more reason TTLs might not be respected in practice: many programs need to resolve DNS names, and some programs will also cache DNS records indefinitely in memory (until the program is restarted).
|
||||
|
||||
For example, AWS has an article on [Setting the JVM TTL for DNS Name Lookups][5]. I haven’t written that much JVM code that does DNS lookups myself, but from a little Googling about the JVM and DNS it seems like you can configure the JVM so that it caches every DNS lookup indefinitely. (like [this elasticsearch issue][6])
|
||||
|
||||
### that’s all!
|
||||
|
||||
I hope this helps you understand what’s going on when updating your DNS!
|
||||
|
||||
As a disclaimer, again – TTLs definitely don’t tell the whole story about DNS propagation – some recursive DNS servers definitely don’t respect TTLs, even if the major ones like 8.8.8.8 do. So even if you’re just updating an A record with a short TTL, it’s very possible that in practice you’ll still get some requests to the old IP for a day or two.
|
||||
|
||||
Also, I changed the nameservers for `examplecat.com` back to their old values after publishing this post.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/how-updating-dns-works/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://github.com/NLnetLabs/unbound/blob/6e0756e819779d9cc2a14741b501cadffe446c93/iterator/iter_hints.c#L131
|
||||
[2]: https://www.iana.org/domains/root/files
|
||||
[3]: https://tools.ietf.org/html/rfc1035
|
||||
[4]: https://wizardzines.com/zines/http/
|
||||
[5]: https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/java-dg-jvm-ttl.html
|
||||
[6]: https://github.com/elastic/elasticsearch/issues/16412
|
||||
@@ -0,0 +1,115 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (A little bit of plain Javascript can do a lot)
|
||||
[#]: via: (https://jvns.ca/blog/2020/06/19/a-little-bit-of-plain-javascript-can-do-a-lot/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
A little bit of plain Javascript can do a lot
|
||||
======
|
||||
|
||||
I’ve never worked as a professional frontend developer, so even though I’ve been writing HTML/CSS/JS for 15 years for little side projects, all of the projects have been pretty small, sometimes I don’t write any Javascript for years in between, and I often don’t quite feel like I know what I’m doing.
|
||||
|
||||
Partly because of that, I’ve leaned on libraries a lot! Ten years ago I used to use jQuery, and since maybe 2017 I’ve been using a lot of vue.js for my little Javascript projects (you can see a [little whack-a-mole game I made here as an intro to Vue][1]).
|
||||
|
||||
But last week, for the first time in a while, I wrote some plain Javascript without a library and it was fun so I wanted to talk about it a bit!
|
||||
|
||||
### experimenting with just plain Javascript
|
||||
|
||||
I really like Vue. But last week when I started building <https://questions.wizardzines.com>, I had slightly different constraints than usual – I wanted to use the same HTML to generate both a PDF (with [Prince][2]) and to make an interactive version of the questions.
|
||||
|
||||
I couldn’t really see how that would work with Vue (because Vue wants to create all the HTML itself), and because it was a small project I decided to try writing it in plain Javascript with no libraries – just write some HTML/CSS and add a single `<script src="js/script.js"> </script>`.
|
||||
|
||||
I hadn’t done this in a while, and I learned a few things along the way that made it easier than I thought it would be when I started.
|
||||
|
||||
### do almost everything by adding & removing CSS classes
|
||||
|
||||
I decided to implement almost all of the UI by just adding & removing CSS classes, and using [CSS transitions][3] if I want to animate a transition.
|
||||
|
||||
here’s a small example, where clicking the “next” question button adds the “done” class to the parent div.
|
||||
|
||||
```
|
||||
div.querySelector('.next-question').onclick = function () {
|
||||
show_next_row();
|
||||
this.parentElement.parentElement.classList.add('done');
|
||||
}
|
||||
```
|
||||
|
||||
This worked pretty well. My CSS as always is a bit of a mess but it felt manageable.
|
||||
|
||||
### add/remove CSS classes with `.classList`
|
||||
|
||||
I started out by editing the classes like this: `x.className = 'new list of classes'`. That felt a bit messy though and I wondered if there was a better way. And there was!
|
||||
|
||||
You can also add CSS classes like this:
|
||||
|
||||
```
|
||||
let x = document.querySelector('div');
|
||||
x.classList.add('hi');
|
||||
x.classList.remove('hi');
|
||||
```
|
||||
|
||||
`element.classList.remove('hi')` is way cleaner than what I was doing before.
|
||||
|
||||
### find elements with `document.querySelectorAll`
|
||||
|
||||
When I started learning jQuery I remember thinking that if you wanted to easily find something in the DOM you had to use jQuery (like `$('.class')`). I just learned this week that you can actually write `document.querySelectorAll('.some-class')` instead, and then you don’t need to depend on any library!
|
||||
|
||||
I got curious about when `querySelectorAll` was introduced. I Googled a tiny bit and it looks like the [Selectors API was built sometime between 2008 and 2013 – I found a [post from the jQuery author discussing the proposed implementation in 2008][4], and [a blog post from 2011][5] saying it was in all major browsers by then, so maybe it didn’t exist when I started using jQuery but it’s definitely been around for quite a while :)
|
||||
|
||||
### set `.innerHTML`
|
||||
|
||||
In one place I wanted to change a button’s HTML contents. Creating DOM elements with `document.createElement` is pretty annoying, so I tried to do that as little as possible and instead set `.innerHTML` to the HTML string I wanted:
|
||||
|
||||
```
|
||||
button.innerHTML = `<i class="icon-lightbulb"></i>I learned something!
|
||||
<object data="/confetti.svg" width="30" height = "30"> </object>
|
||||
`;
|
||||
```
|
||||
|
||||
### scroll through the page with `.scrollIntoView`
|
||||
|
||||
The last fun thing I learned about is `.scrollIntoView` – I wanted to scroll down to the next question automatically when someone clicked “next question”. Turns out this is just one line of code:
|
||||
|
||||
```
|
||||
row.classList.add('revealed');
|
||||
row.scrollIntoView({behavior: 'smooth', block: 'center'});
|
||||
```
|
||||
|
||||
### another vanilla JS example: peekobot
|
||||
|
||||
Another small example of a plain JS library I thought was nice is [peekobot][6], which is a little chatbot interface that’s 100 lines of JS/CSS.
|
||||
|
||||
Looking at [its Javascript][7], it uses some similar patterns – a lot of `.classList.add`, some adding elements to the DOM, some `.querySelectorAll`.
|
||||
|
||||
I learned from reading peekobot’s source about [.closest][8] which finds the closest ancestor that matches a given selector. That seems like it would be a nice way to get rid of some of the `.parentElement.parentElement` that I was writing in my Javascript, which felt a bit fragile.
|
||||
|
||||
### plain Javascript can do a lot!
|
||||
|
||||
I was pretty surprised by how much I could get done with just plain JS. I ended up writing about 50 lines of JS to do everything I wanted to do, plus a bit extra to collect some anonymous metrics about what folks were learning.
|
||||
|
||||
As usual with my frontend posts, this isn’t meant to be Serious Frontend Engineering Advice – my goal is to be able to write little websites with less than 200 lines of Javascript that mostly work. If you are also flailing around in frontend land I hope this helps a bit!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2020/06/19/a-little-bit-of-plain-javascript-can-do-a-lot/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://jvns.ca/blog/2017/06/26/vue-js-fun/
|
||||
[2]: https://www.princexml.com/
|
||||
[3]: https://3dtransforms.desandro.com/card-flip
|
||||
[4]: https://johnresig.com/blog/thoughts-on-queryselectorall/
|
||||
[5]: https://tiffanybbrown.com/2011/08/12/meet-the-selectors-api/
|
||||
[6]: https://peekobot.github.io/peekobot/
|
||||
[7]: https://github.com/Peekobot/peekobot/blob/master/peekobot.js
|
||||
[8]: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
|
||||
@@ -1,160 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (MjSeven)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (An introduction to mutation testing in Python)
|
||||
[#]: via: (https://opensource.com/article/20/7/mutmut-python)
|
||||
[#]: author: (Moshe Zadka https://opensource.com/users/moshez)
|
||||
|
||||
An introduction to mutation testing in Python
|
||||
======
|
||||
Turn invisible bugs into visible fixes with mutation testing.
|
||||
![Searching for code][1]
|
||||
|
||||
You have tests for everything; maybe you even have a badge in your project repository stating 100% test coverage. But what are these tests helping you do? How do you know?
|
||||
|
||||
The _costs_ of unit tests are clear to developers. Tests have to be written. Occasionally they don't work as intended: there are false alarms or flapping tests that alternate success and failure without any code changes. The small bugs you can find through unit tests are valuable, but often they happen quietly on a developer machine and are fixed before a commit ever goes into version control. But the truly alarming bugs are mostly invisible. And the worst of all, the _missing alarms_ are completely invisible: you don't see the bugs you failed to catch until the code gets into a user's hands—and sometimes not even then.
|
||||
|
||||
There is one type of test that makes it possible to make the invisible visible: [mutation testing][2].
|
||||
|
||||
Mutation testing algorithmically modifies source code and checks if any "mutants" survived each test. Any mutant that survives the unit test is a problem: it means that a modification to the code, likely introducing a bug, was not caught by the standard test suite.
|
||||
|
||||
One framework for mutation testing in [Python][3] is `mutmut`.
|
||||
|
||||
Imagine you need to write code that calculates the angle between the hour hand and the minute hand in an analog clock to the nearest degree. The code might look something like:
|
||||
|
||||
|
||||
```
|
||||
def hours_hand(hour, minutes):
|
||||
base = (hour % 12 ) * (360 // 12)
|
||||
correction = int((minutes / 60) * (360 // 12))
|
||||
return base + correction
|
||||
|
||||
def minutes_hand(hour, minutes):
|
||||
return minutes * (360 // 60)
|
||||
|
||||
def between(hour, minutes):
|
||||
return abs(hours_hand(hour, minutes) - minutes_hand(hour, minutes))
|
||||
```
|
||||
|
||||
To begin, write a simple unit test:
|
||||
|
||||
|
||||
```
|
||||
import angle
|
||||
|
||||
def test_twelve():
|
||||
assert angle.between(12, 00) == 0
|
||||
```
|
||||
|
||||
Is this enough? The code has no `if` statement, so if you check coverage:
|
||||
|
||||
|
||||
```
|
||||
$ coverage run `which pytest`
|
||||
============================= test session starts ==============================
|
||||
platform linux -- Python 3.8.3, pytest-5.4.3, py-1.8.2, pluggy-0.13.1
|
||||
rootdir: /home/moshez/src/mut-mut-test
|
||||
collected 1 item
|
||||
|
||||
tests/test_angle.py . [100%]
|
||||
|
||||
============================== 1 passed in 0.01s ===============================
|
||||
```
|
||||
|
||||
Perfect! The tests pass, and coverage is at 100%. Testing expert, you are. But what does that coverage look like when you use mutation testing?
|
||||
|
||||
|
||||
```
|
||||
$ mutmut run --paths-to-mutate angle.py
|
||||
<snip>
|
||||
Legend for output:
|
||||
🎉 Killed mutants. The goal is for everything to end up in this bucket.
|
||||
⏰ Timeout. Test suite took 10 times as long as the baseline so were killed.
|
||||
🤔 Suspicious. Tests took a long time, but not long enough to be fatal.
|
||||
🙁 Survived. This means your tests needs to be expanded.
|
||||
🔇 Skipped. Skipped.
|
||||
<snip>
|
||||
⠋ 21/21 🎉 5 ⏰ 0 🤔 0 🙁 16 🔇 0
|
||||
```
|
||||
|
||||
Oh no. Out of 21 mutants, 16 survived. Only five cases passed the mutation testing. But what does that mean?
|
||||
|
||||
For each mutation test, `mutmut` modified portions of your source code that simulates potential bugs. An example of a modification is changing a `>` comparison to `>=` to see what happens. If there is no unit test for this boundary condition, this mutation will "survive": this is a potential bug that none of the tests will detect.
|
||||
|
||||
It's time to write better unit tests. It is easy to check which changes were made with `results`:
|
||||
|
||||
|
||||
```
|
||||
$ mutmut results
|
||||
<snip>
|
||||
Survived 🙁 (16)
|
||||
|
||||
\---- angle.py (16) ----
|
||||
|
||||
4-7, 9-14, 16-21
|
||||
$ mutmut apply 4
|
||||
$ git diff
|
||||
diff --git a/angle.py b/angle.py
|
||||
index b5dca41..3939353 100644
|
||||
\--- a/angle.py
|
||||
+++ b/angle.py
|
||||
@@ -1,6 +1,6 @@
|
||||
def hours_hand(hour, minutes):
|
||||
hour = hour % 12
|
||||
\- base = hour * (360 // 12)
|
||||
\+ base = hour / (360 // 12)
|
||||
correction = int((minutes / 60) * (360 // 12))
|
||||
return base + correction
|
||||
```
|
||||
|
||||
This is a typical example of a mutation `mutmut` performs; it analyzes the source code and changes operators to different operators: addition to subtraction or, in this case, multiplication to division. Unit tests, generally speaking, should catch bugs when an operator changes; otherwise, they are not testing the behavior effectively. Following this logic, `mutmut` twiddles through source code to double-check your tests.
|
||||
|
||||
You can use `mutmut apply` to apply a failed mutant. Wow, it turns out you barely checked whether the `hour` parameter was used correctly. Fix that:
|
||||
|
||||
|
||||
```
|
||||
$ git diff
|
||||
diff --git a/tests/test_angle.py b/tests/test_angle.py
|
||||
index f51d43a..1a2e4df 100644
|
||||
\--- a/tests/test_angle.py
|
||||
+++ b/tests/test_angle.py
|
||||
@@ -2,3 +2,6 @@ import angle
|
||||
|
||||
def test_twelve():
|
||||
assert angle.between(12, 00) == 0
|
||||
+
|
||||
+def test_three():
|
||||
\+ assert angle.between(3, 00) == 90
|
||||
```
|
||||
|
||||
Previously, you tested only for 12. Will adding a test for three be enough to improve?
|
||||
|
||||
|
||||
```
|
||||
$ mutmut run --paths-to-mutate angle.py
|
||||
<snip>
|
||||
⠋ 21/21 🎉 7 ⏰ 0 🤔 0 🙁 14 🔇 0
|
||||
```
|
||||
|
||||
This new test managed to kill two of the mutants—better than before, but still a long way to go. I won't work through each of the 14 cases left to fix, because I think the pattern is clear. (Can you get them down to zero?)
|
||||
|
||||
Mutation testing is another tool, along with coverage measurement, that allows you to see how comprehensive your test suite is. Using it makes the case that tests need to be improved: any one of those surviving mutants is a mistake a human being can make while fat-fingering code, as well as a potential bug creeping into your program. Keep testing and happy hunting.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/7/mutmut-python
|
||||
|
||||
作者:[Moshe Zadka][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/moshez
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/search_find_code_python_programming.png?itok=ynSL8XRV (Searching for code)
|
||||
[2]: https://opensource.com/article/19/8/mutation-testing-evolution-tdd
|
||||
[3]: https://opensource.com/resources/python
|
||||
@@ -1,472 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Use your favorite programming language to provision Infrastructure as Code)
|
||||
[#]: via: (https://opensource.com/article/20/8/infrastructure-as-code-pulumi)
|
||||
[#]: author: (Lee Briggs https://opensource.com/users/lbriggs)
|
||||
|
||||
Use your favorite programming language to provision Infrastructure as Code
|
||||
======
|
||||
Provision everything you need to get your infrastructure off the ground
|
||||
with Node.js or another programming language.
|
||||
![Puzzle pieces coming together to form a computer screen][1]
|
||||
|
||||
As you navigate the world of IT and technology, there are some terms you come across repeatedly. Some of them are hard to quantify and may take on different meanings as time goes on. ["DevOps"][2] is an example of a word that seems (to me) to change depending on the person using it; the original DevOps pioneers might not even recognize what we call DevOps today.
|
||||
|
||||
If you're a software developer, "Infrastructure as Code" (IaC) may be one of those terms. IaC is using the same software-development practices you'd use to write user-facing features to declare the infrastructure that applications run on. This often means using tools like [Git][3] or [Mercurial][4] for version control and Puppet, Chef, or Ansible for [configuration management][5]. At the infrastructure-provisioning layer, the most common technology is CloudFormation (for AWS specifically) or [Terraform][6] as an open source alternative for creating hybrid-cloud resources for your applications to run on.
|
||||
|
||||
There are great options in the configuration-management space to write IaC as either configuration files or preferred programming languages, but this choice is not well-known in the infrastructure-provisioning space.
|
||||
|
||||
[Pulumi][7] offers an option to use standard programming languages to define infrastructure. It supports an array of languages, including [JavaScript][8], [TypeScript][9], [Go][10], [Python][11] and [C#][12]. Much like Terraform, Pulumi has first-class support for many familiar cloud providers, like [AWS][13], [Azure][14], [Google Cloud][15], and [other providers][16].
|
||||
|
||||
In this article, I'll show you how to use Pulumi to write infrastructure in Node.js.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
First, make sure you're ready to use Pulumi. Pulumi supports all major operating systems, so the methods you use to install its prerequisites depend on the operating system you're using.
|
||||
|
||||
First, install the interpreter for your preferred programming language. I'll be using TypeScript, so I need to install the `node` binary. Consult Node's [installation instructions][17] for information about your operating system. You can use [Homebrew][18] on [Mac][19] or [Linux][20] to install:
|
||||
|
||||
|
||||
```
|
||||
`brew install node`
|
||||
```
|
||||
|
||||
On Linux, you can alternately use your usual package manager, such as **apt** or **dnf**:
|
||||
|
||||
|
||||
```
|
||||
`$ sudo dnf install nodejs`
|
||||
```
|
||||
|
||||
In either case, the result should be that the `node` binary is available in your `$PATH`. To confirm it's accessible, run:
|
||||
|
||||
|
||||
```
|
||||
`node --version`
|
||||
```
|
||||
|
||||
Next, install the Pulumi command-line interface (CLI). You can find operating system-specific [installation instructions][21] in Pulumi's docs. With `brew` on a Mac or Linux:
|
||||
|
||||
|
||||
```
|
||||
`brew install pulumi`
|
||||
```
|
||||
|
||||
Alternately, you can use the install script. First download it and review it, and then execute it:
|
||||
|
||||
|
||||
```
|
||||
$ curl -fsSL --output pulumi_installer.sh \
|
||||
<https://get.pulumi.com/>
|
||||
$ more pulumi_installer.sh
|
||||
$ sh ./pulumi_installer.sh
|
||||
```
|
||||
|
||||
Again, the desired result is to have the `pulumi` binary available in your path. Check the version to make sure you're ready to proceed:
|
||||
|
||||
|
||||
```
|
||||
pulumi version
|
||||
v2.5.0
|
||||
```
|
||||
|
||||
### Configure Pulumi
|
||||
|
||||
Before you start provisioning any infrastructure, give Pulumi somewhere to store its [state][22].
|
||||
|
||||
Pulumi stores its state in a backend. The default backend is Pulumi's software-as-a-service (which has a free plan for individual users), but for this example, use the alternative file backend. The file backend will create a file on your local filesystem to store the state with:
|
||||
|
||||
|
||||
```
|
||||
`pulumi login --local`
|
||||
```
|
||||
|
||||
If you're planning on sharing this project with someone else, the file backend might not be a good starting point. Pulumi can also store its state in a cloud object store like AWS S3. To use it, create an S3 bucket and log in:
|
||||
|
||||
|
||||
```
|
||||
`pulumi login --cloud-url s3://my-pulumi-state-bucket`
|
||||
```
|
||||
|
||||
Now that you've logged into a state backend, you can create a project and a stack!
|
||||
|
||||
Before you start creating a Pulumi project, get to know the following Pulumi terminology, which you'll see in this tutorial.
|
||||
|
||||
#### Project
|
||||
|
||||
A [project][23] is a directory that contains a Pulumi.yaml file. This file contains metadata Pulumi needs to know to do its thing. Example fields you'll find in a Pulumi.yaml file are:
|
||||
|
||||
* The runtime (e.g., Python, Node, Go, .Net)
|
||||
* A description of the project (e.g., "my first Pulumi project")
|
||||
* A name for the project
|
||||
|
||||
|
||||
|
||||
A project is a loosely defined concept that can fit your needs. Generally, a project contains a bunch of _resources_, which are things you want to provision and control. You might choose to have small Pulumi projects with very few resources or large projects that contain all the resources you need. As you become more familiar with Pulumi, it'll become more apparent how you want to lay out your projects.
|
||||
|
||||
#### Stack
|
||||
|
||||
A Pulumi [stack][24] allows you to differentiate your Pulumi projects depending on configurable values. A common use is to deploy a project to different environments like development or production or different regions like Europe, the Middle East and Africa, and the US.
|
||||
|
||||
When getting started, you're not likely to need a complex stack setup, so this walkthrough uses the default stack name, `dev`.
|
||||
|
||||
### Use TypeScript for IaC
|
||||
|
||||
You can bootstrap a Pulumi project using the handy `pulumi new` command. The `new` command has a whole host of flags and options that should help you get started with Pulumi, so go ahead and create your first project:
|
||||
|
||||
|
||||
```
|
||||
$ pulumi new typescript
|
||||
This command will walk you through creating a new Pulumi project.
|
||||
|
||||
Enter a value or leave blank to accept the (default), and press <ENTER>.
|
||||
Press ^C at any time to quit.
|
||||
|
||||
project name: (pulumi) my-first-project
|
||||
project description: (A minimal TypeScript Pulumi program) My very first Pulumi program
|
||||
Created project 'my-first-project'
|
||||
|
||||
Please enter your desired stack name.
|
||||
To create a stack in an organization, use the format <org-name>/<stack-name> (e.g. `acmecorp/dev`).
|
||||
stack name: (dev) dev
|
||||
Created stack 'dev'
|
||||
|
||||
Installing dependencies...
|
||||
|
||||
> node scripts/postinstall
|
||||
|
||||
added 82 packages from 126 contributors and audited 82 packages in 2.84s
|
||||
|
||||
13 packages are looking for funding
|
||||
run `npm fund` for details
|
||||
|
||||
found 0 vulnerabilities
|
||||
|
||||
Finished installing dependencies
|
||||
|
||||
Your new project is ready to go! ✨
|
||||
|
||||
To perform an initial deployment, run 'pulumi up'
|
||||
```
|
||||
|
||||
A lot happened here, so I'll break it down:
|
||||
|
||||
The first part identifies a template for your Pulumi project. I chose the generic `typescript` option, but there are [many options available][25].
|
||||
|
||||
This `new` command grabbed the template from your templates repository and copied this file locally, including the runtime dependencies (in this case, `package.json`).
|
||||
|
||||
The `new` command took care of installing those dependencies by running `npm install` inside this directory. Then `npm install` downloaded and installed everything needed to run your Pulumi program, which, in this case, is very straightforward: the `@pulumi/pulumi` NPM package.
|
||||
|
||||
You're ready to create your very first resource!
|
||||
|
||||
### Create your first cloud resource
|
||||
|
||||
A resource is a thing that is managed by your infrastructure-provisioning software lifecycle. Resources are generally a cloud provider object, like an S3 bucket. Pulumi providers handle Pulumi resources, and providers are specific to the cloud provider they manage. Pulumi has around [40 providers][26] you can use, but for your first resource, use one of the simplest—the [random provider][27].
|
||||
|
||||
The random provider does what the name suggests: it idempotently creates a random resource (which could be a string, for example) and stores it in the Pulumi state.
|
||||
|
||||
Add this as a dependency to your Pulumi project using npm:
|
||||
|
||||
|
||||
```
|
||||
`npm install @pulumi/random`
|
||||
```
|
||||
|
||||
The npm package manager downloads and installs the random provider package and installs it for you. Now you're ready to write your Pulumi program.
|
||||
|
||||
When you generated your project earlier, Pulumi's bootstrap process created an `index.ts` TypeScript file. Open it in your favorite integrated development environment (IDE) and add your first resource:
|
||||
|
||||
|
||||
```
|
||||
import * as pulumi from "@pulumi/pulumi";
|
||||
import * as random from "@pulumi/random";
|
||||
|
||||
const password = new random.RandomString(`password`, {
|
||||
length: 10
|
||||
})
|
||||
```
|
||||
|
||||
If you're at all familiar with TypeScript or JavaScript, this will look very familiar because it's written in a programming language you know. This also applies if you're using one of Pulumi's other supported languages. Here's that same random resource from before, but this time in Python:
|
||||
|
||||
|
||||
```
|
||||
import pulumi_random as random
|
||||
|
||||
password = random.RandomString("password", length=10)
|
||||
```
|
||||
|
||||
Pulumi projects currently support only a single language, but each project can reference other projects written in other languages—a useful trick for members of the polyglot team.
|
||||
|
||||
You've written your first Pulumi resource. Now you need to deploy it.
|
||||
|
||||
Leave your editor and head back to the command line. From your project directory, run `pulumi up` and watch the magic happen:
|
||||
|
||||
|
||||
```
|
||||
pulumi up
|
||||
|
||||
Previewing update (dev):
|
||||
Type Name Plan
|
||||
+ pulumi:pulumi:Stack my-first-project-dev create
|
||||
+ └─ random:index:RandomString password create
|
||||
|
||||
Resources:
|
||||
+ 2 to create
|
||||
|
||||
Do you want to perform this update? yes
|
||||
Updating (dev):
|
||||
Type Name Status
|
||||
+ pulumi:pulumi:Stack my-first-project-dev created
|
||||
+ └─ random:index:RandomString password created
|
||||
|
||||
Resources:
|
||||
+ 2 created
|
||||
|
||||
Duration: 2s
|
||||
|
||||
Permalink: file:///Users/lbriggs/.pulumi/stacks/dev.json
|
||||
```
|
||||
|
||||
Excellent, you have your first Pulumi resource! While you might be enjoying this sense of achievement, unfortunately, this random resource isn't that useful—it's just a random string, and you can't even see what it is. Address that part first: Modify your earlier program and add `export` to the constant you created:
|
||||
|
||||
|
||||
```
|
||||
import * as pulumi from "@pulumi/pulumi";
|
||||
import * as random from "@pulumi/random";
|
||||
|
||||
export const password = new random.RandomString(`password`, {
|
||||
length: 10
|
||||
})
|
||||
```
|
||||
|
||||
Rerun `pulumi up` and look at the output:
|
||||
|
||||
|
||||
```
|
||||
pulumi up
|
||||
Previewing update (dev):
|
||||
Type Name Plan
|
||||
pulumi:pulumi:Stack my-first-project-dev
|
||||
|
||||
Outputs:
|
||||
+ password: {
|
||||
+ id : "&+r?{}J$J7"
|
||||
+ keepers : output<string>
|
||||
+ length : 10
|
||||
+ lower : true
|
||||
+ minLower : 0
|
||||
+ minNumeric : 0
|
||||
+ minSpecial : 0
|
||||
+ minUpper : 0
|
||||
+ number : true
|
||||
+ overrideSpecial: output<string>
|
||||
+ result : "&+r?{}J$J7"
|
||||
+ special : true
|
||||
+ upper : true
|
||||
+ urn : "urn:pulumi:dev::my-first-project::random:index/randomString:RandomString::password"
|
||||
}
|
||||
|
||||
Resources:
|
||||
2 unchanged
|
||||
|
||||
Do you want to perform this update? yes
|
||||
Updating (dev):
|
||||
Type Name Status
|
||||
pulumi:pulumi:Stack my-first-project-dev
|
||||
|
||||
Outputs:
|
||||
+ password: {
|
||||
+ id : "&+r?{}J$J7"
|
||||
+ length : 10
|
||||
+ lower : true
|
||||
+ minLower : 0
|
||||
+ minNumeric: 0
|
||||
+ minSpecial: 0
|
||||
+ minUpper : 0
|
||||
+ number : true
|
||||
+ result : "&+r?{}J$J7"
|
||||
+ special : true
|
||||
+ upper : true
|
||||
+ urn : "urn:pulumi:dev::my-first-project::random:index/randomString:RandomString::password"
|
||||
}
|
||||
|
||||
Resources:
|
||||
2 unchanged
|
||||
|
||||
Duration: 1s
|
||||
Permalink: file:///Users/lbriggs/.pulumi/stacks/dev.json
|
||||
```
|
||||
|
||||
Now you can see a randomly generated string under the `result` section of the `Outputs`. The resource you created has a number of properties that you can see now.
|
||||
|
||||
This is all well and good, but if you want to enjoy IaC, you're going to have to provision something other than a random string. Give it a try!
|
||||
|
||||
### Deploy a container
|
||||
|
||||
So far, you've bootstrapped your Pulumi experience by installing dependencies and registered a simple random resource. Now deploy some actual infrastructure, albeit to your local machine.
|
||||
|
||||
First, add the `@pulumi/docker` provider to your stack. Use your chosen package manager to add it to the project:
|
||||
|
||||
|
||||
```
|
||||
`npm install @pulumi/docker`
|
||||
```
|
||||
|
||||
You've pulled down the Pulumi Docker provider package from npm, which means you can now create Docker images in your project.
|
||||
|
||||
If you don't have Docker installed on your machine, now is an excellent time to get it. Instructions will depend on your operating system, so take a look at [Docker's installation page][28] for information.
|
||||
|
||||
Open up your favorite IDE again and run a Docker container. Modify your `index.ts` file from earlier to make it look like this:
|
||||
|
||||
|
||||
```
|
||||
import * as pulumi from "@pulumi/pulumi";
|
||||
import * as random from "@pulumi/random";
|
||||
import * as docker from "@pulumi/docker";
|
||||
|
||||
const password = new random.RandomString(`password`, {
|
||||
length: 10
|
||||
})
|
||||
|
||||
const container = new docker.Container(`my-password`, {
|
||||
image: 'hashicorp/http-echo',
|
||||
command: [ pulumi.interpolate`-text=Your super secret password is: ${password.result}` ],
|
||||
ports: [{
|
||||
internal: 5678,
|
||||
external: 5678,
|
||||
}]
|
||||
})
|
||||
|
||||
export const id = container.id
|
||||
```
|
||||
|
||||
This creates a container that creates a web server. The output of the web server is your randomly generated string, in this case, a password. Run this and see what happens:
|
||||
|
||||
|
||||
```
|
||||
pulumi up
|
||||
|
||||
Previewing update (dev):
|
||||
Type Name Plan
|
||||
pulumi:pulumi:Stack my-first-project-dev
|
||||
+ └─ docker:index:Container my-password create
|
||||
|
||||
Outputs:
|
||||
+ id : output<string>
|
||||
~ password: {
|
||||
id : "&+r?{}J$J7"
|
||||
length : 10
|
||||
lower : true
|
||||
minLower : 0
|
||||
minNumeric: 0
|
||||
minSpecial: 0
|
||||
minUpper : 0
|
||||
number : true
|
||||
result : "&+r?{}J$J7"
|
||||
special : true
|
||||
upper : true
|
||||
urn : "urn:pulumi:dev::my-first-project::random:index/randomString:RandomString::password"
|
||||
}
|
||||
|
||||
Resources:
|
||||
+ 1 to create
|
||||
2 unchanged
|
||||
|
||||
Do you want to perform this update? yes
|
||||
Updating (dev):
|
||||
Type Name Status
|
||||
pulumi:pulumi:Stack my-first-project-dev
|
||||
+ └─ docker:index:Container my-password created
|
||||
|
||||
Outputs:
|
||||
+ id : "e73b34aeca34a64b72b61b0b9b8438637ce28853937bc359a1528ca99f49ddda"
|
||||
password: {
|
||||
id : "&+r?{}J$J7"
|
||||
length : 10
|
||||
lower : true
|
||||
minLower : 0
|
||||
minNumeric: 0
|
||||
minSpecial: 0
|
||||
minUpper : 0
|
||||
number : true
|
||||
result : "&+r?{}J$J7"
|
||||
special : true
|
||||
upper : true
|
||||
urn : "urn:pulumi:dev::my-first-project::random:index/randomString:RandomString::password"
|
||||
}
|
||||
|
||||
Resources:
|
||||
+ 1 created
|
||||
2 unchanged
|
||||
|
||||
Duration: 2s
|
||||
Permalink: file:///Users/lbriggs/.pulumi/stacks/dev.json
|
||||
```
|
||||
|
||||
You'll notice in the `Outputs` section that the values you're outputting have changed; it's just a Docker container ID. Check whether your very simple password generator works:
|
||||
|
||||
|
||||
```
|
||||
curl <http://localhost:5678>
|
||||
Your super secret password is: &+r?{}J$J7
|
||||
```
|
||||
|
||||
It does! You just provisioned your first piece of infrastructure with TypeScript!
|
||||
|
||||
#### A quick note on Pulumi outputs
|
||||
|
||||
You'll notice in the code that creates the Docker container that it uses a special `pulumi.interpolate` call. If you're familiar with TypeScript, you might be curious why that's needed (as it's Pulumi-specific). There's an interesting reason.
|
||||
|
||||
When Pulumi creates a resource, there are values that Pulumi doesn't know until the program executes. In Pulumi, these are called `Outputs`. These `Outputs` can be seen in the code above; for example, in your first random resource, you used the `export` keyword to output the random resource's properties, and you also exported the container ID of the container you created.
|
||||
|
||||
Because Pulumi doesn't know the value of these `Outputs` until execution time, it needs special helpers to use them when manipulating strings. If you want to know more about this special programming model, watch [this short video][29].
|
||||
|
||||
### Wrapping up
|
||||
|
||||
IaC has evolved in many ways as complexity has arisen in hybrid-cloud infrastructures. In the infrastructure-provisioning space, Pulumi is a great choice for using your favorite programming language to provision everything you need to get your infrastructure off the ground, then you can tag in your favorite configuration management tooling to take the next steps.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/8/infrastructure-as-code-pulumi
|
||||
|
||||
作者:[Lee Briggs][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/lbriggs
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/puzzle_computer_solve_fix_tool.png?itok=U0pH1uwj (Puzzle pieces coming together to form a computer screen)
|
||||
[2]: https://opensource.com/resources/devops
|
||||
[3]: https://git-scm.com/
|
||||
[4]: https://www.mercurial-scm.org/
|
||||
[5]: https://opensource.com/article/18/12/configuration-management-tools
|
||||
[6]: https://opensource.com/article/20/7/terraform-kubernetes
|
||||
[7]: https://www.pulumi.com/
|
||||
[8]: https://developer.mozilla.org/en-US/docs/Web/JavaScript
|
||||
[9]: https://www.typescriptlang.org/
|
||||
[10]: https://golang.org/
|
||||
[11]: https://www.python.org/
|
||||
[12]: https://en.wikipedia.org/wiki/C_Sharp_(programming_language)
|
||||
[13]: https://www.pulumi.com/docs/intro/cloud-providers/aws/
|
||||
[14]: https://www.pulumi.com/docs/intro/cloud-providers/azure/
|
||||
[15]: https://www.pulumi.com/docs/intro/cloud-providers/gcp/
|
||||
[16]: https://www.pulumi.com/docs/reference/pkg/
|
||||
[17]: https://nodejs.org/en/download/
|
||||
[18]: https://brew.sh/
|
||||
[19]: https://opensource.com/article/20/6/homebrew-mac
|
||||
[20]: https://opensource.com/article/20/6/homebrew-linux
|
||||
[21]: https://www.pulumi.com/docs/get-started/install/
|
||||
[22]: https://www.pulumi.com/docs/intro/concepts/state/
|
||||
[23]: https://www.pulumi.com/docs/intro/concepts/project/
|
||||
[24]: https://www.pulumi.com/docs/intro/concepts/stack/
|
||||
[25]: https://github.com/pulumi/templates
|
||||
[26]: https://www.pulumi.com/docs/intro/cloud-providers/
|
||||
[27]: https://www.pulumi.com/docs/intro/cloud-providers/random/
|
||||
[28]: https://docs.docker.com/get-docker/
|
||||
[29]: https://www.youtube.com/watch?v=lybOxul2otM
|
||||
@@ -1,682 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (robsean)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Add throwing mechanics to your Python game)
|
||||
[#]: via: (https://opensource.com/article/20/9/add-throwing-python-game)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
Add throwing mechanics to your Python game
|
||||
======
|
||||
Running around avoiding enemies is one thing. Fighting back is another.
|
||||
Learn how in the 12th article in this series on creating a platformer in
|
||||
Pygame.
|
||||
![Gaming on a grid with penguin pawns][1]
|
||||
|
||||
This is part 12 in an ongoing series about creating video games in [Python 3][2] using the [Pygame][3] module. Previous articles are:
|
||||
|
||||
1. [Learn how to program in Python by building a simple dice game][4]
|
||||
2. [Build a game framework with Python using the Pygame module][5]
|
||||
3. [How to add a player to your Python game][6]
|
||||
4. [Using Pygame to move your game character around][7]
|
||||
5. [What's a hero without a villain? How to add one to your Python game][8]
|
||||
6. [Put platforms in a Python game with Pygame][9]
|
||||
7. [Simulate gravity in your Python game][10]
|
||||
8. [Add jumping to your Python platformer game][11]
|
||||
9. [Enable your Python game player to run forward and backward][12]
|
||||
10. [Put some loot in your Python platformer game][13]
|
||||
11. [Add scorekeeping to your Python game][14]
|
||||
|
||||
|
||||
|
||||
My previous article was meant to be the final article in this series, and it encouraged you to go program your own additions to this game. Many of you did! I got emails asking for help with a common mechanic that I hadn't yet covered: combat. After all, jumping to avoid baddies is one thing, but sometimes it's awfully satisfying to just make them go away. It's common in video games to throw something at your enemies, whether it's a ball of fire, an arrow, a bolt of lightning, or whatever else fits the game.
|
||||
|
||||
Unlike anything you have programmed for your platformer game in this series so far, throwable items have a _time to live_. Once you throw an object, it's expected to travel some distance and then disappear. If it's an arrow or something like that, it may disappear when it passes the edge of the screen. If it's a fireball or a bolt of lightning, it might fizzle out after some amount of time.
|
||||
|
||||
That means each time a throwable item is spawned, a unique measure of its lifespan must also be spawned. To introduce this concept, this article demonstrates how to throw only one item at a time. (In other words, only one throwable item may exist at a time.) On the one hand, this is a game limitation, but on the other hand, it is a game mechanic in itself. Your player won't be able to throw 50 fireballs at once, since you only allow one at a time, so it becomes a challenge for your player to time when they release a fireball to try to hit an enemy. And behind the scenes, this also keeps your code simple.
|
||||
|
||||
If you want to enable more throwable items at once, challenge yourself after you finish this tutorial by building on the knowledge you gain.
|
||||
|
||||
### Create the throwable class
|
||||
|
||||
If you followed along with the other articles in this series, you should be familiar with the basic `__init__` function when spawning a new object on the screen. It's the same function you used for spawning your [player][6] and your [enemies][8]. Here's an `__init__` function to spawn a throwable object:
|
||||
|
||||
|
||||
```
|
||||
class Throwable(pygame.sprite.Sprite):
|
||||
"""
|
||||
Spawn a throwable object
|
||||
"""
|
||||
def __init__(self, x, y, img, throw):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.image = pygame.image.load(os.path.join('images',img))
|
||||
self.image.convert_alpha()
|
||||
self.image.set_colorkey(ALPHA)
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.x = x
|
||||
self.rect.y = y
|
||||
self.firing = throw
|
||||
```
|
||||
|
||||
The primary difference in this function compared to your `Player` class or `Enemy` class `__init__` function is that it has a `self.firing` variable. This variable keeps track of whether or not a throwable object is currently alive on screen, so it stands to reason that when a throwable object is created, the variable is set to `1`.
|
||||
|
||||
### Measure time to live
|
||||
|
||||
Next, just as with `Player` and `Enemy`, you need an `update` function so that the throwable object moves on its own once it's thrown into the air toward an enemy.
|
||||
|
||||
The easiest way to determine the lifespan of a throwable object is to detect when it goes off-screen. Which screen edge you need to monitor depends on the physics of your throwable object.
|
||||
|
||||
* If your player is throwing something that travels quickly along the horizontal axis, like a crossbow bolt or arrow or a very fast magical force, then you want to monitor the horizontal limit of your game screen. This is defined by `worldx`.
|
||||
* If your player is throwing something that travels vertically or both horizontally and vertically, then you must monitor the vertical limit of your game screen. This is defined by `worldy`.
|
||||
|
||||
|
||||
|
||||
This example assumes your throwable object goes a little forward and eventually falls to the ground. The object does not bounce off the ground, though, and continues to fall off the screen. You can try different settings to see what fits your game best:
|
||||
|
||||
|
||||
```
|
||||
def update(self,worldy):
|
||||
'''
|
||||
throw physics
|
||||
'''
|
||||
if self.rect.y < worldy: #vertical axis
|
||||
self.rect.x += 15 #how fast it moves forward
|
||||
self.rect.y += 5 #how fast it falls
|
||||
else:
|
||||
self.kill() #remove throwable object
|
||||
self.firing = 0 #free up firing slot
|
||||
```
|
||||
|
||||
To make your throwable object move faster, increase the momentum of the `self.rect` values.
|
||||
|
||||
If the throwable object is off-screen, then the object is destroyed, freeing up the RAM that it had occupied. In addition, `self.firing` is set back to `0` to allow your player to take another shot.
|
||||
|
||||
### Set up your throwable object
|
||||
|
||||
Just like with your player and enemies, you must create a sprite group in your setup section to hold the throwable object.
|
||||
|
||||
Additionally, you must create an inactive throwable object to start the game with. If there isn't a throwable object when the game starts, the first time a player attempts to throw a weapon, it will fail.
|
||||
|
||||
This example assumes your player starts with a fireball as a weapon, so each instance of a throwable object is designated by the `fire` variable. In later levels, as the player acquires new skills, you could introduce a new variable using a different image but leveraging the same `Throwable` class.
|
||||
|
||||
In this block of code, the first two lines are already in your code, so don't retype them:
|
||||
|
||||
|
||||
```
|
||||
player_list = pygame.sprite.Group() #context
|
||||
player_list.add(player) #context
|
||||
fire = Throwable(player.rect.x,player.rect.y,'fire.png',0)
|
||||
firepower = pygame.sprite.Group()
|
||||
```
|
||||
|
||||
Notice that a throwable item starts at the same location as the player. That makes it look like the throwable item is coming from the player. The first time the fireball is generated, a `0` is used so that `self.firing` shows as available.
|
||||
|
||||
### Get throwing in the main loop
|
||||
|
||||
Code that doesn't appear in the main loop will not be used in the game, so you need to add a few things in your main loop to get your throwable object into your game world.
|
||||
|
||||
First, add player controls. Currently, you have no firepower trigger. There are two states for a key on a keyboard: the key can be down, or the key can be up. For movement, you use both: pressing down starts the player moving, and releasing the key (the key is up) stops the player. Firing needs only one signal. It's a matter of taste as to which key event (a key press or a key release) you use to trigger your throwable object.
|
||||
|
||||
In this code block, the first two lines are for context:
|
||||
|
||||
|
||||
```
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
player.jump(platform_list)
|
||||
if event.key == pygame.K_SPACE:
|
||||
if not fire.firing:
|
||||
fire = Throwable(player.rect.x,player.rect.y,'fire.png',1)
|
||||
firepower.add(fire)
|
||||
```
|
||||
|
||||
Unlike the fireball you created in your setup section, you use a `1` to set `self.firing` as unavailable.
|
||||
|
||||
Finally, you must update and draw your throwable object. The order of this matters, so put this code between your existing `enemy.move` and `player_list.draw` lines:
|
||||
|
||||
|
||||
```
|
||||
enemy.move() # context
|
||||
|
||||
if fire.firing:
|
||||
fire.update(worldy)
|
||||
firepower.draw(world)
|
||||
player_list.draw(screen) # context
|
||||
enemy_list.draw(screen) # context
|
||||
```
|
||||
|
||||
Notice that these updates are performed only if the `self.firing` variable is set to 1. If it is set to 0, then `fire.firing` is not true, and the updates are skipped. If you tried to do these updates, no matter what, your game would crash because there wouldn't be a `fire` object to update or draw.
|
||||
|
||||
Launch your game and try to throw your weapon.
|
||||
|
||||
### Detect collisions
|
||||
|
||||
If you played your game with the new throwing mechanic, you probably noticed that you can throw objects, but it doesn't have any effect on your foes.
|
||||
|
||||
The reason is that your enemies do not check for a collision. An enemy can be hit by your throwable object and never know about it.
|
||||
|
||||
You've already done collision detection in your `Player` class, and this is very similar. In your `Enemy` class, add a new `update` function:
|
||||
|
||||
|
||||
```
|
||||
def update(self,firepower, enemy_list):
|
||||
"""
|
||||
detect firepower collision
|
||||
"""
|
||||
fire_hit_list = pygame.sprite.spritecollide(self,firepower,False)
|
||||
for fire in fire_hit_list:
|
||||
enemy_list.remove(self)
|
||||
```
|
||||
|
||||
The code is simple. Each enemy object checks to see if it has been hit by the `firepower` sprite group. If it has, then the enemy is removed from the enemy group and disappears.
|
||||
|
||||
To integrate that function into your game, call the function in your new firing block in the main loop:
|
||||
|
||||
|
||||
```
|
||||
if fire.firing: # context
|
||||
fire.update(worldy) # context
|
||||
firepower.draw(screen) # context
|
||||
enemy_list.update(firepower,enemy_list) # update enemy
|
||||
```
|
||||
|
||||
You can try your game now, and most everything works as expected. There's still one problem, though, and that's the direction of the throw.
|
||||
|
||||
### Change the throw mechanic direction
|
||||
|
||||
Currently, your hero's fireball moves only to the right. This is because the `update` function of the `Throwable` class adds pixels to the position of the fireball, and in Pygame, a larger number on the X-axis means movement toward the right of the screen. When your hero turns the other way, you probably want it to throw its fireball to the left.
|
||||
|
||||
By this point, you know how to implement this, at least technically. However, the easiest solution uses a variable in what may be a new way for you. Generically, you can "set a flag" (sometimes also termed "flip a bit") to indicate the direction your hero is facing. Once you do that, you can check that variable to learn whether the fireball needs to move left or right.
|
||||
|
||||
First, create a new variable in your `Player` class to represent which direction your hero is facing. Because my hero faces right naturally, I treat that as the default:
|
||||
|
||||
|
||||
```
|
||||
self.score = 0
|
||||
self.facing_right = True # add this
|
||||
self.is_jumping = True
|
||||
```
|
||||
|
||||
When this variable is `True`, your hero sprite is facing right. It must be set anew every time the player changes the hero's direction, so do that in your main loop on the relevant `keyup` events:
|
||||
|
||||
|
||||
```
|
||||
if event.type == pygame.KEYUP:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(steps, 0)
|
||||
player.facing_right = False # add this line
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(-steps, 0)
|
||||
player.facing_right = True # add this line
|
||||
```
|
||||
|
||||
Finally, change the `update` function of your `Throwable` class to check whether the hero is facing right or not and to add or subtract pixels from the fireball's position as appropriate:
|
||||
|
||||
|
||||
```
|
||||
if self.rect.y < worldy:
|
||||
if player.facing_right:
|
||||
self.rect.x += 15
|
||||
else:
|
||||
self.rect.x -= 15
|
||||
self.rect.y += 5
|
||||
```
|
||||
|
||||
Try your game again and clear your world of some baddies.
|
||||
|
||||
![Python platformer with throwing capability][15]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][16])
|
||||
|
||||
As a bonus challenge, try incrementing your player's score whenever an enemy is vanquished.
|
||||
|
||||
### The complete code
|
||||
|
||||
|
||||
```
|
||||
#!/usr/bin/env python3
|
||||
# by Seth Kenlon
|
||||
|
||||
# GPLv3
|
||||
# This program is free software: you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <[http://www.gnu.org/licenses/\>][17].
|
||||
|
||||
import pygame
|
||||
import pygame.freetype
|
||||
import sys
|
||||
import os
|
||||
|
||||
'''
|
||||
Variables
|
||||
'''
|
||||
|
||||
worldx = 960
|
||||
worldy = 720
|
||||
fps = 40
|
||||
ani = 4
|
||||
world = pygame.display.set_mode([worldx, worldy])
|
||||
forwardx = 600
|
||||
backwardx = 120
|
||||
|
||||
BLUE = (80, 80, 155)
|
||||
BLACK = (23, 23, 23)
|
||||
WHITE = (254, 254, 254)
|
||||
ALPHA = (0, 255, 0)
|
||||
|
||||
tx = 64
|
||||
ty = 64
|
||||
|
||||
font_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "fonts", "amazdoom.ttf")
|
||||
font_size = tx
|
||||
pygame.freetype.init()
|
||||
myfont = pygame.freetype.Font(font_path, font_size)
|
||||
|
||||
'''
|
||||
Objects
|
||||
'''
|
||||
|
||||
def stats(score, health):
|
||||
myfont.render_to(world, (4, 4), "Score:"+str(score), BLUE, None, size=64)
|
||||
myfont.render_to(world, (4, 72), "Health:"+str(health), BLUE, None, size=64)
|
||||
|
||||
class Throwable(pygame.sprite.Sprite):
|
||||
"""
|
||||
Spawn a throwable object
|
||||
"""
|
||||
def __init__(self, x, y, img, throw):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.image = pygame.image.load(os.path.join('images', img))
|
||||
self.image.convert_alpha()
|
||||
self.image.set_colorkey(ALPHA)
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.x = x
|
||||
self.rect.y = y
|
||||
self.firing = throw
|
||||
|
||||
def update(self, worldy):
|
||||
'''
|
||||
throw physics
|
||||
'''
|
||||
if self.rect.y < worldy:
|
||||
if player.facing_right:
|
||||
self.rect.x += 15
|
||||
else:
|
||||
self.rect.x -= 15
|
||||
self.rect.y += 5
|
||||
else:
|
||||
self.kill()
|
||||
self.firing = 0
|
||||
|
||||
# x location, y location, img width, img height, img file
|
||||
class Platform(pygame.sprite.Sprite):
|
||||
def __init__(self, xloc, yloc, imgw, imgh, img):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.image = pygame.image.load(os.path.join('images', img)).convert()
|
||||
self.image.convert_alpha()
|
||||
self.image.set_colorkey(ALPHA)
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.y = yloc
|
||||
self.rect.x = xloc
|
||||
|
||||
class Player(pygame.sprite.Sprite):
|
||||
"""
|
||||
Spawn a player
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.movex = 0
|
||||
self.movey = 0
|
||||
self.frame = 0
|
||||
self.health = 10
|
||||
self.damage = 0
|
||||
self.score = 0
|
||||
self.facing_right = True
|
||||
self.is_jumping = True
|
||||
self.is_falling = True
|
||||
self.images = []
|
||||
for i in range(1, 5):
|
||||
img = pygame.image.load(os.path.join('images', 'walk' + str(i) + '.png')).convert()
|
||||
img.convert_alpha()
|
||||
img.set_colorkey(ALPHA)
|
||||
self.images.append(img)
|
||||
self.image = self.images[0]
|
||||
self.rect = self.image.get_rect()
|
||||
|
||||
def gravity(self):
|
||||
if self.is_jumping:
|
||||
self.movey += 3.2
|
||||
|
||||
def control(self, x, y):
|
||||
"""
|
||||
control player movement
|
||||
"""
|
||||
self.movex += x
|
||||
|
||||
def jump(self):
|
||||
if self.is_jumping is False:
|
||||
self.is_falling = False
|
||||
self.is_jumping = True
|
||||
|
||||
def update(self):
|
||||
"""
|
||||
Update sprite position
|
||||
"""
|
||||
|
||||
# moving left
|
||||
if self.movex < 0:
|
||||
self.is_jumping = True
|
||||
self.frame += 1
|
||||
if self.frame > 3 * ani:
|
||||
self.frame = 0
|
||||
self.image = pygame.transform.flip(self.images[self.frame // ani], True, False)
|
||||
|
||||
# moving right
|
||||
if self.movex > 0:
|
||||
self.is_jumping = True
|
||||
self.frame += 1
|
||||
if self.frame > 3 * ani:
|
||||
self.frame = 0
|
||||
self.image = self.images[self.frame // ani]
|
||||
|
||||
# collisions
|
||||
enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
|
||||
if self.damage == 0:
|
||||
for enemy in enemy_hit_list:
|
||||
if not self.rect.contains(enemy):
|
||||
self.damage = self.rect.colliderect(enemy)
|
||||
if self.damage == 1:
|
||||
idx = self.rect.collidelist(enemy_hit_list)
|
||||
if idx == -1:
|
||||
self.damage = 0 # set damage back to 0
|
||||
self.health -= 1 # subtract 1 hp
|
||||
|
||||
ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
|
||||
for g in ground_hit_list:
|
||||
self.movey = 0
|
||||
self.rect.bottom = g.rect.top
|
||||
self.is_jumping = False # stop jumping
|
||||
|
||||
# fall off the world
|
||||
if self.rect.y > worldy:
|
||||
self.health -=1
|
||||
print(self.health)
|
||||
self.rect.x = tx
|
||||
self.rect.y = ty
|
||||
|
||||
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
|
||||
for p in plat_hit_list:
|
||||
self.is_jumping = False # stop jumping
|
||||
self.movey = 0
|
||||
if self.rect.bottom <= p.rect.bottom:
|
||||
self.rect.bottom = p.rect.top
|
||||
else:
|
||||
self.movey += 3.2
|
||||
|
||||
if self.is_jumping and self.is_falling is False:
|
||||
self.is_falling = True
|
||||
self.movey -= 33 # how high to jump
|
||||
|
||||
loot_hit_list = pygame.sprite.spritecollide(self, loot_list, False)
|
||||
for loot in loot_hit_list:
|
||||
loot_list.remove(loot)
|
||||
self.score += 1
|
||||
print(self.score)
|
||||
|
||||
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
|
||||
|
||||
self.rect.x += self.movex
|
||||
self.rect.y += self.movey
|
||||
|
||||
class Enemy(pygame.sprite.Sprite):
|
||||
"""
|
||||
Spawn an enemy
|
||||
"""
|
||||
|
||||
def __init__(self, x, y, img):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.image = pygame.image.load(os.path.join('images', img))
|
||||
self.image.convert_alpha()
|
||||
self.image.set_colorkey(ALPHA)
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.x = x
|
||||
self.rect.y = y
|
||||
self.counter = 0
|
||||
|
||||
def move(self):
|
||||
"""
|
||||
enemy movement
|
||||
"""
|
||||
distance = 80
|
||||
speed = 8
|
||||
|
||||
if self.counter >= 0 and self.counter <= distance:
|
||||
self.rect.x += speed
|
||||
elif self.counter >= distance and self.counter <= distance * 2:
|
||||
self.rect.x -= speed
|
||||
else:
|
||||
self.counter = 0
|
||||
|
||||
self.counter += 1
|
||||
|
||||
def update(self, firepower, enemy_list):
|
||||
"""
|
||||
detect firepower collision
|
||||
"""
|
||||
fire_hit_list = pygame.sprite.spritecollide(self, firepower, False)
|
||||
for fire in fire_hit_list:
|
||||
enemy_list.remove(self)
|
||||
|
||||
class Level:
|
||||
def ground(lvl, gloc, tx, ty):
|
||||
ground_list = pygame.sprite.Group()
|
||||
i = 0
|
||||
if lvl == 1:
|
||||
while i < len(gloc):
|
||||
ground = Platform(gloc[i], worldy - ty, tx, ty, 'tile-ground.png')
|
||||
ground_list.add(ground)
|
||||
i = i + 1
|
||||
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl))
|
||||
|
||||
return ground_list
|
||||
|
||||
def bad(lvl, eloc):
|
||||
if lvl == 1:
|
||||
enemy = Enemy(eloc[0], eloc[1], 'enemy.png')
|
||||
enemy_list = pygame.sprite.Group()
|
||||
enemy_list.add(enemy)
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl))
|
||||
|
||||
return enemy_list
|
||||
|
||||
# x location, y location, img width, img height, img file
|
||||
def platform(lvl, tx, ty):
|
||||
plat_list = pygame.sprite.Group()
|
||||
ploc = []
|
||||
i = 0
|
||||
if lvl == 1:
|
||||
ploc.append((200, worldy - ty - 128, 3))
|
||||
ploc.append((300, worldy - ty - 256, 3))
|
||||
ploc.append((550, worldy - ty - 128, 4))
|
||||
while i < len(ploc):
|
||||
j = 0
|
||||
while j <= ploc[i][2]:
|
||||
plat = Platform((ploc[i][0] + (j * tx)), ploc[i][1], tx, ty, 'tile.png')
|
||||
plat_list.add(plat)
|
||||
j = j + 1
|
||||
print('run' + str(i) + str(ploc[i]))
|
||||
i = i + 1
|
||||
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl))
|
||||
|
||||
return plat_list
|
||||
|
||||
def loot(lvl):
|
||||
if lvl == 1:
|
||||
loot_list = pygame.sprite.Group()
|
||||
loot = Platform(tx*5, ty*5, tx, ty, 'loot_1.png')
|
||||
loot_list.add(loot)
|
||||
|
||||
if lvl == 2:
|
||||
print(lvl)
|
||||
|
||||
return loot_list
|
||||
|
||||
'''
|
||||
Setup
|
||||
'''
|
||||
|
||||
backdrop = pygame.image.load(os.path.join('images', 'stage.png'))
|
||||
clock = pygame.time.Clock()
|
||||
pygame.init()
|
||||
backdropbox = world.get_rect()
|
||||
main = True
|
||||
|
||||
player = Player() # spawn player
|
||||
player.rect.x = 0 # go to x
|
||||
player.rect.y = 30 # go to y
|
||||
player_list = pygame.sprite.Group()
|
||||
player_list.add(player)
|
||||
steps = 10
|
||||
fire = Throwable(player.rect.x, player.rect.y, 'fire.png', 0)
|
||||
firepower = pygame.sprite.Group()
|
||||
|
||||
eloc = []
|
||||
eloc = [300, worldy-ty-80]
|
||||
enemy_list = Level.bad(1, eloc)
|
||||
gloc = []
|
||||
|
||||
i = 0
|
||||
while i <= (worldx / tx) + tx:
|
||||
gloc.append(i * tx)
|
||||
i = i + 1
|
||||
|
||||
ground_list = Level.ground(1, gloc, tx, ty)
|
||||
plat_list = Level.platform(1, tx, ty)
|
||||
enemy_list = Level.bad( 1, eloc )
|
||||
loot_list = Level.loot(1)
|
||||
|
||||
'''
|
||||
Main Loop
|
||||
'''
|
||||
|
||||
while main:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit()
|
||||
try:
|
||||
sys.exit()
|
||||
finally:
|
||||
main = False
|
||||
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == ord('q'):
|
||||
pygame.quit()
|
||||
try:
|
||||
sys.exit()
|
||||
finally:
|
||||
main = False
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(-steps, 0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(steps, 0)
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
player.jump()
|
||||
|
||||
if event.type == pygame.KEYUP:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(steps, 0)
|
||||
player.facing_right = False
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(-steps, 0)
|
||||
player.facing_right = True
|
||||
if event.key == pygame.K_SPACE:
|
||||
if not fire.firing:
|
||||
fire = Throwable(player.rect.x, player.rect.y, 'fire.png', 1)
|
||||
firepower.add(fire)
|
||||
|
||||
# scroll the world forward
|
||||
if player.rect.x >= forwardx:
|
||||
scroll = player.rect.x - forwardx
|
||||
player.rect.x = forwardx
|
||||
for p in plat_list:
|
||||
p.rect.x -= scroll
|
||||
for e in enemy_list:
|
||||
e.rect.x -= scroll
|
||||
for l in loot_list:
|
||||
l.rect.x -= scroll
|
||||
|
||||
# scroll the world backward
|
||||
if player.rect.x <= backwardx:
|
||||
scroll = backwardx - player.rect.x
|
||||
player.rect.x = backwardx
|
||||
for p in plat_list:
|
||||
p.rect.x += scroll
|
||||
for e in enemy_list:
|
||||
e.rect.x += scroll
|
||||
for l in loot_list:
|
||||
l.rect.x += scroll
|
||||
|
||||
world.blit(backdrop, backdropbox)
|
||||
player.update()
|
||||
player.gravity()
|
||||
player_list.draw(world)
|
||||
if fire.firing:
|
||||
fire.update(worldy)
|
||||
firepower.draw(world)
|
||||
enemy_list.draw(world)
|
||||
enemy_list.update(firepower, enemy_list)
|
||||
loot_list.draw(world)
|
||||
ground_list.draw(world)
|
||||
plat_list.draw(world)
|
||||
for e in enemy_list:
|
||||
e.move()
|
||||
stats(player.score, player.health)
|
||||
pygame.display.flip()
|
||||
clock.tick(fps)
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/9/add-throwing-python-game
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/game_pawn_grid_linux.png?itok=4gERzRkg (Gaming on a grid with penguin pawns)
|
||||
[2]: https://www.python.org/
|
||||
[3]: https://www.pygame.org/news
|
||||
[4]: https://opensource.com/article/17/10/python-101
|
||||
[5]: https://opensource.com/article/17/12/game-framework-python
|
||||
[6]: https://opensource.com/article/17/12/game-python-add-a-player
|
||||
[7]: https://opensource.com/article/17/12/game-python-moving-player
|
||||
[8]: https://opensource.com/article/18/5/pygame-enemy
|
||||
[9]: https://opensource.com/article/18/7/put-platforms-python-game
|
||||
[10]: https://opensource.com/article/19/11/simulate-gravity-python
|
||||
[11]: https://opensource.com/article/19/12/jumping-python-platformer-game
|
||||
[12]: https://opensource.com/article/19/12/python-platformer-game-run
|
||||
[13]: https://opensource.com/article/19/12/loot-python-platformer-game
|
||||
[14]: https://opensource.com/article/20/1/add-scorekeeping-your-python-game
|
||||
[15]: https://opensource.com/sites/default/files/uploads/pygame-throw.jpg (Python platformer with throwing capability)
|
||||
[16]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[17]: http://www.gnu.org/licenses/\>
|
||||
@@ -1,151 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (robsean)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Easily set image transparency using GIMP)
|
||||
[#]: via: (https://opensource.com/article/20/9/chroma-key-gimp)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
Easily set image transparency using GIMP
|
||||
======
|
||||
Use chroma key or "green screen" techniques to set transparencies on
|
||||
your video-game graphics.
|
||||
![Gaming with penguin pawns][1]
|
||||
|
||||
Whether you're programming a game or an app with [Python][2] or [Lua][3], you're probably using PNG graphics for your game assets. An advantage of the PNG format, which is not available in a JPEG, is the ability to store an **alpha channel**. Alpha is, essentially, the "color" of invisibility or transparency. Alpha is the part of an image you _don't_ see. For example, if you were to draw a doughnut, the doughnut hole would be filled with alpha, and you could see whatever was behind it.
|
||||
|
||||
A common problem is how to find the alpha part of an image. Sometimes, your programming framework, whether it's [Python Arcade][4], [Pygame][5], LÖVE, or anything else, detects the alpha channel and treats it (after the appropriate function calls) as transparency. That means it renders no new pixels where there's alpha, leaving that doughnut hole empty. It's 100% transparent or 0% opaque and functionally "invisible."
|
||||
|
||||
Other times, your framework and your graphic asset don't agree on where the alpha channel is located (or that an alpha channel exists at all), and you get pixels where you wanted transparency.
|
||||
|
||||
This article describes the most sure-fire way I know to work around that.
|
||||
|
||||
### Chroma key
|
||||
|
||||
In computer graphics, there are a few values that contribute to how a pixel is rendered. **Chrominance**, or **chroma**, describes the saturation or intensity of a pixel. The **chroma key** technique (also known as **green screening**) was originally developed as a chemical process, in which a specific color (blue at first and later green) was deliberately obscured by a **matte** during the copying of a film negative, allowing another image to be substituted where there once was a blue or green screen. That's a simplified explanation, but it demonstrates the origins of what is known as the alpha channel in computer graphics.
|
||||
|
||||
An alpha channel is information saved in a graphic to identify pixels that are meant to be transparent. RGB graphics, for example, have red, green, and blue channels. RGBA graphics contain red, green, blue, and alpha. The value of alpha can range from 0 to 1, with decimal points being valid entries.
|
||||
|
||||
Because an alpha channel can be expressed in several different ways, relying on an embedded alpha channel can be problematic. Instead, you can pick a color and turn it into an alpha value of 0 in your game framework. For that to work, you must know the colors in your graphic.
|
||||
|
||||
### Prepare your graphic
|
||||
|
||||
To prepare a graphic with an explicit color reserved exclusively for a chroma key, open the graphic in your favorite graphic editor. I recommend [GIMP][6] or [Glimpse][7], but [mtPaint][8] or [Pinta][9] or even [Inkscape][10] can work just as well, depending on the nature of your graphics and your ability to translate these instructions to a different tool.
|
||||
|
||||
Start by opening this graphic of Tux the penguin:
|
||||
|
||||
![Tux the penguin][11]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][12])
|
||||
|
||||
### Select the graphic
|
||||
|
||||
Once the graphic is open, go to the **Windows** menu and select **Dockable Dialogs** and then **Layers**. Right-click on Tux's layer in the **Layer** palette. From the pop-up menu, select **Alpha to Selection**. If your image does not have a built-in alpha channel, then you must create your own selection manually.
|
||||
|
||||
![Alpha to selection][13]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][12])
|
||||
|
||||
To create a selection manually, click the **Paths** tool from the toolbox.
|
||||
|
||||
![GIMP Paths tool][14]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][12])
|
||||
|
||||
Using the **Paths** tool, move your mouse around the graphic, clicking and releasing (do not drag) at each major intersection of its outline. Don't worry about following curves; just find the major intersections and corners. This creates a node at each point, with a straight line drawn between them. You don't need to close your path, so when you reach the final intersection before the one where you started, you're done.
|
||||
|
||||
![Create a path in GIMP][15]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][12])
|
||||
|
||||
Once you've created your outline path, go to the **Windows** menu and select **Dockable Dialogs** and then **Tool Options**. In the **Tool Options** panel, select **Edit (Ctrl)**. With this activated, you can edit the paths you've just drawn by clicking the lines or nodes and adjusting them to fit your graphic better. You can even give the lines curves.
|
||||
|
||||
![Edit path][16]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][12])
|
||||
|
||||
Now select the **Paths** panel from the **Windows > Dockable Dialogs** menu. In the **Paths** panel, click the **Path to Selection** button. Your graphic is now selected.
|
||||
|
||||
### Grow the selection
|
||||
|
||||
If you feel your selection is too tight, you can give yourself a little slack by growing the selection. I sometimes do this when I want to impose or thicken a border around a graphic.
|
||||
|
||||
To grow a selection, click the **Select** menu and choose **Grow**. Enter a pixel value and click **OK**.
|
||||
|
||||
### Invert the selection
|
||||
|
||||
You have your graphic selected, but what you actually want to select is everything _except_ your graphic. That's because you're creating an alpha matte to define what in your graphic will be replaced by something else. In other words, you need to mark the pixels that will be turned invisible.
|
||||
|
||||
To invert the selection, click on the **Select** menu and choose **Invert**. Now everything except your graphic is selected.
|
||||
|
||||
### Fill with alpha
|
||||
|
||||
With everything except your graphic selected, choose the color you want to use to designate your alpha matte. The most common color is green (as you might guess from the term "green screen"). There's nothing magical about the color green or even a particular shade of green. It's used because humans, frequent subjects of graphic manipulation, contain no green pigment, so it's easy to key out green without accidentally keying out part of the central subject. Of course, if your graphic is a green alien or an emerald or something that _does_ contain green, you should use a different color. You can use any color you want, as long as it's solid and consistent. If you're doing this to many graphics, your choice should be consistent across all graphics.
|
||||
|
||||
![Foreground color in toolbox][17]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][12])
|
||||
|
||||
Set your foreground color with the color value you've chosen. To ensure that your choice is exact, use the [HTML][18] or [HSV][19] representation of the color. For example, if you're using pure green, it can be expressed in GIMP (and most open source graphic applications) as `00ff00` (that's 00 red, FF green, and 00 blue, with F being the maximum amount).
|
||||
|
||||
![Setting color values][20]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][12])
|
||||
|
||||
Whatever color you choose, make sure you take note of the HTML or HSV values so you use the exact same color for every graphic.
|
||||
|
||||
To fill in your alpha matte, click the **Edit** menu and choose **Fill with FG Color**.
|
||||
|
||||
### Flatten and export
|
||||
|
||||
If you've left a border around your graphic, set your background color to the color you want to use as the border stroke. This is usually either black or white, but it can be anything that suits your game's aesthetic.
|
||||
|
||||
Once you have set the background color, click on the **Image** menu and select **Flatten Image**. It's safe to do this whether or not you added a border. This process removes the alpha channel from your image, filling in any "transparent" pixels with the background color.
|
||||
|
||||
![Flattening image][21]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][12])
|
||||
|
||||
You now have an image ready for your game engine. Export the image to whatever format your game engine prefers, and then import it into your game using whatever function calls it requires. In your code, set the alpha value to `00ff00` (or whatever color you used), and then use the game engine's graphic transforms to treat that color as an alpha channel.
|
||||
|
||||
### Other methods
|
||||
|
||||
This isn't the only way to get transparency in your game graphics. Check your game engine's documentation to find out how it tries to process alpha channels by default, and when you're not certain, try letting your game engine auto-detect transparency in your graphic before you go about editing it. Sometimes, your game engine's expectations and your graphic's preset values happen to match, and you get transparency without having to do any extra work.
|
||||
|
||||
When that fails, though, try a little chroma key. It's worked for the film industry for nearly 100 years, and it can work for you too.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/9/chroma-key-gimp
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/gaming_grid_penguin.png?itok=7Fv83mHR (Gaming with penguin pawns)
|
||||
[2]: https://opensource.com/article/17/10/python-101
|
||||
[3]: https://opensource.com/article/17/4/how-program-games-raspberry-pi
|
||||
[4]: https://opensource.com/article/18/4/easy-2d-game-creation-python-and-arcade
|
||||
[5]: https://opensource.com/article/17/12/game-framework-python
|
||||
[6]: http://gimp.org
|
||||
[7]: https://glimpse-editor.github.io
|
||||
[8]: https://opensource.com/article/17/2/mtpaint-pixel-art-animated-gifs
|
||||
[9]: https://www.pinta-project.com/
|
||||
[10]: http://inkscape.org
|
||||
[11]: https://opensource.com/sites/default/files/uploads/tux.png (Tux the penguin)
|
||||
[12]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[13]: https://opensource.com/sites/default/files/uploads/gimp_alpha-to-selection.jpg (Alpha to selection)
|
||||
[14]: https://opensource.com/sites/default/files/uploads/gimp_path-tool.jpg (GIMP Paths tool)
|
||||
[15]: https://opensource.com/sites/default/files/uploads/gimp_path-create.jpg (Create a path in GIMP)
|
||||
[16]: https://opensource.com/sites/default/files/uploads/gimp_path-edit.jpg (Edit path)
|
||||
[17]: https://opensource.com/sites/default/files/uploads/gimp_foreground-colour.jpg (Foreground color in toolbox)
|
||||
[18]: https://www.w3schools.com/colors/colors_picker.asp
|
||||
[19]: https://en.wikipedia.org/wiki/HSL_and_HSV
|
||||
[20]: https://opensource.com/sites/default/files/uploads/gimp_colour.jpg (Setting color values)
|
||||
[21]: https://opensource.com/sites/default/files/uploads/gimp_matte.jpg (Flattening image)
|
||||
@@ -1,171 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Secure NTP with NTS)
|
||||
[#]: via: (https://fedoramagazine.org/secure-ntp-with-nts/)
|
||||
[#]: author: (Miroslav Lichvar https://fedoramagazine.org/author/mlichvar/)
|
||||
|
||||
Secure NTP with NTS
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
Many computers use the Network Time Protocol (NTP) to synchronize their system clocks over the internet. NTP is one of the few unsecured internet protocols still in common use. An attacker that can observe network traffic between a client and server can feed the client with bogus data and, depending on the client’s implementation and configuration, force it to set its system clock to any time and date. Some programs and services might not work if the client’s system clock is not accurate. For example, a web browser will not work correctly if the web servers’ certificates appear to be expired according to the client’s system clock. Use Network Time Security (NTS) to secure NTP.
|
||||
|
||||
Fedora 33[1][2] is the first Fedora release to support NTS. NTS is a new authentication mechanism for NTP. It enables clients to verify that the packets they receive from the server have not been modified while in transit. The only thing an attacker can do when NTS is enabled is drop or delay packets. See [RFC8915][3] for further details about NTS.
|
||||
|
||||
NTP can be secured well with symmetric keys. Unfortunately, the server has to have a different key for each client and the keys have to be securely distributed. That might be practical with a private server on a local network, but it does not scale to a public server with millions of clients.
|
||||
|
||||
NTS includes a Key Establishment (NTS-KE) protocol that automatically creates the encryption keys used between the server and its clients. It uses Transport Layer Security (TLS) on TCP port 4460. It is designed to scale to very large numbers of clients with a minimal impact on accuracy. The server does not need to keep any client-specific state. It provides clients with cookies, which are encrypted and contain the keys needed to authenticate the NTP packets. Privacy is one of the goals of NTS. The client gets a new cookie with each server response, so it doesn’t have to reuse cookies. This prevents passive observers from tracking clients migrating between networks.
|
||||
|
||||
The default NTP client in Fedora is _chrony_. Chrony added NTS support in version 4.0. The default configuration hasn’t changed. Chrony still uses public servers from the [pool.ntp.org][4] project and NTS is not enabled by default.
|
||||
|
||||
Currently, there are very few public NTP servers that support NTS. The two major providers are Cloudflare and Netnod. The [Cloudflare servers][5] are in various places around the world. They use anycast addresses that should allow most clients to reach a close server. The [Netnod servers][6] are located in Sweden. In the future we will probably see more public NTP servers with NTS support.
|
||||
|
||||
A general recommendation for configuring NTP clients for best reliability is to have at least three working servers. For best accuracy, it is recommended to select close servers to minimize network latency and asymmetry caused by asymmetric network routing. If you are not concerned about fine-grained accuracy, you can ignore this recommendation and use any NTS servers you trust, no matter where they are located.
|
||||
|
||||
If you do want high accuracy, but you don’t have a close NTS server, you can mix distant NTS servers with closer non-NTS servers. However, such a configuration is less secure than a configuration using NTS servers only. The attackers still cannot force the client to accept arbitrary time, but they do have a greater control over the client’s clock and its estimate of accuracy, which may be unacceptable in some environments.
|
||||
|
||||
### Enable client NTS in the installer
|
||||
|
||||
When installing Fedora 33, you can enable NTS in the _Time & Date_ dialog in the _Network Time_ configuration. Enter the name of the server and check the NTS support before clicking the **+** (Add) button. You can add one or more servers or pools with NTS. To remove the default pool of servers (_2.fedora.pool.ntp.org_), uncheck the corresponding mark in the _Use_ column.
|
||||
|
||||
![Network Time configuration in Fedora installer][7]
|
||||
|
||||
### Enable client NTS in the configuration file
|
||||
|
||||
If you upgraded from a previous Fedora release, or you didn’t enable NTS in the installer, you can enable NTS directly in _/etc/chrony.conf_. Specify the server with the _nts_ option in addition to the recommended _iburst_ option. For example:
|
||||
|
||||
```
|
||||
server time.cloudflare.com iburst nts
|
||||
server nts.sth1.ntp.se iburst nts
|
||||
server nts.sth2.ntp.se iburst nts
|
||||
```
|
||||
|
||||
You should also allow the client to save the NTS keys and cookies to disk, so it doesn’t have to repeat the NTS-KE session on each start. Add the following line to _chrony.conf_, if it is not already present:
|
||||
|
||||
```
|
||||
ntsdumpdir /var/lib/chrony
|
||||
```
|
||||
|
||||
If you don’t want NTP servers provided by DHCP to be mixed with the servers you have specified, remove or comment out the following line in _chrony.conf_:
|
||||
|
||||
```
|
||||
sourcedir /run/chrony-dhcp
|
||||
```
|
||||
|
||||
After you have finished editing _chrony.conf_, save your changes and restart the _chronyd_ service:
|
||||
|
||||
```
|
||||
systemctl restart chronyd
|
||||
```
|
||||
|
||||
### Check client status
|
||||
|
||||
Run the following command under the root user to check whether the NTS key establishment was successful:
|
||||
|
||||
```
|
||||
# chronyc -N authdata
|
||||
Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
|
||||
=========================================================================
|
||||
time.cloudflare.com NTS 1 15 256 33m 0 0 8 100
|
||||
nts.sth1.ntp.se NTS 1 15 256 33m 0 0 8 100
|
||||
nts.sth2.ntp.se NTS 1 15 256 33m 0 0 8 100
|
||||
```
|
||||
|
||||
The _KeyID_, _Type_, and _KLen_ columns should have non-zero values. If they are zero, check the system log for error messages from _chronyd_. One possible cause of failure is a firewall is blocking the client’s connection to the server’s TCP port ( port 4460).
|
||||
|
||||
Another possible cause of failure is a certificate that is failing to verify because the client’s clock is wrong. This is a chicken-or-the-egg type problem with NTS. You may need to manually correct the date or temporarily disable NTS in order to get NTS working. If your computer has a real-time clock, as almost all computers do, and it’s backed up by a good battery, this operation should be needed only once.
|
||||
|
||||
If the computer doesn’t have a real-time clock or battery, as is common with some small ARM computers like the Raspberry Pi, you can add the _-s_ option to _/etc/sysconfig/chronyd_ to restore time saved on the last shutdown or reboot. The clock will be behind the true time, but if the computer wasn’t shut down for too long and the server’s certificates were not renewed too close to their expiration, it should be sufficient for the time checks to succeed. As a last resort, you can disable the time checks with the _nocerttimecheck_ directive. See the _chrony.conf(5)_ man page for details.
|
||||
|
||||
Run the following command to confirm that the client is making NTP measurements:
|
||||
|
||||
```
|
||||
# chronyc -N sources
|
||||
MS Name/IP address Stratum Poll Reach LastRx Last sample
|
||||
===============================================================================
|
||||
^* time.cloudflare.com 3 6 377 45 +355us[ +375us] +/- 11ms
|
||||
^+ nts.sth1.ntp.se 1 6 377 44 +237us[ +237us] +/- 23ms
|
||||
^+ nts.sth2.ntp.se 1 6 377 44 -170us[ -170us] +/- 22ms
|
||||
```
|
||||
|
||||
The _Reach_ column should have a non-zero value; ideally 377. The value 377 shown above is an octal number. It indicates that the last eight requests all had a valid response. The validation check will include NTS authentication if enabled. If the value only rarely or never gets to 377, it indicates that NTP requests or responses are getting lost in the network. Some major network operators are known to have middleboxes that block or limit rate of large NTP packets as a mitigation for amplification attacks that exploit the monitoring protocol of _ntpd_. Unfortunately, this impacts NTS-protected NTP packets, even though they don’t cause any amplification. The NTP working group is considering an alternative port for NTP as a workaround for this issue.
|
||||
|
||||
### Enable NTS on the server
|
||||
|
||||
If you have your own NTP server running _chronyd_, you can enable server NTS support to allow its clients to be synchronized securely. If the server is a client of other servers, it should use NTS or a symmetric key for its own synchronization. The clients assume the synchronization chain is secured between all servers up to the primary time servers.
|
||||
|
||||
Enabling server NTS is similar to enabling HTTPS on a web server. You just need a private key and certificate. The certificate could be signed by the Let’s Encrypt authority using the _certbot_ tool, for example. When you have the key and certificate file (including intermediate certificates), specify them in _chrony.conf_ with the following directives:
|
||||
|
||||
```
|
||||
ntsserverkey /etc/pki/tls/private/foo.example.net.key
|
||||
ntsservercert /etc/pki/tls/certs/foo.example.net.crt
|
||||
```
|
||||
|
||||
Make sure the _ntsdumpdir_ directive mentioned previously in the client configuration is present in _chrony.conf_. It allows the server to save its keys to disk, so the clients of the server don’t have to get new keys and cookies when the server is restarted.
|
||||
|
||||
Restart the _chronyd_ service:
|
||||
|
||||
```
|
||||
systemctl restart chronyd
|
||||
```
|
||||
|
||||
If there are no error messages in the system log from _chronyd_, it should be accepting client connections. If the server has a firewall, it needs to allow both the UDP 123 and TCP 4460 ports for NTP and NTS-KE respectively.
|
||||
|
||||
You can perform a quick test from a client machine with the following command:
|
||||
|
||||
```
|
||||
$ chronyd -Q -t 3 'server foo.example.net iburst nts maxsamples 1'
|
||||
2020-10-13T12:00:52Z chronyd version 4.0 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCDNS +NTS +SECHASH +IPV6 +DEBUG)
|
||||
2020-10-13T12:00:52Z Disabled control of system clock
|
||||
2020-10-13T12:00:55Z System clock wrong by -0.001032 seconds (ignored)
|
||||
2020-10-13T12:00:55Z chronyd exiting
|
||||
```
|
||||
|
||||
If you see a _System clock wrong_ message, it’s working correctly.
|
||||
|
||||
On the server, you can use the following command to check how many NTS-KE connections and authenticated NTP packets it has handled:
|
||||
|
||||
```
|
||||
# chronyc serverstats
|
||||
NTP packets received : 2143106240
|
||||
NTP packets dropped : 117180834
|
||||
Command packets received : 16819527
|
||||
Command packets dropped : 0
|
||||
Client log records dropped : 574257223
|
||||
NTS-KE connections accepted: 104
|
||||
NTS-KE connections dropped : 0
|
||||
Authenticated NTP packets : 52139
|
||||
```
|
||||
|
||||
If you see non-zero _NTS-KE connections accepted_ and _Authenticated NTP packets_, it means at least some clients were able to connect to the NTS-KE port and send an authenticated NTP request.
|
||||
|
||||
_— Cover photo by Louis. K on Unsplash —_
|
||||
|
||||
* * *
|
||||
|
||||
1\. The Fedora 33 _Beta_ installer contains an older chrony prerelease which doesn’t work with current NTS servers because the NTS-KE port has changed. Consequently, in the Network Time configuration in the installer, the servers will always appear as not working. After installation, the chrony package needs to be updated before it will work with current servers.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/secure-ntp-with-nts/
|
||||
|
||||
作者:[Miroslav Lichvar][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/mlichvar/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2020/10/secure-ntp-with-nts-816x345.jpg
|
||||
[2]: tmp.rl0XC1HIGm#footnote1
|
||||
[3]: https://tools.ietf.org/html/rfc8915
|
||||
[4]: https://www.pool.ntp.org
|
||||
[5]: https://developers.cloudflare.com/time-services/nts/usage
|
||||
[6]: https://www.netnod.se/time-and-frequency/how-to-use-nts
|
||||
[7]: https://fedoramagazine.org/wp-content/uploads/2020/10/anaconda-nts.png
|
||||
@@ -1,170 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (You can Surf Internet in Linux Terminal With These Command Line Browsers)
|
||||
[#]: via: (https://itsfoss.com/terminal-web-browsers/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
You can Surf Internet in Linux Terminal With These Command Line Browsers
|
||||
======
|
||||
|
||||
I’m guessing that you are probably using Firefox or a Chrome-based browser like [Brave][1] to read this article. Or, maybe, Google Chrome or [Chromium][2].
|
||||
|
||||
In other words, you are utilizing a GUI-based approach to browse the web. However, back in the days, people used the terminal to fetch resources and browse the web because everything was mostly text-based information.
|
||||
|
||||
Even though you cannot get every information from a terminal now, you can still try the command line browsers for some text-based information and open a web page from the Linux terminal.
|
||||
|
||||
Not just limited to that, but if you are accessing a remote server or stuck in a terminal without a GUI, a terminal web browser can prove to be useful as well.
|
||||
|
||||
So, in this article, I will be mentioning some terminal based web browsers that you can try on Linux.
|
||||
|
||||
### Best Terminal-based Web Browsers for Linux Users
|
||||
|
||||
_**Note:** The list is in no particular order of ranking._
|
||||
|
||||
#### 1\. W3M
|
||||
|
||||
![][3]
|
||||
|
||||
w3m is a popular open-source text-based web browser for the terminal. Even though the original project is no longer active, an active version of it is being maintained by a different developer Tatsuya Kinoshita.
|
||||
|
||||
w3m is quite simple, supports SSL connections, colors, and in-line images as well. Of course, depending on what resource you are trying to access, things might look different on your end. As per my quick test, it didn’t seem to load up [DuckDuckGo][4] but I could [use Google in terminal][5] just fine.
|
||||
|
||||
You can simply type **w3m** in the terminal to get help after installation. If you’re curious, you can also check out the repository at [GitHub][6].
|
||||
|
||||
##### How to install and use w3m?
|
||||
|
||||
W3M is available on most of the default repositories for any Debian-based Linux distribution. If you have an Arch-based distro, you might want to check [AUR][7] if it’s not available directly.
|
||||
|
||||
For Ubuntu, you can install it by typing in:
|
||||
|
||||
```
|
||||
sudo apt install w3m w3m-img
|
||||
```
|
||||
|
||||
Here, we are installing the w3m package along with image extension for in-line image support. Next, to get started, you have to simply follow the command below:
|
||||
|
||||
```
|
||||
w3m xyz.com
|
||||
```
|
||||
|
||||
Of course, you need to replace xyz.com to any website that you want to browse/test. Finally, you should know that you can use the keyboard arrow keys to navigate and press enter when you want to take an action.
|
||||
|
||||
To quit, you can press **SHIFT+Q**, and to go back to the previous page — **SHIFT+B**. Additional shortcuts include **SHIFT + T** to open a new tab and **SHIFT + U** to open a new URL.
|
||||
|
||||
You can explore more about it by heading to its man page as well.
|
||||
|
||||
#### 2\. Lynx
|
||||
|
||||
![][8]
|
||||
|
||||
Lynx is yet another open source command line browser which you can try. Fortunately, more websites tend to work when using Lynx, so I’d say it is definitely better in that aspect. I was able to load up DuckDuckGo and make it work.
|
||||
|
||||
In addition to that, I also noticed that it lets you accept/deny cookies when visiting various web resources. You can set it to always accept or deny as well. So, that’s a good thing.
|
||||
|
||||
On the other hand, the window does not re-size well while using it from the terminal. I haven’t looked for any solutions to that, so if you’re trying this out, you might want to do that. In either case, it works great and you get all the instructions for the keyboard shortcuts right when you launch it in the terminal.
|
||||
|
||||
Note that it does not match the system terminal theme, so it will look different no matter how your terminal looks like.
|
||||
|
||||
##### How to install Lynx?
|
||||
|
||||
Unlike w3m, you do get some Win32 installers if you’re interested to try. But, on Linux, it is available on the most of the default repositories.
|
||||
|
||||
For Ubuntu, you just need to type in:
|
||||
|
||||
```
|
||||
sudo apt install lynx
|
||||
```
|
||||
|
||||
To get started, you just have to follow the command below:
|
||||
|
||||
```
|
||||
lynx examplewebsite.com
|
||||
```
|
||||
|
||||
Here, you just need to replace the example website with the resource you want to visit.
|
||||
|
||||
If you want to explore the packages for other Linux distros, you can check out their [official website resources][9].
|
||||
|
||||
#### 3\. Links2
|
||||
|
||||
![][10]
|
||||
|
||||
Links2 is an interesting text-based browser that you can easily utilize on your terminal with a good user experience. It gives you a nice interface to type in the URL and then proceed as soon as you launch it.
|
||||
|
||||
![][11]
|
||||
|
||||
It is worth noting that the theme will depend on your terminal settings, I have it set as “black-green”, hence this is what you see. Once you launch it as a command line browser, you just need to press any key to bring the URL prompt or Q to quit it. It works good enough and renders text from most of the sites.
|
||||
|
||||
Unlike Lynx, you do not get the ability to accept/reject cookies. Other than that, it seems to work just fine.
|
||||
|
||||
##### How to install Links2?
|
||||
|
||||
As you’d expect, you will find it available in the most of the default repositories. For Ubuntu, you can install it by typing the following command in the terminal:
|
||||
|
||||
```
|
||||
sudo apt install links2
|
||||
```
|
||||
|
||||
You can refer to its [official][12] [][12][website][12] for packages or documentations if you want to install it on any other Linux distribution.
|
||||
|
||||
#### 4\. eLinks
|
||||
|
||||
![][13]
|
||||
|
||||
eLinks is similar to Links2 — but it is no longer maintained. You will still find it in the default repositories of various distributions, hence, I kept it in this list.
|
||||
|
||||
It does not blend in with your system terminal theme. So, this may not be a pretty experience as a text-based browser without a “dark” mode if you needed that.
|
||||
|
||||
##### How to install eLinks?
|
||||
|
||||
On Ubuntu, it is easy to install it. You just have to type in the following in the terminal:
|
||||
|
||||
```
|
||||
sudo apt install elinks
|
||||
```
|
||||
|
||||
For other Linux distributions, you should find it available on the standard repositories. But, you can refer to the [official installation instructions][14] if you do not find it in the repository.
|
||||
|
||||
### Wrapping Up
|
||||
|
||||
It’s no surprise that there aren’t a lot of text-based web browsers to run on the terminal. Some projects like [Browsh][15] have tried to present a modern Linux command-line browser but it did not work in my case.
|
||||
|
||||
While tools like curl and wget allow you to [download files from the Linux command line][16], these terminal-based web browsers provide additional features.
|
||||
|
||||
In addition to command-line browsers, you may also like to try some [command line games for Linux][17], if you want to play around in the terminal.
|
||||
|
||||
What do you think about the text-based web browsers for Linux terminal? Feel free to let me know your thoughts in the comments below.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/terminal-web-browsers/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/brave-web-browser/
|
||||
[2]: https://itsfoss.com/install-chromium-ubuntu/
|
||||
[3]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/10/w3m-google.jpg?resize=800%2C463&ssl=1
|
||||
[4]: https://duckduckgo.com/
|
||||
[5]: https://itsfoss.com/review-googler-linux/
|
||||
[6]: https://github.com/tats/w3m
|
||||
[7]: https://itsfoss.com/aur-arch-linux/
|
||||
[8]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/10/lynx-terminal.jpg?resize=800%2C497&ssl=1
|
||||
[9]: https://lynx.invisible-island.net/lynx-resources.html
|
||||
[10]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/10/links2-terminal.jpg?resize=800%2C472&ssl=1
|
||||
[11]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/10/links2-terminal-welcome.jpg?resize=800%2C541&ssl=1
|
||||
[12]: http://links.twibright.com/download.php
|
||||
[13]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/10/elinks-terminal.jpg?resize=800%2C465&ssl=1
|
||||
[14]: http://elinks.or.cz/documentation/installation.html
|
||||
[15]: https://www.brow.sh/
|
||||
[16]: https://itsfoss.com/download-files-from-linux-terminal/
|
||||
[17]: https://itsfoss.com/best-command-line-games-linux/
|
||||
@@ -1,133 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (5 new sudo features you need to know in 2020)
|
||||
[#]: via: (https://opensource.com/article/20/10/sudo-19)
|
||||
[#]: author: (Peter Czanik https://opensource.com/users/czanik)
|
||||
|
||||
5 new sudo features you need to know in 2020
|
||||
======
|
||||
From central session recording through chroot support to Python API,
|
||||
sudo 1.9 offers many new features.
|
||||
![Wratchet set tools][1]
|
||||
|
||||
When you want to perform an action on a [POSIX system][2], one of the safest ways to do so is to use the sudo command. Unlike logging in as the root user and performing what could be a dangerous action, sudo grants any user [designated as a "sudoer"][3] by the sysadmin temporary permission to perform a normally restricted activity.
|
||||
|
||||
This system has helped keep Linux, Unix, and macOS systems safe from silly mistakes and malicious attacks for decades, and it is the default administrative mechanism on all major Linux distributions today.
|
||||
|
||||
When it was released in May 2020, sudo 1.9 brought many new features, including central collection of session recordings, support for chroot within sudo, and a Python API. If you are surprised by any of these, read my article about some [lesser-known features of sudo][4].
|
||||
|
||||
Sudo is a lot more than just a prefix for administrative commands. You can fine-tune permissions, record what is happening on the terminal, extend sudo using plugins, store configurations in LDAP, do extensive logging, and much more.
|
||||
|
||||
Version 1.9.0 and subsequent minor releases added a variety of new features (which I'll describe below), including:
|
||||
|
||||
* A recording service to collect sudo session recordings centrally
|
||||
* Audit plugin API
|
||||
* Approval plugin API
|
||||
* Python support for plugins
|
||||
* Chroot and CWD support built into sudo (starting with 1.9.3)
|
||||
|
||||
|
||||
|
||||
### Where to get sudo 1.9
|
||||
|
||||
Most Linux distributions still package the previous generation of sudo (version 1.8), and it will stay that way in long-term support (LTS) releases for several years. The most complete sudo 1.9 package I am aware of in a Linux distribution is openSUSE [Tumbleweed][5], which is a rolling distro, and the sudo package has Python support available in a subpackage. Recent [Fedora][6] releases include sudo 1.9 but without Python. [FreeBSD Ports][7] has the latest sudo version available, and you can enable Python support if you build sudo yourself instead of using the package.
|
||||
|
||||
If your favorite Linux distribution does not yet include sudo 1.9, check the [sudo binaries page][8] to see if a ready-to-use package is available for your system. This page also has packages for several commercial Unix variants.
|
||||
|
||||
As usual, before you start experimenting with sudo settings, _make sure you know the root password_. Yes, even on Ubuntu. Having a temporary "backdoor" is important; without it, you would have to hack your own system if something goes wrong. And remember: a syntactically correct configuration does not mean that anybody can do anything through sudo on that system!
|
||||
|
||||
### Recording service
|
||||
|
||||
The recording service collects session recordings centrally. This offers many advantages compared to local session log storage:
|
||||
|
||||
* It is more convenient to search in one place instead of visiting individual machines for recordings
|
||||
* Recordings are available even if the sending machine is down
|
||||
* Recordings cannot be deleted by local users who want to cover their tracks
|
||||
|
||||
|
||||
|
||||
For a quick test, you can send sessions through non-encrypted connections to the recording service. My blog contains [instructions][9] for setting it up in just a few minutes. For a production setup, I recommend using encryption. There are many possibilities, so read the [documentation][10] that best suits your environment.
|
||||
|
||||
### Audit plugin API
|
||||
|
||||
The new audit plugin API is not a user-visible feature. In other words, you cannot configure it from the sudoers file. It is an API, meaning that you can access audit information from plugins, including ones written in Python. You can use it in many different ways, like sending events from sudo directly to Elasticsearch or Logging-as-a-Service (LaaS) when something interesting happens. You can also use it for debugging and print otherwise difficult-to-access information to the screen in whatever format you like.
|
||||
|
||||
Depending on how you want to use it, you can find its documentation in the sudo plugin manual page (for C) and the sudo Python plugin manual. [Sample Python code][11] is available in the sudo source code, and there is also a [simplified example][12] on my blog.
|
||||
|
||||
### Approval plugin API
|
||||
|
||||
The approval plugin API makes it possible to include extra restrictions before a command will execute. These will run only after the policy plugin succeeds, so you can effectively add additional policy layers without replacing the policy plugin and thus sudoers. Multiple approval plugins may be defined, and all must succeed for the command to execute.
|
||||
|
||||
As with the audit plugin API, you can use it both from C and Python. The [sample Python code][13] documented on my blog is a good introduction to the API. Once you understand how it works, you can extend it to connect sudo to ticketing systems and approve sessions only with a related open ticket. You can also connect to an HR database so that only the engineer on duty can gain administrative privileges.
|
||||
|
||||
### Python support for plugins
|
||||
|
||||
Even though I am not a programmer, my favorite new sudo 1.9 feature is Python support for plugins. You can use most of the APIs available from C with Python as well. Luckily, sudo is not performance-sensitive, so the relatively slow speed of running Python code is not a problem for sudo. Using Python for extending sudo has many advantages:
|
||||
|
||||
* Easier, faster development
|
||||
* No need to compile; code might even be distributed by configuration management
|
||||
* Many APIs do not have ready-to-use C clients, but Python code is available
|
||||
|
||||
|
||||
|
||||
In addition to the audit and approval plugin APIs, there are a few others available, and you can do very interesting things with them.
|
||||
|
||||
By using the policy plugin API, you can replace the sudo policy engine. Note you will lose most sudo features, and there is no more sudoers-based configuration. This can still be useful in niche cases, but most of the time, it is better to keep using sudoers and create additional policies using the approval plugin API. If you want to give it a try, my [introduction to the Python plugin][14] provides a very simple policy: allowing only the `id` command. Once again, make sure you know the root password, as once this policy is enabled, it prevents any practical use of sudo.
|
||||
|
||||
Using the I/O logs API, you can access input and output from user sessions. This means you can analyze what is happening in a session and even terminate it if you find something suspicious. This API has many possible uses, such as data-leak prevention. You can monitor the screen for keywords and, if any of them appear in the data stream, you can break the connection before the keyword can appear on the user's screen. Another possibility is checking what the user is typing and using that data to reconstruct the command line the user is entering. For example, if a user enters `rm -fr /`, you can disconnect the user even before Enter is hit.
|
||||
|
||||
The group plugin API allows non-Unix group lookups. In a way, this is similar to the approval plugin API as it also extends the policy plugin. You can check if a user is part of a given group and act based on this in later parts of the configuration.
|
||||
|
||||
### Chroot and CWD support
|
||||
|
||||
The latest additions to sudo are chroot and change working directory (CWD) support. Neither option is enabled by default—you need to explicitly enable them in the sudoers file. When they're enabled, you can fine-tune target directories or allow users to specify which directory to use. The logs reflect when these settings were used.
|
||||
|
||||
On most systems, chroot is available only to root. If one of your users needs chroot, you need to give them root access, which gives them a lot more power than just chroot. Alternately, you can allow access to the chroot command through sudo, but it still allows loopholes where they can gain full access. When you use sudo's built-in chroot support, you can easily restrict access to a single directory. You can also give users the flexibility to specify the root directory. Of course, this might lead to disasters (e.g., `sudo --chroot / -s`), but at least the event is logged.
|
||||
|
||||
When you run a command through sudo, it sets the working directory to the current directory. This is the expected behavior, but there may be cases when the command needs to be run in a different directory. For example, I recall using an application that checked my privileges by checking whether my working directory was `/root`.
|
||||
|
||||
### Try the new features
|
||||
|
||||
I hope that this article inspires you to take a closer look at sudo 1.9. Central session recording is both more convenient and secure than storing session logs locally. Chroot and CWD support give you additional security and flexibility. And using Python to extend sudo makes it easy to custom-tailor sudo to your environment. You can try the new features by using one of the latest Linux distributions or the ready-to-use packages from the sudo website.
|
||||
|
||||
If you want to learn more about sudo, here are a few resources:
|
||||
|
||||
* [Sudo website][15]
|
||||
* [Sudo blog][16]
|
||||
* [Sudo on Twitter][17]
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/10/sudo-19
|
||||
|
||||
作者:[Peter Czanik][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/czanik
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/tools_osyearbook2016_sysadmin_cc.png?itok=Y1AHCKI4 (Wratchet set tools)
|
||||
[2]: https://opensource.com/article/19/7/what-posix-richard-stallman-explains
|
||||
[3]: https://opensource.com/article/17/12/using-sudo-delegate
|
||||
[4]: https://opensource.com/article/19/10/know-about-sudo
|
||||
[5]: https://software.opensuse.org/distributions/tumbleweed
|
||||
[6]: https://getfedora.org/
|
||||
[7]: https://www.freebsd.org/ports/
|
||||
[8]: https://www.sudo.ws/download.html#binary
|
||||
[9]: https://blog.sudo.ws/posts/2020/03/whats-new-in-sudo-1.9-recording-service/
|
||||
[10]: https://www.sudo.ws/man/sudo_logsrvd.man.html#EXAMPLES
|
||||
[11]: https://github.com/sudo-project/sudo/blob/master/plugins/python/example_audit_plugin.py
|
||||
[12]: https://blog.sudo.ws/posts/2020/06/sudo-1.9-using-the-new-audit-api-from-python/
|
||||
[13]: https://blog.sudo.ws/posts/2020/08/sudo-1.9-using-the-new-approval-api-from-python/
|
||||
[14]: https://blog.sudo.ws/posts/2020/01/whats-new-in-sudo-1.9-python/
|
||||
[15]: https://www.sudo.ws/
|
||||
[16]: https://blog.sudo.ws/
|
||||
[17]: https://twitter.com/sudoproject
|
||||
@@ -1,90 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Reclaim hard-drive space with LVM)
|
||||
[#]: via: (https://fedoramagazine.org/reclaim-hard-drive-space-with-lvm/)
|
||||
[#]: author: (Troy Curtis Jr https://fedoramagazine.org/author/troycurtisjr/)
|
||||
|
||||
Reclaim hard-drive space with LVM
|
||||
======
|
||||
|
||||
![Hard drive image][1]
|
||||
|
||||
Photo by Frank R @ Unsplash.com
|
||||
|
||||
LVM is a tool for logical volume management which includes allocating disks, striping, mirroring and resizing logical volumes. It is commonly used on Fedora installations (prior to BTRFS as default it was LVM+Ext4). But have you ever started up your system to find out that Gnome just said the home volume is almost out of space! Luckily, there is likely some space sitting around in another volume, unused and ready to re-alocate. Here’s how to reclaim hard-drive space with LVM.
|
||||
|
||||
The key to easily re-alocate space between volumes is the [Logical Volume Manager (LVM)][2]. Fedora 32 and before use LVM to divide disk space by default. This technology is similar to standard hard-drive partitions, but LVM is a lot more flexible. LVM enables not only flexible volume size management, but also advanced capabilities such as read-write snapshots, striping or mirroring data across multiple drives, using a high-speed drive as a cache for a slower drive, and much more. All of these advanced options can get a bit overwhelming, but resizing a volume is straight-forward.
|
||||
|
||||
### LVM basics
|
||||
|
||||
The _volume group_ serves as the main container in the LVM system. By default Fedora only defines a single volume group, but there can be as many as needed. Actual hard-drive and hard-drive partitions are added to the _volume group_ as _physical volumes_. _Physical volumes_ add available free space to the _volume group_. A typical Fedora install has one formatted boot partition, and the rest of the drive is a partition configured as an LVM _physical volume_.
|
||||
|
||||
Out of this pool of available space, the _volume group_ allocates one or more _logical volumes_. These volumes are similar to hard-drive partitions, but without the limitation of contiguous space on the disk. LVM _logical volumes_ can even span multiple devices! Just like hard-drive partitions, _logical volumes_ have a defined size and can contain any filesystem which can then be mounted to specific directories.
|
||||
|
||||
### What’s needed
|
||||
|
||||
Confirm the system uses LVM with the _gnome-disks_ application, and make sure there is free space available in some other volume. Without space to reclaim from another volume, this guide isn’t useful. A [Fedora live CD/USB][3] is also needed. Any file system that needs to shrink must be unmounted. Running from a live image allows all the volumes on the hard-disk to remain unmounted, even important directories like _/_ and _/home_.
|
||||
|
||||
![Use gnome-disks to verify free space][4]
|
||||
|
||||
### A word of warning
|
||||
|
||||
No data should be lost by following this guide, but it does muck around with some very low-level and powerful commands. One mistake could destroy all data on the hard-drive. So backup all the data on the disk first!
|
||||
|
||||
### Resizing LVM volumes
|
||||
|
||||
To begin, boot the Fedora live image and select _Try Fedora_ at the dialog. Next, use the _Run Command_ to launch the _blivet-gui_ application (accessible by pressing _Alt-F2_, typing _blivet-gui_, then pressing _enter_). Select the volume group on the left under _LVM_. The logical volumes are on the right.
|
||||
|
||||
![Explore logical volumes in blivet-gui][5]
|
||||
|
||||
The logical volume labels consist of both the volume group name and the logical volume name. In the example, the volume group is “fedora_localhost-live” and there are “home”, “root”, and “swap” logical volumes allocated. To find the full volume, select each one, click on the _gear_ icon, and choose _resize_. The slider in the resize dialog indicates the allowable sizes for the volume. The minimum value on the left is the space already in use within the file system, so this is the minimum possible volume size (without deleting data). The maximum value on the right is the greatest size the volume can have based on available free space in the _volume group_.
|
||||
|
||||
![Resize dialog in blivet-gui][6]
|
||||
|
||||
A grayed out _resize_ option means the volume is full and there is no free space in the volume group. It’s time to change that! Look through all of the volumes to find one with plenty of extra space, like in the screenshot above. Move the slider to the left to set the new size. Free up enough space to be useful for the full volume, but still leave plenty of space for future data growth. Otherwise, this volume will be the next to fill up.
|
||||
|
||||
Click _resize_ and note that a new item appears in the volume listing: _free space_. Now select the full volume that started this whole endeavor, and move the slider all the way to the right. Press _resize_ and marvel at the new improved volume layout. However, nothing has changed on the hard drive yet. Click on the _check-mark_ to commit the changes to disk.
|
||||
|
||||
![Review changes in blivet-gui][7]
|
||||
|
||||
Review the summary of the changes, and if everything looks right, click _Ok_ to proceed. Wait for _blivet-gui_ to finish. Now reboot back into the main Fedora install and enjoy all the new space in the previously full volume.
|
||||
|
||||
### Planning for the future
|
||||
|
||||
It is challenging to know how much space any particular volume will need in the future. Instead of immediately allocating all available free space, consider leaving it free in the volume group. In fact, Fedora Server reserves space in the volume group by default. Extending a volume is possible while it is online and in use. No live image or reboot needed. When a volume is almost full, easily extend the volume using part of the available free space and keep working. Unfortunately the default disk manager, _gnome-disks_, does not support LVM volume resizing, so install _[blivet-gui][8]_ for a graphical management tool. Alternately, there is a simple terminal command to extend a volume:
|
||||
|
||||
```
|
||||
lvresize -r -L +1G /dev/fedora_localhost-live/root
|
||||
```
|
||||
|
||||
### Wrap-up
|
||||
|
||||
Reclaiming hard-drive space with LVM just scratches the surface of LVM capabilities. Most people, especially on the desktop, probably don’t need the more advanced features. However, LVM is there when the need arises, though it can get a bit complex to implement. [BTRFS][9] is the default filesystem, without LVM, starting with [Fedora 33][10]. BTRFS can be easier to manage while still flexible enough for most common usages. Check out the recent [Fedora Magazine articles on BTRFS][11] to learn more.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/reclaim-hard-drive-space-with-lvm/
|
||||
|
||||
作者:[Troy Curtis Jr][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/troycurtisjr/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2020/11/lvm-resize-816x345.jpg
|
||||
[2]: http://sourceware.org/lvm2/
|
||||
[3]: https://getfedora.org/en/workstation/download/
|
||||
[4]: https://fedoramagazine.org/wp-content/uploads/2020/11/gnome-disks.png
|
||||
[5]: https://fedoramagazine.org/wp-content/uploads/2020/11/blivet-overview.png
|
||||
[6]: https://fedoramagazine.org/wp-content/uploads/2020/11/blivet-resize-1024x525.png
|
||||
[7]: https://fedoramagazine.org/wp-content/uploads/2020/11/blivet-summary-1024x525.png
|
||||
[8]: https://fedoraproject.org/wiki/Blivet-gui
|
||||
[9]: https://fedoramagazine.org/btrfs-coming-to-fedora-33/
|
||||
[10]: https://fedoramagazine.org/whats-new-fedora-33-workstation/
|
||||
[11]: https://fedoramagazine.org/btrfs-snapshots-backup-incremental/
|
||||
@@ -1,99 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Day 1: a confusing Rails error message)
|
||||
[#]: via: (https://jvns.ca/blog/2020/11/09/day-1--a-little-rails-/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
Day 1: a confusing Rails error message
|
||||
======
|
||||
|
||||
Today I started an Recurse Center batch! I got to meet a few people, and started on a tiny fun Rails project. I think I won’t talk too much about what the project actually is today, but here are some quick notes on a day with Rails:
|
||||
|
||||
### some notes on getting started
|
||||
|
||||
The main thing I learned about setting up a Rails project is that
|
||||
|
||||
1. it uses sqlite by default, you have to tell it to use Postgres
|
||||
2. there are a ton of things that Rails includes by default that you can disable.
|
||||
|
||||
|
||||
|
||||
I installed and `rm -rf`’d Rails maybe 7 times before I was satisfied with it and ended up with this incantation:
|
||||
|
||||
```
|
||||
rails new . -d postgresql --skip-sprockets --skip-javascript`
|
||||
```
|
||||
|
||||
Basically because I definitely wanted to use Postgres and not sqlite, and skipping sprockets and javascript seemed to make installing Rails faster, and I figured I could install them later if I decided I wanted them.
|
||||
|
||||
### the official Rails guide is really good
|
||||
|
||||
I used 2 main resources for creating my starter Rails app:
|
||||
|
||||
* DHH’s original Rails talk from 2005 <https://www.youtube.com/watch?v=Gzj723LkRJY> (which I didn’t watch this time, but I watched the last time I spent a day with Rails, and I found it pretty inspiring and helpful)
|
||||
* The official Rails “getting started” guide, which seems pretty short and clear <https://guides.rubyonrails.org/v5.0/getting_started.html>
|
||||
|
||||
|
||||
|
||||
### a mysterious error message: `undefined method 'user'`
|
||||
|
||||
I love bugs, so here’s a weird Rails error I ran into today! I had some code that looked like this:
|
||||
|
||||
```
|
||||
@user = User.new(user_params)
|
||||
@user.save
|
||||
```
|
||||
|
||||
Pretty simple, right? But when that code ran, I got this baffling error message:
|
||||
|
||||
```
|
||||
undefined method `user' for #<User:0x00007fb6f4012ab8> Did you mean? super
|
||||
```
|
||||
|
||||
I was EXTREMELY confused about what was going on here because I hadn’t _called_ a method called `user`. I’d called `.save`. What???? I stayed confused and frustrated about this for maybe 20 minutes, and then finally I looked at my `User` model and found this code:
|
||||
|
||||
```
|
||||
class User < ApplicationRecord
|
||||
has_secure_password
|
||||
|
||||
validates :user, presence: true, uniqueness: true
|
||||
end
|
||||
```
|
||||
|
||||
`validates :user...` was _supposed_ to be some Rails magic validating that every `User` had a `username`, and that usernames had to be unique. But I’d made a typo, and I’d written `user` and not `username`. I fixed this and then everything worked! hooray!
|
||||
|
||||
I still don’t understand how I was supposed to debug this though: the stack trace told me the problem was with the `@user.save` line, and never mentioned that `validates :user` thing at all. I feel like there must be a way to debug this but I don’t know what it is.
|
||||
|
||||
The whole point of me playing with Rails is to see how the Rails magic plays out in practice so this was a fun bug to hit early on.
|
||||
|
||||
### a simple user management system
|
||||
|
||||
I decided I wanted users in my toy app. Some Googling showed me that there’s an extremely popular gem called [devise][1] that handles users. I found the README a little overwhelming and I knew that I wanted a very minimal user management system in my toy app, so instead I followed this guide called [Authentication from Scratch with Rails 5.2][2] which seems to be working out so far. Rails seems to already have a bunch of built in stuff for managing users – I was really surprised by how short that guide was and how little code I needed to write.
|
||||
|
||||
I learned while implementing users that Rails has a built in magical session management system (see [How Rails Sessions Work][3]. By default all the session data seems to be stored in a cookie on the user’s computer, though I guess you can also store the session data in a database if it gets too big for a cookie.
|
||||
|
||||
It’s definitely kind of strange to already have a session management system and cookies and users without quite knowing what’s going on exactly, but it’s also kind of fun! We’ll see how it goes.
|
||||
|
||||
### tomorrow: more rails!
|
||||
|
||||
Maybe tomorrow I can actually make some progress on implementing my fun rails app idea!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2020/11/09/day-1--a-little-rails-/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://github.com/heartcombo/devise
|
||||
[2]: https://medium.com/@wintermeyer/authentication-from-scratch-with-rails-5-2-92d8676f6836
|
||||
[3]: https://www.justinweiss.com/articles/how-rails-sessions-work/
|
||||
@@ -0,0 +1,119 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Day 2: Rails associations & dragging divs around)
|
||||
[#]: via: (https://jvns.ca/blog/2020/11/10/day-2--rails-associations---dragging-divs-around/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
Day 2: Rails associations & dragging divs around
|
||||
======
|
||||
null
|
||||
Hello! Today was day 2 of building my toy project. Here are a few more notes on things that have been fun about Rails!
|
||||
|
||||
### the goal: make a refrigerator poetry forum
|
||||
|
||||
I wanted to make kind of a boring standard website to learn Rails, and that other people could interact with. Like a forum! But of course if people can actually type on a website that creates all kinds of problems (what if they’re spammers? or just mean?).
|
||||
|
||||
The first idea I came up with that would let people interact with the website but not actually be able to type things into it was a refrigerator poetry forum where you can write poems given only a fixed set of words.
|
||||
|
||||
So, that’s the plan!
|
||||
|
||||
My goal with this project is to find out if I want to use Rails for other small web projects (instead of what I usually do, which is use something more basic like Flask, or give up on having a backend at all and write everything in Javascript).
|
||||
|
||||
### how do you drag the words around? jQuery UI draggable!
|
||||
|
||||
I wanted people to be able to drag the words around, but I didn’t feel like writing a lot of Javascript. It turns out that this is SUPER easy – there’s a jQuery library to do it called “draggable”!
|
||||
|
||||
At first the dragging didn’t work on mobile, but there’s a hack to make jQuery UI work on mobile called [jQuery UI touch punch][1]. Here’s what it looks like (you can view source if you’re interested in seeing how it works, there’s very little code).
|
||||
|
||||
banana forest cake is
|
||||
|
||||
### a fun Rails feature: “associations”
|
||||
|
||||
I’ve never used a relational ORM before, and one thing I was excited about with Rails was to see what using Active Record is like! Today I learned about one of Rails’ ORM features: [associations][2]. Here’s what that’s about if you know absolutely nothing about ORMs like me.
|
||||
|
||||
In my forum, I have:
|
||||
|
||||
* users
|
||||
* topics (I was going to call this “threads” but apparently that’s a reserved word in Rails so they’re called “topics” for now)
|
||||
* posts
|
||||
|
||||
|
||||
|
||||
When displaying a post, I need to show the username of the user who created the post. So I thought I might need to write some code to load the posts and load the user for each post like this: (in Rails, `Post.where` and `User.find` will run SQL statements and turn the results into Ruby objects)
|
||||
|
||||
```
|
||||
@posts = Post.where(topic_id: id)
|
||||
@posts.each do |post|
|
||||
user = User.find(post.user_id)
|
||||
post.user = user
|
||||
end
|
||||
```
|
||||
|
||||
This is no good though – it’s doing a separate SQL query for every post! I knew there was a better way, and I found out that it’s called [Associations][2]. That link is to the guide from <https://guides.rubyonrails.org>, which has treated me well so far.
|
||||
|
||||
Basically all I needed to do was:
|
||||
|
||||
1. Add a `has_many :posts` line to the User model
|
||||
2. Add a `belongs_to :user` line to the Post model
|
||||
3. Rails now knows how to join these two tables even though I didn’t tell it what columns to join on! I think this is because I named the `user_id` column in the `posts` table according to the convention it expects.
|
||||
4. Do the exact same thing for `User` and `Topic` (a topic also `has_many :posts`)
|
||||
|
||||
|
||||
|
||||
And then my code to load every post along with its associated user becomes just one line! Here’s the line:
|
||||
|
||||
```
|
||||
@posts = @topic.posts.order(created_at: :asc).preload(:user)
|
||||
```
|
||||
|
||||
More importantly than it being just one line, instead of doing a separate query to get the user for each post, it gets all the users in 1 query. Apparently there are a bunch of [different ways][3] to do similar things in Rails (preload, eager load, joins, and includes?). I don’t know what all those are yet but maybe I’ll learn that later.
|
||||
|
||||
### a fun Rails feature: scaffolding!
|
||||
|
||||
Rails has this command line tool called `rails` and it does a lot of code generation. For example, I wanted to add a Topic model / controller. Instead of having to go figure out where to add all the code, I could just run:
|
||||
|
||||
```
|
||||
rails generate scaffold Topic title:text
|
||||
```
|
||||
|
||||
and it generated a bunch of code, so that I already had basic endpoints to create / edit / delete Topics. For example, here’s my [topic controller right now][4], most of which I did not write (I only wrote the highlighted 3 lines). I’ll probably delete a lot of it, but it feels kinda nice to have a starting point where I can expand on the parts I want and delete the parts I don’t want.
|
||||
|
||||
### database migrations!
|
||||
|
||||
The `rails` tool can also generate database migrations! For example, I decided I wanted to remove the `title` field from posts.
|
||||
|
||||
Here’s what I had to do:
|
||||
|
||||
```
|
||||
rails generate migration RemoveTitleFromPosts title:string
|
||||
rails db:migrate
|
||||
```
|
||||
|
||||
That’s it – just run a couple of command line incantations! I ran a few of these migrations as I changed my mind about what I wanted my database schema to be and it’s been pretty straightforward so far – it feels pretty magical.
|
||||
|
||||
It got a tiny bit more interesting when I tried to add a `not null` constraint to a column where some of the fields in that column were null – the migration failed. But I could just fix the offending records and easily rerun the migration.
|
||||
|
||||
### that’s all for today!
|
||||
|
||||
tomorrow maybe I’ll put it on the internet if I make more progress.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2020/11/10/day-2--rails-associations---dragging-divs-around/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://github.com/furf/jquery-ui-touch-punch
|
||||
[2]: https://guides.rubyonrails.org/association_basics.html
|
||||
[3]: https://blog.bigbinary.com/2013/07/01/preload-vs-eager-load-vs-joins-vs-includes.html
|
||||
[4]: https://github.com/jvns/refrigerator-forum/blob/776b3227cfd7004cb1efb00ec7e3f82a511cbdc4/app/controllers/topics_controller.rb#L13-L15
|
||||
46
sources/tech/20201111 Day 3- an infinitely tall fridge.md
Normal file
46
sources/tech/20201111 Day 3- an infinitely tall fridge.md
Normal file
@@ -0,0 +1,46 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Day 3: an infinitely tall fridge)
|
||||
[#]: via: (https://jvns.ca/blog/2020/11/11/day-3--an-infinitely-tall-fridge/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
Day 3: an infinitely tall fridge
|
||||
======
|
||||
|
||||
Hello! Here are some notes from Day 3 at the Recurse Center.
|
||||
|
||||
This post is an extremely short one from the toy refrigerator poetry forum website I’m working on. I needed to come up with a design for it, and finally today I came up with an idea: just put everything on an image of a fridge.
|
||||
|
||||
I found a stock image of a fridge, but I ran into a problem immediately, which was that the entire website could not fit on said fridge image.
|
||||
|
||||
So I figured how to make a fridge that was as tall as I wanted it to be. (not technically “infinite”, but “a fridge that is as big as required” didn’t have quite the same ring).
|
||||
|
||||
### here’s the infinite fridge
|
||||
|
||||
Here’s a CodePen with the HTML/CSS required to make an infinite fridge. It’s relatively simple and I’m very pleased about this. It basically has 3 images: one for the top of the fridge, a 1px line that can be repeated as much as required, and then the bottom.
|
||||
|
||||
See the Pen [infinite refrigerator][1] by Julia Evans ([Julia Evans][2]) on [CodePen][3].
|
||||
|
||||
### that’s all!
|
||||
|
||||
I started writing an explanation of how exactly this infinite fridge works, but I ran out of time so maybe another day :). (the main trick is that `padding-bottom` is a percentage of the parent element’s width, not its height, so you can use it to create a box with a fixed aspect ratio)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2020/11/11/day-3--an-infinitely-tall-fridge/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://codepen.io/wizardzines/pen/bGeOdvJ
|
||||
[2]: https://codepen.io/wizardzines
|
||||
[3]: https://codepen.io
|
||||
@@ -1,146 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Using Fedora 33 with Microsoft’s WSL2)
|
||||
[#]: via: (https://fedoramagazine.org/wsl-fedora-33/)
|
||||
[#]: author: (Jim Perrin https://fedoramagazine.org/author/jperrin/)
|
||||
|
||||
Using Fedora 33 with Microsoft’s WSL2
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
Photo by [Matthias Heil][2] on [Unsplash][3]
|
||||
|
||||
If you’re like me, you may find yourself running Windows for a variety of reasons from work to gaming. Sure you could run Fedora in a virtual machine or as a container, but those don’t blend into a common windows experience as easily as the Windows Subsystem for Linux (WSL). Using Fedora via WSL will let you blend the two environments together for a fantastic development environment.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
There are a few basics you’ll need in order to make this all work. You should be running Windows 10, and have WSL2 installed already. If not, check out the [Microsoft documentation for instructions][4], and come back here when you’re finished. Microsoft recommends setting wsl2 as the distro default for simplicity. This guide assumes you’ve done that.
|
||||
|
||||
Next, you’re going to need some means of unpacking xz compressed files. You can do this with another WSL-based distribution, or use [7zip][5].
|
||||
|
||||
### Download a Fedora 33 rootfs
|
||||
|
||||
Since Fedora doesn’t ship an actual rootfs archive, we’re going to abuse the one used to generate the container image for dockerhub. You will want to download the [tar.xz file][6] from the fedora-cloud GitHub repository. Once you have the tar.xz, uncompress it, but don’t unpack it. You want to end up with something like fedora-33-_datestamp_.tar. Once you have that, you’re ready to build the image.
|
||||
|
||||
### Composing the WSL Fedora build
|
||||
|
||||
I prefer to use _c:\distros_, but you can choose nearly whatever location you want. Whatever you choose, make sure the top level path exists before you import the build. Now open a cmd or powershell prompt, because it’s time to import:
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
wsl.exe --import Fedora-33 c:\distros\Fedora-33 $HOME\Downloads\fedora-33.tar
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
You will see Fedora-33 show up in wsl’s list
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
PS C:\Users\jperrin> wsl.exe -l -v
|
||||
NAME STATE VERSION
|
||||
Fedora-33 Stopped 2
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
From here, you can start to play around with Fedora in wsl, but we have a few things we need to do to make it actually _useful_ as a wsl distro.
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
wsl -d Fedora-33
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
This will launch Fedora’s wsl instance as the root user. From here, you’re going to install a few core packages and set a new default user. You’re also going to need to configure sudo, otherwise you won’t be able to easily elevate privileges if you need to install something else later.
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
dnf update
|
||||
dnf install wget curl sudo ncurses dnf-plugins-core dnf-utils passwd findutils
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
_wslutilites_ uses _curl_ and _wget_ for things like VS Code integration, so they’re useful to have around. Since you need to use a Copr repo for this, you want the added dnf functionality.
|
||||
|
||||
### Add your user
|
||||
|
||||
Now it’s time to add your user, and set it as the default.
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
useradd -G wheel yourusername
|
||||
passwd yourusername
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Now that you’ve created your username and added a password, make sure they work. Exit the wsl instance, and launch it again, this time specifying the username. You’re also going to test sudo, and check your uid.
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
wsl -d Fedora-33 -u yourusername
|
||||
$id -u
|
||||
1000
|
||||
$ sudo cat /etc/shadow
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Assuming everything worked fine, you’re now ready to set the default user for your Fedora setup in Windows. To do this, exit the wsl instance and get back into Powershell. This Powershell one-liner configures your user properly:
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Get-ItemProperty Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss\\*\ DistributionName | Where-Object -Property DistributionName -eq Fedora-33 | Set-ItemProperty -Name DefaultUid -Value 1000
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Now you should be able to launch WSL again without specifying a user, and be yourself instead of root.
|
||||
|
||||
### Customize!
|
||||
|
||||
From here, you’re done getting the basic Fedora 33 setup running in wsl, but it doesn’t have the Windows integration piece yet. If this is something you want, there’s a Copr repo to enable. If you choose to add this piece, you’ll be able to run Windows apps directly from inside your shell, as well as integrate your Linux environment easily with VS Code. Note that Copr is not officially supported by Fedora infrastructure. Use packages at your own risk
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
dnf copr enable trustywolf/wslu
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Now you can go configure your terminal, setup a Python development environment, or however else you want to use Fedora 33. Enjoy!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/wsl-fedora-33/
|
||||
|
||||
作者:[Jim Perrin][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/jperrin/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2020/11/wsl-fedora33-816x345.jpg
|
||||
[2]: https://unsplash.com/@matthias_heil?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[3]: https://unsplash.com/s/photos/windows?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[4]: https://docs.microsoft.com/en-us/windows/wsl/install-win10
|
||||
[5]: https://www.7-zip.org/download.html
|
||||
[6]: https://github.com/fedora-cloud/docker-brew-fedora/tree/33/x86_64
|
||||
@@ -1,136 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to Install and Use Etcher on Linux for Making Live Linux USB)
|
||||
[#]: via: (https://itsfoss.com/install-etcher-linux/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
How to Install and Use Etcher on Linux for Making Live Linux USB
|
||||
======
|
||||
|
||||
_**Etcher is a popular USB flasher app for creating bootable Linux USB drives. Let me show you how to install it and how to use it for making a live Linux disk.**_
|
||||
|
||||
### Etcher: An open source tool to flash Linux ISO on SD Cards & USB drives
|
||||
|
||||
Etcher is an open-source project by [Balena][1] to help flash SD cards for Raspberry Pi. In fact, we used it in our tutorial on [how to install Raspbian OS on a SD Card][2].
|
||||
|
||||
Not just limited to SD Cards, you can also use Etcher to [make a bootable USB drive][3] just like we created a [live USB of Manjaro in Linux][4] with the help of it.
|
||||
|
||||
Ever since its first release, Etcher caught the attention for its neat interface and simplicity of use.
|
||||
|
||||
![][5]
|
||||
|
||||
In this article, I will be focusing on the steps to help you install Etcher on Linux. And then, I’ll also show how to use it. Before I do that, let me give you an overview of the features it offers:
|
||||
|
||||
### Features of Etcher
|
||||
|
||||
* Validate drive before flashing
|
||||
* Beautiful user interface
|
||||
* Auto-detects USB drive/SD card to prevent wiping the HDD on your computer
|
||||
* Cross-platform support (Windows, macOS, and Linux)
|
||||
* Fast flashing
|
||||
* Simple three-step process
|
||||
|
||||
|
||||
|
||||
On paper, you get everything one would need to flash OS images on an SD card and a USB drive. It is also exciting to know that they plan to add the support simultaneous writing to multiple devices as per their [roadmap][6].
|
||||
|
||||
### Installing Etcher on Linux
|
||||
|
||||
To get started, you have to grab the AppImage file that it offers (suitable for any Linux distribution) from its official website.
|
||||
|
||||
You just need to head on to its [homepage][7] and download the one for your system (32-bit/64-bit):
|
||||
|
||||
![][8]
|
||||
|
||||
In my case, I got the 64-bit AppImage file for Ubuntu. You can go through our guide on [using AppImage files on Linux][9], but I’ll give you a head start on what you need to do next.
|
||||
|
||||
You need to give the file permissions to execute and you can do that by right-clicking on the **AppImage file -> Properties**.
|
||||
|
||||
![][10]
|
||||
|
||||
Next, click on “**Allow executing as a program**” under the Permissions tab as shown in the image below.
|
||||
|
||||
![][11]
|
||||
|
||||
Now, just double-click on the AppImage file to launch balenaEtcher!
|
||||
|
||||
This should work on any Linux distribution. In either case, you can also head over to its [GitHub releases se][12][c][12][tion][12] to find RPM, DEB, and the source file if you want to build it from source or just install it using the .rpm or .deb files.
|
||||
|
||||
You can also refer to our guide on [using deb file in Ubuntu][13] to install applications.
|
||||
|
||||
Attention!
|
||||
|
||||
It’s been noticed that when you use Etcher to create live USB of Linux distributions, it leaves the USB in an apparent unusable state where it has only a few MB of free state and cannot be formatted directly. On Linux, you can [use the Disks tool to manually delete the partitions and then format it][14].
|
||||
|
||||
### Using Etcher on Linux
|
||||
|
||||
It is just a three-step process to get started using Etcher. It should be self-explanatory as per the on-screen instructions after you launch it, but just to give you a head start, here’s what you have to do:
|
||||
|
||||
**Step 1:** Select the appropriate ISO image file or the URL of the file that you need to flash (as shown in the image below).
|
||||
|
||||
![][15]
|
||||
|
||||
**Step 2**: Next, you will have to select the target device. It automatically detects and highlights removable devices to help you prevent selecting any internal storage locations.
|
||||
|
||||
![][16]
|
||||
|
||||
In this case, I have a USB drive connected, and I have it selected as well (as shown in the screenshot below).
|
||||
|
||||
![][17]
|
||||
|
||||
**Step 3:** Now, all you have to do is — flash the image and wait for it to complete successfully.
|
||||
|
||||
![][18]
|
||||
|
||||
Here’s how the progress looks:
|
||||
|
||||
![][19]
|
||||
|
||||
And, it is done!
|
||||
|
||||
![][20]
|
||||
|
||||
[Download balenaEtcher][7]
|
||||
|
||||
### Wrapping Up
|
||||
|
||||
Etcher is a useful tool to flash OS images for both SD cards and USB drives. I tend to use it primarily to create live USB drives to test Linux distros and I’m happy with it.
|
||||
|
||||
What do you prefer to use to create bootable drives? Have you tried Etcher already? Let me know your thoughts in the comments down below.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/install-etcher-linux/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.balena.io/
|
||||
[2]: https://itsfoss.com/tutorial-how-to-install-raspberry-pi-os-raspbian-wheezy/
|
||||
[3]: https://itsfoss.com/create-bootable-ubuntu-usb-drive-mac-os/
|
||||
[4]: https://itsfoss.com/create-live-usb-manjaro-linux/
|
||||
[5]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/10/etcher-mxlinux-2.png?resize=800%2C518&ssl=1
|
||||
[6]: https://github.com/balena-io/etcher/milestones
|
||||
[7]: https://www.balena.io/etcher
|
||||
[8]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/etcher-official-site-download.png?resize=800%2C580&ssl=1
|
||||
[9]: https://itsfoss.com/use-appimage-linux/
|
||||
[10]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/balena-etcher-permission.jpg?resize=800%2C378&ssl=1
|
||||
[11]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/balena-etcher-execute.jpg?resize=800%2C445&ssl=1
|
||||
[12]: https://github.com/balena-io/etcher/releases/tag/v1.5.109
|
||||
[13]: https://itsfoss.com/install-deb-files-ubuntu/
|
||||
[14]: https://itsfoss.com/cant-format-usb-disk/
|
||||
[15]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/balena-etcher-select.jpg?resize=800%2C521&ssl=1
|
||||
[16]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/etcher-select-target.jpg?resize=800%2C509&ssl=1
|
||||
[17]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/etcher-target-device.jpg?resize=800%2C521&ssl=1
|
||||
[18]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/etcher-flash.jpg?resize=800%2C516&ssl=1
|
||||
[19]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/etcher-flashing.jpg?resize=800%2C510&ssl=1
|
||||
[20]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/etcher-flash-complete.jpg?resize=800%2C507&ssl=1
|
||||
@@ -1,275 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to Install Fedora in VirtualBox [With Steps for USB, Clipboard and Folder Sharing])
|
||||
[#]: via: (https://itsfoss.com/install-fedora-in-virtualbox/)
|
||||
[#]: author: (Dimitrios Savvopoulos https://itsfoss.com/author/dimitrios/)
|
||||
|
||||
How to Install Fedora in VirtualBox [With Steps for USB, Clipboard and Folder Sharing]
|
||||
======
|
||||
|
||||
If you are curious about Fedora Linux, there are several ways to try it.
|
||||
|
||||
The easiest way that won’t affect your current operating system is to [create a live USB of Fedora.][1]
|
||||
|
||||
An alternative way to try Fedora, is to get advantage of virtualization technology through an installation in VirtualBox. This way, you use Fedora like an application on your current operating system.
|
||||
|
||||
This way, you can perform more thorough testing without messing up your current operating system.
|
||||
|
||||
You can even copy your virtual setup and re-install it on some other system. Sounds handy? Let me show you how to do it.
|
||||
|
||||
### Installing Fedora in VirtualBox
|
||||
|
||||
![][2]
|
||||
|
||||
Let’s see the steps for installing Fedora Linux in Oracle VirtualBox.
|
||||
|
||||
#### Step 1: Install VirtualBox
|
||||
|
||||
If you haven’t already installed VirtualBox on your system, you can download it from the official website. You can find instructions for Windows, Mac OS and Linux. [Ubuntu users can refer to this detailed tutorial on installing VirtualBox][3].
|
||||
|
||||
![][4]
|
||||
|
||||
[Download VirtualBox][5]
|
||||
|
||||
#### **Step 2: Download the Fedora ISO**
|
||||
|
||||
If you are not familiar with fedora, there are a few images to be aware of.
|
||||
|
||||
[Fedora IoT][6] is to be used for scalable infrastructure, [Fedora workstation][7] is an image with a set of tools oriented for a desktop in a vanilla GNOME desktop environment and [Fedora server][8] as its name reveals, is tailored for a server or data center.
|
||||
|
||||
If GNOME isn’t your first choice, you can download a [spin][9] of Fedora desktop with an alternative desktop environment. For this tutorial, I chose [Fedora 33][10] with the GNOME desktop environment.
|
||||
|
||||
[Download Fedora][11]
|
||||
|
||||
#### Step 3: Create an empty virtual machine and configure it
|
||||
|
||||
Fedora requires a minimum of 20GB disk space & 2GB RAM, to install and run successfully. Although double those amounts is recommended for a smoother user experience. Based on that I will create and configure the virtual machine.
|
||||
|
||||
Start Virtual Box and click on New.
|
||||
|
||||
![Create a new virtual machine][12]
|
||||
|
||||
The most important option to pay attention, is the **type to be set to Linux and the version to Fedora (64-bit)**. If you start typing Fedora at the name prompt, VirtualBox will automatically pick the correct settings for you. Although the name doesn’t have to be Fedora, it can be anything you like.
|
||||
|
||||
_If you have access to 32-bit version only, you need to enable virtualization technology on BIOS, if you have an AMD CPU it is called SVM. Worst-case scenario is that your CPU doesn’t support virtualization technology. If you are not sure, check this first._
|
||||
|
||||
Once you have similar settings with me, click on the create button.
|
||||
|
||||
![Name your VM and assign it at least 3 GB RAM][13]
|
||||
|
||||
As mentioned before, you need at least 20 GB of disk space to be able to install Fedora. I have 32 GB of RAM on my system so I assigned 8 GB here. You should be fine with 3 GB of RAM.
|
||||
|
||||
A word about RAM consumption, the RAM will only be consumed by the virtual machine when you are running it. Otherwise, it will be available for regular usage.
|
||||
|
||||
Make sure that the rest of the settings match the example and click Create.
|
||||
|
||||
![Assign 15-20 GB of disk space in VDI format][14]
|
||||
|
||||
Before you click the start button of your virtual machine, you need to load the ISO as shown below [Optical Drive].
|
||||
|
||||
![Add the Fedora ISO to optical drive storage][15]
|
||||
|
||||
As your virtual hard drive is empty, the virtual machine will boot from this ISO. Think of it as using a live USB or disk for installing Linux.
|
||||
|
||||
![Go to Settings and add ISO as optical drive][16]
|
||||
|
||||
Then, if you have a multi-core CPU it is recommended to assign 2 or more cores for your virtual machine. You may find the CPU cores under the system tab. When you configure your system click ok and start the virtual machine.
|
||||
|
||||
![Optional step: Assign number of CPU cores][17]
|
||||
|
||||
Once you have configured everything, click on the start button to begin the installation.
|
||||
|
||||
#### Step 4: Install Fedora in VirtualBox
|
||||
|
||||
If you have followed the process correctly, when you start the virtual machine you will boot directly from the ISO file. When you see a similar to below screen select Start Fedora, and press the enter key.
|
||||
|
||||
![Fedora running in live environment in virtual machine][18]
|
||||
|
||||
To start the installation dialog box, click on Install to Hard Drive.
|
||||
|
||||
![Click on “install to hard drive”][19]
|
||||
|
||||
Before you proceed to the installation, it is essential to define your keyboard layout, your timezone and finally where the operating system will be installed.
|
||||
|
||||
![Choose keyboard, time and date and then go to Installation Destination][20]
|
||||
|
||||
The partitioning process is straight forward. You made some free space as VDI earlier. It should be automatically recognized.
|
||||
|
||||
Select your disk and set the storage configuration to automatic. Click on Done to go to the previous dialog box.
|
||||
|
||||
![Disk should be automatically recognized][21]
|
||||
|
||||
Once you have configured the above, click on “Begin Installation”.
|
||||
|
||||
![Begin installation of Fedora][22]
|
||||
|
||||
Now you just need to wait for five-six minutes for installation completion. Click on the “Finish installation” button when installation is finished.
|
||||
|
||||
As a last step, you need to power off your system. If you are unfamiliar with the GNOME desktop environment you can do it like so.
|
||||
|
||||
![Turn off Fedora live environment after installation][23]
|
||||
|
||||
You have to manually unload the ISO file that you loaded at the initial steps.
|
||||
|
||||
![Remove Fedora ISO From Optical Drive][24]
|
||||
|
||||
The next time you start the virtual machine with Fedora, you will be prompted to create a user account and set your password for Fedora Linux.
|
||||
|
||||
### Use VirtualBox guest additions for additional features like clipboard sharing, folder sharing and more
|
||||
|
||||
[Guest Additions][25] are designed to be installed inside a virtual machine post installation of the guest operating system. They contain device drivers and system applications that optimize the guest operating system for better performance and usability.
|
||||
|
||||
The Guest Additions ISO file is mounted as a virtual CD-ROM in order to be installed.
|
||||
|
||||
This is a straightforward process. Simply click on the devices tab and then click on “Insert Guest Additions CD image”
|
||||
|
||||
![][26]
|
||||
|
||||
You will be prompted to download the guest additions image, when prompt click on Download.
|
||||
|
||||
![Install VirtualBox Guest Additions][27]
|
||||
|
||||
#### **Shared clipboard**
|
||||
|
||||
At some point you’ll need to move some content between your virtual machine and the host operating system. The shared clipboard/drag and drop support will allow you to copy items on one platform and paste them on the other.
|
||||
|
||||
To enable this feature, choose **Settings** on the VirtualBox home page and follow the instructions as below. I find the **Bidirectional** option the most convenient.
|
||||
|
||||
![Enable clipboard sharing between guest and host systems][28]
|
||||
|
||||
#### **Shared folders**
|
||||
|
||||
There are two types of shares:
|
||||
|
||||
* Permanent shares, that are saved with the Virtual Machine settings.
|
||||
* Transient shares, that are disappear when the Virtual Machine is powered off. These can be created using a checkbox in the VirtualBox Manager.
|
||||
|
||||
|
||||
|
||||
In this tutorial, I will make a permanent shared folder. In the VM settings add the host system folder you want to share and choose the name that you want to appear at your VM.
|
||||
|
||||
![][29]
|
||||
|
||||
The next time you start the virtual machine, the folder should appear as a network drive.
|
||||
|
||||
![][30]
|
||||
|
||||
#### **Better video support**
|
||||
|
||||
While the virtual graphics card which Oracle VirtualBox provides all the basic features, the custom video drivers that are installed with the Guest Additions provide you with extra high and non-standard video modes, as well as accelerated video performance.
|
||||
|
||||
Using Guest Additions, the guest OS’s resolution will dynamically resize as you adjust the VirtualBox window on your computer.
|
||||
|
||||
Finally, Guest Additions can take advantage of your computer’s graphics card. If you’re a gamer or using productivity software in a WM, this makes a huge difference.
|
||||
|
||||
#### USB and Network Devices sharing
|
||||
|
||||
With VirtualBox, users have the ability to use a fully-functional operating system, without having to do the setup on different hardware. However, sharing USB and network devices between the host and guest machine is not as straightforward as it should be.
|
||||
|
||||
To access USB devices, you will need to install [the VirtualBox extension pack][31].
|
||||
|
||||
![Install VirtualBox Extensions pack][32]
|
||||
|
||||
_**This is for Linux only**_ because I am using all this in Linux.
|
||||
|
||||
In order for VirtualBox to have access to the USB subsystem, the user (on host system) running VirtualBox must belong to the vboxuser group. To do this, open up a terminal and issue the following command:
|
||||
|
||||
```
|
||||
sudo usermod -aG vboxusers 'your username'
|
||||
```
|
||||
|
||||
Once you run the command, you should either log out and log back in, or restart your host machine.
|
||||
|
||||
At this step, plug in your USB stick and through your VM settings you should be able to find and add the medium as shown at the example.
|
||||
|
||||
![][33]
|
||||
|
||||
Your USB will be accessible the next time you start your virtual machine.
|
||||
|
||||
![][34]
|
||||
|
||||
### Bonus Tip: Save and export the Virtual Machine so that you can use it later on any system
|
||||
|
||||
You may want to use your virtual machine to another computer or it is time to build a new machine and you need to keep your virtual machine as it is. You can easily export your current setup and import it to another machine at a few easy steps.
|
||||
|
||||
At the VirtualBox home panel, click on file and the export appliance. If you prefer keyboard shortcuts, you can simply click **Ctrl+E**.
|
||||
|
||||
![][35]
|
||||
|
||||
Choose the virtual machine you want to export and click on next.
|
||||
|
||||
![][36]
|
||||
|
||||
The Format option needs some attention. There are three different options of Open Virtualization Format 0.9, 1.0 and 2.0, which can be either ovf or ova extensions.
|
||||
|
||||
With ovf extension, several files will be written separately, compared to ova extension, which combines all the files into one Open Virtualization Format archive.
|
||||
|
||||
The default format, Open Virtualization Format 1.0, should be fine.
|
||||
|
||||
![][37]
|
||||
|
||||
To finish the process, click next and at the next dialog box click export.
|
||||
|
||||
#### Conclusion
|
||||
|
||||
By using a virtual machine you can’t just test an operating system but deploy a fully functioning system, equally comparable to a physical machine. Nowadays, hardware has become so powerful and affordable that most of its power is not being utilized.
|
||||
|
||||
Through virtualization technology, you can use those wasted resources. The need for physical machines is reduced, and consequently the energy consumption is less. You can save money both from hardware and reduced running costs.
|
||||
|
||||
On a larger scale, server virtualization is more of a basic requirement than an advanced concept.
|
||||
|
||||
I hope you found this tutorial helpful in installing Fedora Linux in VirtualBox. If you face any issues, please let me know in the comments.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/install-fedora-in-virtualbox/
|
||||
|
||||
作者:[Dimitrios Savvopoulos][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/dimitrios/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/create-fedora-live-usb-ubuntu/
|
||||
[2]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/install-fedora-in-virtualbox.png?resize=800%2C450&ssl=1
|
||||
[3]: https://itsfoss.com/install-virtualbox-ubuntu/
|
||||
[4]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/05/download-virtulabox.jpg?resize=799%2C294&ssl=1
|
||||
[5]: https://www.virtualbox.org/
|
||||
[6]: https://getfedora.org/en/iot/
|
||||
[7]: https://getfedora.org/en/workstation/
|
||||
[8]: https://getfedora.org/en/server/
|
||||
[9]: https://spins.fedoraproject.org/
|
||||
[10]: https://itsfoss.com/fedora-33/
|
||||
[11]: https://getfedora.org/
|
||||
[12]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/10/0.-create-a-new-vm.png?resize=800%2C550&ssl=1
|
||||
[13]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/10/1-create-vm-fedora.png?resize=800%2C533&ssl=1
|
||||
[14]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/10/2-fedora-vm-disk.png?resize=800%2C533&ssl=1
|
||||
[15]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/fedora-vm-settings-iso.png?resize=800%2C640&ssl=1
|
||||
[16]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/3-fedora-vm-settings2.png?resize=800%2C600&ssl=1
|
||||
[17]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/10/4-fedora-vm-cpu.png?resize=800%2C533&ssl=1
|
||||
[18]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/6-fedora-vm-boot.png?resize=800%2C600&ssl=1
|
||||
[19]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/10/7-fedora-vm-install-1.png?resize=800%2C622&ssl=1
|
||||
[20]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/10/9-fedora-vm-partitioning-2.png?resize=800%2C706&ssl=1
|
||||
[21]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/10-fedora-vm-hdd.png?resize=732%2C645&ssl=1
|
||||
[22]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/12-fedora-vm-installation-1.png?resize=800%2C706&ssl=1
|
||||
[23]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/15-power-off-fedora-gnome.png?resize=800%2C706&ssl=1
|
||||
[24]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/remove-fedora-iso-from-optical-drive.png?resize=800%2C589&ssl=1
|
||||
[25]: https://www.virtualbox.org/manual/ch04.html
|
||||
[26]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/16-Fedora-vm-guest-additions.png?resize=800%2C706&ssl=1
|
||||
[27]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/17-Fedora-vm-guest-additions.png?resize=800%2C686&ssl=1
|
||||
[28]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/19-fedora-vm-shared-clipboard-2.png?resize=800%2C650&ssl=1
|
||||
[29]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/20-fedora-vm-shared-folders-1.png?resize=800%2C650&ssl=1
|
||||
[30]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/22-fedora-vm-shared-folders2-1.png?resize=800%2C547&ssl=1
|
||||
[31]: https://download.virtualbox.org/virtualbox/6.1.16/Oracle_VM_VirtualBox_Extension_Pack-6.1.16.vbox-extpack
|
||||
[32]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/21.-fedora-vm-extension-pack.png?resize=800%2C600&ssl=1
|
||||
[33]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/25.-fedora-vm-usb-1.png?resize=800%2C527&ssl=1
|
||||
[34]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/26.-fedora-vm-usb-1.png?resize=800%2C578&ssl=1
|
||||
[35]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/23.-fedora-vm-export.png?resize=800%2C600&ssl=1
|
||||
[36]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/24.-fedora-vm-export-1.png?resize=800%2C545&ssl=1
|
||||
[37]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/25.-fedora-vm-export-800x545.png?resize=800%2C545&ssl=1
|
||||
@@ -0,0 +1,87 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Day 5: drawing lots of faces with sketch-rnn)
|
||||
[#]: via: (https://jvns.ca/blog/2020/11/16/day-5--lots-of-faces-with-sketch-rnn/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
Day 5: drawing lots of faces with sketch-rnn
|
||||
======
|
||||
|
||||
Hello! This week it’s generative art week at RC, and I thought it would be fun to generate drawings of faces.
|
||||
|
||||
Someone suggested the [Google Quickdraw][1] dataset, which has a lot of pictures of faces. And even though I think most of the faces in there are not really that interesting, I really quite like some of them, like these two:
|
||||
|
||||
![][2] ![][3]
|
||||
|
||||
So that seems like somewhere to start!
|
||||
|
||||
### step 1: get the sketch-rnn model
|
||||
|
||||
sketch-rnn is an RNN trained on the quickdraw dataset that generates line drawings. You can see it in action in Monica Dinculescu’s very fun [magic sketchpad][4] demo here – you start making a drawing, and it’ll complete you drawing as a cat / bridge / whatever you want.
|
||||
|
||||
I figured that would be a fun place to start, and [ml5js][5] has a [tutorial showing how to write Javascript code to draw things with sketch-rnn][6], which I followed.
|
||||
|
||||
### step 2: make the tutorial code use async/await
|
||||
|
||||
The ml5js example had a bunch of global variables and callbacks and I found it difficult to work with, so I spent a while refactoring it to use async/await so that I could play around with it more easily. This took a while but I got it to work.
|
||||
|
||||
### step 3: make sketch-rnn draw lots of faces and put them into a gallery
|
||||
|
||||
I started out with making a more interactive website, but decided to instead do something really simple to start: just get the model to draw a lot of faces and see how I felt about them.
|
||||
|
||||
Here’s the resulting (very janky, not responsive) website I made, which draws faces and then puts them into a little “gallery” on the right: [lots of sketch-rnn faces][7]. You can see it “live” drawing the faces which is fun.
|
||||
|
||||
The set of images that comes out looks something like this:
|
||||
|
||||
![][8]
|
||||
|
||||
I don’t really like _any_ of these faces, but it’s a start! It’s also very slow on my 2015 laptop, but faster on the iPad. I didn’t spend a lot of time profiling it, but it seems to spend a lot of time in some function with `lstm` in its name – I don’t know what an LSTM is exactly but I know it’s a component of an RNN, so I guess (as you’d expect) it just has a lot of math to do in Javascript to calculate the next line to draw and that’s slow.
|
||||
|
||||
### next step: maybe find out if sketch-rnn can tell the difference between “interesting” and “boring” faces
|
||||
|
||||
I think that this face:
|
||||
|
||||
![][2]
|
||||
|
||||
is a lot more interesting than this face:
|
||||
|
||||
![][9]
|
||||
|
||||
Can I convince the neural network to distinguish between faces that I think are ‘interesting’ and ‘boring’ and maybe only generate more “interesting” faces? We’ll see! Right now I am stuck on trying to get a pre-trained model loaded into Python, so there’s a long way to go.
|
||||
|
||||
I did find someone who’d done something kind of similar, on [bad flamingos vs good flamingos][10] in the quickdraw dataset.
|
||||
|
||||
I still don’t really know anything about RNNs, but maybe if I can answer this question I will learn something about them.
|
||||
|
||||
### also there’s a refrigerator poetry forum
|
||||
|
||||
Here’s that refrigerator poetry forum I was talking about last week: <https://refrigerator-poetry-forum.herokuapp.com/>. You can write magnet poetry-style poems on a refrigerator. People wrote some charming poems and I’m happy with it. I think I might use Rails for another project in the future.
|
||||
|
||||
Hopefully people won’t abuse it, if there’s abuse I’ll just take it off the internet probably.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2020/11/16/day-5--lots-of-faces-with-sketch-rnn/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://quickdraw.withgoogle.com/data/face
|
||||
[2]: https://jvns.ca/images/face1.jpg
|
||||
[3]: https://jvns.ca/images/face2.jpg
|
||||
[4]: https://magic-sketchpad.glitch.me/
|
||||
[5]: https://learn.ml5js.org
|
||||
[6]: https://github.com/ml5js/ml5-library/tree/main/examples/javascript/SketchRNN/SketchRNN_interactive
|
||||
[7]: https://lots-of-sketchrnn-faces.netlify.app/
|
||||
[8]: https://jvns.ca/images/faces.png
|
||||
[9]: https://jvns.ca/images/boring-face.png
|
||||
[10]: https://colinmorris.github.io/blog/bad_flamingos
|
||||
@@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (MjSeven)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Podman with capabilities on Fedora)
|
||||
[#]: via: (https://fedoramagazine.org/podman-with-capabilities-on-fedora/)
|
||||
[#]: author: (shiwanibiradar https://fedoramagazine.org/author/shiwanibiradar/)
|
||||
|
||||
Podman with capabilities on Fedora
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
Containerization is a booming technology. As many as seventy-five percent of global organizations could be running some type of containerization technology in the near future. Since widely used technologies are more likely to be targeted by hackers, securing containers is especially important. This article will demonstrate how [POSIX capabilities][2] are used to secure Podman containers. Podman is the default container management tool in RHEL8.
|
||||
|
||||
### Determine the Podman container’s privilege mode
|
||||
|
||||
Containers run in either privileged or unprivileged mode. In privileged mode, [the container uid 0 is mapped to the host’s uid 0][3]. For some use cases, unprivileged containers [lack sufficient access][4] to the resources of the host machine. Technologies and techniques including Mandatory Access Control (apparmor, SELinux), seccomp filters, dropping of capabilities, and namespaces help to secure containers regardless of their mode of operation.
|
||||
|
||||
**To determine the privilege mode from outside the container:**
|
||||
|
||||
```
|
||||
$ podman inspect --format="{{.HostConfig.Privileged}}" <container id>
|
||||
```
|
||||
|
||||
If the above command returns _true_ then the container is running in privileged mode. If it returns _false_ then the container is running in unprivileged mode.
|
||||
|
||||
**To determine the privilege mode from inside the container:**
|
||||
|
||||
```
|
||||
$ ip link add dummy0 type dummy
|
||||
```
|
||||
|
||||
If this command allows you to create an interface then you are running a privileged container. Otherwise you are running an unprivileged container.
|
||||
|
||||
### Capabilities
|
||||
|
||||
Namespaces isolate a container’s processes from arbitrary access to the resources of its host and from access to the resources of other containers running on the same host. Processes within _privileged_ containers, however, might still be able to do things like alter the IP routing table, trace arbitrary processes, and load kernel modules. Capabilities allow one to apply finer-grained restrictions on what resources the processes within a container can access or alter; even when the container is running in privileged mode. Capabilities also allow one to assign privileges to an unprivileged container that it would not otherwise have.
|
||||
|
||||
For example, to add the _NET_ADMIN_ capability to an unprivileged container so that a network interface can be created inside of the container, you would run _podman_ with parameters similar to the following:
|
||||
|
||||
```
|
||||
[root@vm1 ~]# podman run -it --cap-add=NET_ADMIN centos
|
||||
[root@b27fea33ccf1 /]# ip link add dummy0 type dummy
|
||||
[root@b27fea33ccf1 /]# ip link
|
||||
```
|
||||
|
||||
The above commands demonstrate a _dummy0_ interface being created in an unprivileged container. Without the _NET_ADMIN_ capability, an unprivileged container would not be able to create an interface. The above commands demonstrate how to grant a capability to an unprivileged container.
|
||||
|
||||
Currently, there are about [39 capabilities][5] that can be granted or denied. Privileged containers are granted many capabilities by default. It is advisable to drop unneeded capabilities from privileged containers to make them more secure.
|
||||
|
||||
**To drop all capabilities from a container:**
|
||||
|
||||
```
|
||||
$ podman run -it -d --name mycontainer --cap-drop=all centos
|
||||
```
|
||||
|
||||
**To list a container’s capabilities:**
|
||||
|
||||
```
|
||||
$ podman exec -it 48f11d9fa512 capsh --print
|
||||
```
|
||||
|
||||
The above command should show that no capabilities are granted to the container.
|
||||
|
||||
**Refer to the _capabilities_ man page for a complete list of capabilities:**
|
||||
|
||||
```
|
||||
$ man capabilities
|
||||
```
|
||||
|
||||
**Use the _capsh_ command to list the capabilities you currently possess:**
|
||||
|
||||
```
|
||||
$ capsh --print
|
||||
```
|
||||
|
||||
As another example, the below command demonstrates dropping the _NET_RAW_ capability from a container. Without the _NET_RAW_ capability, servers on the internet cannot be pinged from within the container.
|
||||
|
||||
```
|
||||
$ podman run -it --name mycontainer1 --cap-drop=net_raw centos
|
||||
>>> ping google.com (will output error, operation not permitted)
|
||||
```
|
||||
|
||||
As a final example, if your container were to only need the _SETUID_ and _SETGID_ capabilities, you could achieve such a permission set by dropping all capabilities and then re-adding only those two.
|
||||
|
||||
```
|
||||
$ podman run -d --cap-drop=all --cap-add=setuid --cap-add=setgid fedora sleep 5 > /dev/null; pscap | grep sleep
|
||||
```
|
||||
|
||||
The _pscap_ command shown above should show the capabilities that have been granted to the container.
|
||||
|
||||
I hope you enjoyed this brief exploration of how capabilities are used to secure Podman containers.
|
||||
|
||||
Thank You!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/podman-with-capabilities-on-fedora/
|
||||
|
||||
作者:[shiwanibiradar][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/shiwanibiradar/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2018/10/podman-816x345.jpg
|
||||
[2]: https://www.linuxjournal.com/magazine/making-root-unprivileged
|
||||
[3]: https://linuxcontainers.org/lxc/security/#privileged-containers
|
||||
[4]: https://github.com/containers/podman/blob/master/rootless.md
|
||||
[5]: https://man7.org/linux/man-pages/man7/capabilities.7.html
|
||||
@@ -1,272 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Unlock encrypted disks on Linux automatically)
|
||||
[#]: via: (https://opensource.com/article/20/11/nbde-linux)
|
||||
[#]: author: (Curt Warfield https://opensource.com/users/rcurtiswarfield)
|
||||
|
||||
Unlock encrypted disks on Linux automatically
|
||||
======
|
||||
Open encrypted disks without having to manually enter a passcode by
|
||||
using Network-Bound Disk Encryption (NBDE).
|
||||
![Lock][1]
|
||||
|
||||
From a security viewpoint, it's important to encrypt your sensitive data to protect it from prying eyes and hackers. Linux Unified Key Setup ([LUKS][2]) is a great tool and a common standard for Linux disk encryption. Because it stores all pertinent setup information in the partition header, it makes migrating data easy.
|
||||
|
||||
To configure encrypted disks or partitions with LUKS, you will need to use the [cryptsetup][3] utility. Unfortunately, one of the downsides of encrypting your disks is that you have to manually provide the password every time the system is rebooted or the disk is remounted.
|
||||
|
||||
However, Network-Bound Disk Encryption (NBDE) can automatically and securely unlock encrypted disks without any user intervention. It is available in several Linux distributions, beginning with Red Hat Enterprise Linux 7.4, CentOS 7.4, and Fedora 24, and in later versions of each.
|
||||
|
||||
NBDE is implemented with the following technologies:
|
||||
|
||||
* **[Clevis framework][4]:** A pluggable framework tool that automatically decrypts and unlocks LUKS volumes
|
||||
* **[Tang server][5]:** A service for binding cryptographic keys to network presence
|
||||
|
||||
|
||||
|
||||
Tang provides the encryption keys to the Clevis client. According to Tang's developers, this provides a secure, stateless, anonymous alternative to key escrow services.
|
||||
|
||||
Because NBDE uses the client-server architecture, you must configure both the client and the server. You can use a virtual machine on your local network for your Tang server.
|
||||
|
||||
### Server installation
|
||||
|
||||
Install Tang using sudo:
|
||||
|
||||
|
||||
```
|
||||
`sudo yum install tang -y`
|
||||
```
|
||||
|
||||
Enable the Tang server:
|
||||
|
||||
|
||||
```
|
||||
`sudo systemctl enable tangd.socket --now`
|
||||
```
|
||||
|
||||
The Tang server works on port 80 and must be added to firewalld. Add the appropriate firewalld rule:
|
||||
|
||||
|
||||
```
|
||||
sudo firewall-cmd --add-port=tcp/80 --perm
|
||||
sudo firewall-cmd --reload
|
||||
```
|
||||
|
||||
The server should now be installed.
|
||||
|
||||
### Client installation
|
||||
|
||||
For this example, assume you have added a new 1GB disk named `/dev/vdc` to your system.
|
||||
|
||||
Create the primary partition using fdisk or parted:
|
||||
|
||||
|
||||
```
|
||||
sudo fdisk /dev/vdc
|
||||
```
|
||||
|
||||
Complete the following steps to install the client.
|
||||
|
||||
|
||||
```
|
||||
Welcome to fdisk (util-linux 2.23.2).
|
||||
|
||||
Changes will remain in memory only, until you decide to write them.
|
||||
Be careful before using the write command.
|
||||
|
||||
Device does not contain a recognized partition table
|
||||
Building a new DOS disklabel with disk identifier 0x4a6812d4.
|
||||
|
||||
Command (m for help):
|
||||
```
|
||||
|
||||
Enter **n** to create the new partition:
|
||||
|
||||
|
||||
```
|
||||
Partition type:
|
||||
p primary (0 primary, 0 extended, 4 free)
|
||||
e extended
|
||||
Select (default p):
|
||||
```
|
||||
|
||||
Hit the **Enter** key to select the primary partition:
|
||||
|
||||
|
||||
```
|
||||
Using default response p
|
||||
Partition number (1-4, default 1):
|
||||
```
|
||||
|
||||
Hit the **Enter** key to select the default partition number:
|
||||
|
||||
|
||||
```
|
||||
First sector (2048-2097151, default 2048):
|
||||
Using default value 2048
|
||||
Last sector, +sectors or +size{K,M,G} (2048-2097151, default 2097151):
|
||||
```
|
||||
|
||||
Hit the **Enter** key to select the last sector:
|
||||
|
||||
|
||||
```
|
||||
Using default value 2097151
|
||||
Partition 1 of type Linux and of size 1023 MiB is set
|
||||
|
||||
Command (m for help): wq
|
||||
```
|
||||
|
||||
Type **wq** to save the changes and exit fdisk:
|
||||
|
||||
|
||||
```
|
||||
The partition table has been altered!
|
||||
|
||||
Calling ioctl() to re-read partition table.
|
||||
Syncing disks.
|
||||
```
|
||||
|
||||
Run `partprobe` to inform the system of the partition table changes:
|
||||
|
||||
|
||||
```
|
||||
`sudo partprobe`
|
||||
```
|
||||
|
||||
Install the cryptsetup package using sudo:
|
||||
|
||||
|
||||
```
|
||||
`sudo yum install cryptsetup -y`
|
||||
```
|
||||
|
||||
Use the `cryptsetup luksFormat` command to encrypt the disk. You will need to type **YES** when prompted and also choose and enter a passphrase to encrypt the disk:
|
||||
|
||||
|
||||
```
|
||||
sudo cryptsetup luksFormat /dev/vdc1
|
||||
WARNING!
|
||||
========
|
||||
This will overwrite data on /dev/vdc1 irrevocably.
|
||||
|
||||
Are you sure? (Type uppercase yes):
|
||||
|
||||
Enter passphrase for /dev/vdc1:
|
||||
Verify passphrase:
|
||||
```
|
||||
|
||||
Use the `cryptsetup luksOpen` command to map the encrypted partition to a logical device. For example, use `encryptedvdc1` as the name. You will also need to enter the passphrase again:
|
||||
|
||||
|
||||
```
|
||||
sudo cryptsetup luksOpen /dev/vdc1 encryptedvdc1
|
||||
Enter passphrase for /dev/vdc1:
|
||||
```
|
||||
|
||||
The encrypted partition is now available at `/dev/mapper/encryptedvdc1`.
|
||||
|
||||
Create an XFS filesystem on the encrypted partition:
|
||||
|
||||
|
||||
```
|
||||
`sudo mkfs.xfs /dev/mapper/encryptedvdc1`
|
||||
```
|
||||
|
||||
Create a directory for mounting the encrypted partition:
|
||||
|
||||
|
||||
```
|
||||
`sudo mkdir /encrypted`
|
||||
```
|
||||
|
||||
Use the `cryptsetup luksClose` command to lock the partition:
|
||||
|
||||
|
||||
```
|
||||
`cryptsetup luksClose encryptedvdc1`
|
||||
```
|
||||
|
||||
Install the Clevis packages using sudo:
|
||||
|
||||
|
||||
```
|
||||
`sudo yum install clevis clevis-luks clevis-dracut -y`
|
||||
```
|
||||
|
||||
Modify /etc/crypttab to open the encrypted volume at boot time:
|
||||
|
||||
|
||||
```
|
||||
`sudo vim /etc/crypttab`
|
||||
```
|
||||
|
||||
Add the following line:
|
||||
|
||||
|
||||
```
|
||||
`encryptedvdc1 /dev/vdc1 none _netdev`
|
||||
```
|
||||
|
||||
Modify /etc/fstab to automatically mount the encrypted volume during a reboot or at boot time:
|
||||
|
||||
|
||||
```
|
||||
`sudo vim /etc/fstab`
|
||||
```
|
||||
|
||||
Add the following line:
|
||||
|
||||
|
||||
```
|
||||
`/dev/mapper/encryptedvdc1 /encrypted xfs _netdev 1 2`
|
||||
```
|
||||
|
||||
For this example, assume the Tang server's IP address is `192.168.1.20`. You can also use the hostname or domain if you prefer.
|
||||
|
||||
Run the following `clevis` command:
|
||||
|
||||
|
||||
```
|
||||
sudo clevis bind luks -d /dev/vdc1 tang '{"url":"<http://192.168.1.20"}>'
|
||||
The advertisement contains the following signing keys:
|
||||
|
||||
rwA2BAITfYLuyNiIeYUMBzkhk7M
|
||||
|
||||
Do you wish to trust these keys? [ynYN] Y
|
||||
Enter existing LUKS password:
|
||||
```
|
||||
|
||||
Type **Y** to accept the keys for the Tang server and provide the existing LUKS password for the initial setup.
|
||||
|
||||
Enable clevis-luks-askpass.path via systemctl in order to prevent being prompted for the passphrase for non-root partitions.
|
||||
|
||||
|
||||
```
|
||||
`sudo systemctl enable clevis-luks-askpass.path`
|
||||
```
|
||||
|
||||
The client is installed. Now, whenever you reboot the server, the encrypted disk should automatically be decrypted and mounted by retrieving the keys from the Tang server.
|
||||
|
||||
If the Tang server is unavailable for any reason, you'll need to provide the passphrase manually in order to decrypt and mount the partition.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/nbde-linux
|
||||
|
||||
作者:[Curt Warfield][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/rcurtiswarfield
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/security-lock-password.jpg?itok=KJMdkKum (Lock)
|
||||
[2]: https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup
|
||||
[3]: https://gitlab.com/cryptsetup/cryptsetup
|
||||
[4]: https://github.com/latchset/clevis
|
||||
[5]: https://github.com/latchset/tang
|
||||
250
sources/tech/20201117 Getting started with btrfs for Linux.md
Normal file
250
sources/tech/20201117 Getting started with btrfs for Linux.md
Normal file
@@ -0,0 +1,250 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Getting started with btrfs for Linux)
|
||||
[#]: via: (https://opensource.com/article/20/11/btrfs-linux)
|
||||
[#]: author: (Alan Formy-Duval https://opensource.com/users/alanfdoss)
|
||||
|
||||
Getting started with btrfs for Linux
|
||||
======
|
||||
The B-tree filesystem is a filesystem and volume manager rolled into
|
||||
one. It offers a lot of promise for delivering an advanced filesystem
|
||||
feature set to Linux.
|
||||
![Filing cabinet for organization][1]
|
||||
|
||||
Btrfs has been available for Linux for several years, so you may already be familiar with it. If not, you may have questions about it, especially if you use Fedora Workstation (Btrfs is now its default filesystem). This article aims to help you get familiar with it and its advanced features, such as [copy-on-write][2] and [checksums][3].
|
||||
|
||||
Btrfs, short for B-Tree Filesystem, is actually a filesystem and volume manager rolled into one. It's often seen as a response to ZFS, introduced in Sun Microsystem's Solaris OS back in 2005, now largely replaced by an open source implementation called OpenZFS. Ubuntu Linux and FreeBSD often feature OpenZFS. Other examples with similar features are Red Hat's Stratis and the Linux Logical Volume Manager (LVM).
|
||||
|
||||
### Setup
|
||||
|
||||
To try Btrfs, I [downloaded][4] the Fedora 33 Workstation ISO file and installed it into a new virtual machine (VM). The installation process has not changed from previous versions. I did not customize any settings, including drive partitioning and formatting, to maintain an accurate "out of the box" setup for this tutorial. Once the VM was up and running, I installed and ran the GNOME Partition Editor ([GParted][5]) for a nice, factory-fresh view of the drive layout.
|
||||
|
||||
![GParted's view of Btrfs on Fedora 33 Workstation using GParted][6]
|
||||
|
||||
(Alan Formy-Duvall, [CC BY-SA 4.0][7])
|
||||
|
||||
From this point, it's not much different from what you're used to; in fact, you can use the system normally, and you might not even notice that the filesystem is Btrfs. However, having this new default enables you to leverage several cool features.
|
||||
|
||||
### Examine the Btrfs filesystem
|
||||
|
||||
I am not aware of any Btrfs-specific graphical tools, although some of its functions have been incorporated into existing disk-management tools.
|
||||
|
||||
From the command line, you can get a closer look at the Btrfs format:
|
||||
|
||||
|
||||
```
|
||||
# btrfs filesystem show
|
||||
Label: 'fedora_localhost-live' uuid: f2bb02f9-5c41-4c91-8eae-827a801ee58a
|
||||
Total devices 1 FS bytes used 6.36GiB
|
||||
devid 1 size 10.41GiB used 8.02GiB path /dev/vda3
|
||||
```
|
||||
|
||||
### Change Btrfs labels
|
||||
|
||||
The first thing I noticed was the filesystem label set by the installer: `fedora_localhost-live`. This is inaccurate because it is now an installed system and no longer a [live CD][8]. So I changed it using the `btrfs filesystem label` command.
|
||||
|
||||
Changing a Btrfs filesystem label is simple:
|
||||
|
||||
|
||||
```
|
||||
# btrfs filesystem label /
|
||||
fedora_localhost-live
|
||||
# btrfs filesystem label / fedora33workstation
|
||||
# btrfs filesystem label /
|
||||
fedora33workstation
|
||||
```
|
||||
|
||||
### Manage Btrfs subvolumes
|
||||
|
||||
A subvolume appears to be a standard directory that can be managed by Btrfs. There are several subvolumes on my new Fedora 33 Workstation:
|
||||
|
||||
|
||||
```
|
||||
# btrfs subvolume list /
|
||||
ID 256 gen 2458 top level 5 path home
|
||||
ID 258 gen 2461 top level 5 path root
|
||||
ID 265 gen 1593 top level 258 path var/lib/machines
|
||||
```
|
||||
|
||||
Create a new subvolume using the `btrfs subvolume create` command, or delete a subvolume with `btrfs subvolume delete`:
|
||||
|
||||
|
||||
```
|
||||
# btrfs subvolume create /opt/foo
|
||||
Create subvolume '/opt/foo'
|
||||
# btrfs subvolume list /
|
||||
ID 256 gen 2884 top level 5 path home
|
||||
ID 258 gen 2888 top level 5 path root
|
||||
ID 265 gen 1593 top level 258 path var/lib/machines
|
||||
ID 276 gen 2888 top level 258 path opt/foo
|
||||
# btrfs subvolume delete /opt/foo
|
||||
Delete subvolume (no-commit): '/opt/foo'
|
||||
```
|
||||
|
||||
Subvolumes allow actions like setting a quota, taking a snapshot, and replicating to other locations and hosts. How can system administrators take advantage of these capabilities? How about for user home directories?
|
||||
|
||||
#### Add a user
|
||||
|
||||
As has been the case since olden times, adding a new user account creates a home directory for the account to use:
|
||||
|
||||
|
||||
```
|
||||
# useradd student1
|
||||
# getent passwd student1
|
||||
student1❌1006:1006::/home/student1:/bin/bash
|
||||
# ls -l /home
|
||||
drwx------. 1 student1 student1 80 Oct 29 00:21 student1
|
||||
```
|
||||
|
||||
Traditionally, a user's home directory is a subdirectory of `/home`. Ownership and privileges are tailored to the owner, but there are no special functions for managing them. The enterprise server environment is another scenario. Often, a directory is reserved for use by a particular application and its user. You can take advantage of Btrfs to manage and apply constraints to these directories.
|
||||
|
||||
To accommodate Btrfs subvolumes as user homes, there is a new option to the `useradd` command: `--btrfs-subvolume-home`. Although the man pages have not been updated (as of this writing), you can see the option by running `useradd --help`. By passing this option when adding a new user, a new Btrfs subvolume will be created. It functions just like the `-d` option does for creating a regular directory:
|
||||
|
||||
|
||||
```
|
||||
# useradd --btrfs-subvolume-home student2
|
||||
Create subvolume '/home/student2'
|
||||
```
|
||||
|
||||
Verify the user with `getent passwd student2`, and it will appear normal. However, run the `btrfs subvolume` command to list subvolumes, and you will see something interesting: the new user's home directory!
|
||||
|
||||
|
||||
```
|
||||
# btrfs subvolume list /
|
||||
ID 256 gen 2458 top level 5 path home
|
||||
ID 258 gen 2461 top level 5 path root
|
||||
ID 265 gen 1593 top level 258 path var/lib/machines
|
||||
ID 272 gen 2459 top level 256 path home/student2
|
||||
```
|
||||
|
||||
Explore the second scenario of an enterprise server environment. Suppose you need to install a [WildFly][9] server in `/opt` and deploy a Java web application. Often, your first step is to create a `wildfly` user. Do this using the new `--btrfs-subvolume-home` option along with the `-b` option to specify `/opt` as the base directory:
|
||||
|
||||
|
||||
```
|
||||
# useradd -b /opt --btrfs-subvolume-home wildfly
|
||||
Create subvolume '/opt/wildfly'
|
||||
```
|
||||
|
||||
Now, the `wildfly` user can log in and complete the installation in `/opt/wildfly`.
|
||||
|
||||
#### Delete a user
|
||||
|
||||
When you delete a user, sometimes you want to delete that user's files and the home directory at the same time. The `userdel` command has the `-r` option for this, and it also deletes Btrfs subvolumes:
|
||||
|
||||
|
||||
```
|
||||
# userdel -r student2
|
||||
Delete subvolume (commit): '/home/student2'
|
||||
```
|
||||
|
||||
#### Set disk-usage quotas
|
||||
|
||||
In one of my computer science classes, a student ran a C program that went out of control and wrote to the disk until the entire `/home` was filled on the department's Unix system! The server became unavailable until the admin killed the runaway process and cleared some space. The same is true for the scenario above; that Wildfly enterprise application will have a growing number of log files and content stores for its users. How can you prevent a server from grinding to a halt because the disk has filled up? Setting disk-usage constraints is a good idea. Fortunately, Btrfs supports this by way of quotas.
|
||||
|
||||
There are several steps required to configure quotas. The first step is to enable `quota` on the Btrfs filesystem:
|
||||
|
||||
|
||||
```
|
||||
`# btrfs quota enable /`
|
||||
```
|
||||
|
||||
Make sure you know each subvolume's quota group (qgroup) ID number, which is displayed by the `btrfs subvolume list` command. Each subvolume needs an associated qgroup based on its ID number. This can be done on an individual basis with `btrfs qgroup create`, but, conveniently, the Btrfs wiki provides the following command to expedite creating qgroups for subvolumes on a filesystem:
|
||||
|
||||
|
||||
```
|
||||
`>btrfs subvolume list \<path> | cut -d' ' -f2 | xargs -I{} -n1 btrfs qgroup destroy 0/{} \<path>`
|
||||
```
|
||||
|
||||
In a freshly installed Fedora 33 workstation system, you are operating on the root filesystem path, `/`. Substitute `\<path>` with the root path:
|
||||
|
||||
|
||||
```
|
||||
`# btrfs subvolume list / | cut -d' ' -f2 | xargs -I{} -n1 btrfs qgroup create 0/{} /`
|
||||
```
|
||||
|
||||
Then run `btrfs quota rescan` and take a look at the new qgroups:
|
||||
|
||||
|
||||
```
|
||||
# btrfs quota rescan /
|
||||
quota rescan started
|
||||
# btrfs qgroup show /
|
||||
qgroupid rfer excl
|
||||
\-------- ---- ----
|
||||
0/5 16.00KiB 16.00KiB
|
||||
0/256 272.04MiB 272.04MiB
|
||||
0/258 6.08GiB 6.08GiB
|
||||
0/265 16.00KiB 16.00KiB
|
||||
0/271 16.00KiB 16.00KiB
|
||||
0/273 16.00KiB 16.00KiB
|
||||
```
|
||||
|
||||
Now you can assign a quota to one of the qgroups, which, in turn, is applied to its associated subvolume. So, if you want to limit student3's home directory usage to 1GB, use the `btrfs qgroup limit` command:
|
||||
|
||||
|
||||
```
|
||||
`# btrfs qgroup limit 1G /home/student3`
|
||||
```
|
||||
|
||||
Confirm the quota for the specific subvolume:
|
||||
|
||||
|
||||
```
|
||||
# btrfs qgroup show -reF /home/student3
|
||||
qgroupid rfer excl max_rfer max_excl
|
||||
\-------- ---- ---- -------- --------
|
||||
0/271 16.00KiB 16.00KiB 1.00GiB none
|
||||
```
|
||||
|
||||
Slightly different options will show all qgroups and any quotas that are set:
|
||||
|
||||
|
||||
```
|
||||
# btrfs qgroup show -re /
|
||||
qgroupid rfer excl max_rfer max_excl
|
||||
\-------- ---- ---- -------- --------
|
||||
0/5 16.00KiB 16.00KiB none none
|
||||
0/256 272.04MiB 272.04MiB none none
|
||||
0/258 6.08GiB 6.08GiB none none
|
||||
0/265 16.00KiB 16.00KiB none none
|
||||
0/271 16.00KiB 16.00KiB 1.00GiB none
|
||||
0/273 16.00KiB 16.00KiB none none
|
||||
```
|
||||
|
||||
### Other features
|
||||
|
||||
These examples provide some idea of Btrfs' features. Run `btrfs --help` to see the full list of commands. Many other notable capabilities exist; for instance, snapshots and send/receive are two worth learning.
|
||||
|
||||
### Final thoughts
|
||||
|
||||
Btrfs offers a lot of promise for delivering an advanced filesystem feature set to Linux. It wasn't the first; I credit ZFS for my introduction to this type of filesystem some 15 years ago, but Btrfs is fully open source and unencumbered by patents.
|
||||
|
||||
I advise starting with a virtual machine or spare system if you want to explore this filesystem.
|
||||
|
||||
I would like to see some graphical management utilities produced for system administrators who like to operate in the GUI world. Fortunately, Btrfs has strong development activity, as evidenced by the Fedora project's decision to make it default on Workstation 33.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/btrfs-linux
|
||||
|
||||
作者:[Alan Formy-Duval][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/alanfdoss
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/files_documents_organize_letter.png?itok=GTtiiabr (Filing cabinet for organization)
|
||||
[2]: https://en.wikipedia.org/wiki/Copy-on-write
|
||||
[3]: https://en.wikipedia.org/wiki/Checksum
|
||||
[4]: https://getfedora.org/en/workstation/download/
|
||||
[5]: https://gparted.org/
|
||||
[6]: https://opensource.com/sites/default/files/uploads/gparted_btrfs.png (GParted's view of Btrfs on Fedora 33 Workstation using GParted)
|
||||
[7]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[8]: https://en.wikipedia.org/wiki/Live_CD
|
||||
[9]: https://www.wildfly.org/
|
||||
503
sources/tech/20201117 How to upgrade to Terraform 0.12.md
Normal file
503
sources/tech/20201117 How to upgrade to Terraform 0.12.md
Normal file
@@ -0,0 +1,503 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to upgrade to Terraform 0.12)
|
||||
[#]: via: (https://opensource.com/article/20/11/update-terraform)
|
||||
[#]: author: (Jessica Cherry https://opensource.com/users/cherrybomb)
|
||||
|
||||
How to upgrade to Terraform 0.12
|
||||
======
|
||||
Updating your environment to Terraform 0.12 is not for the faint of
|
||||
heart, but this how-to will make it less painful.
|
||||
![Green graph of measurements][1]
|
||||
|
||||
In [getting started with Terraform][2], I used Terraform version 0.11. As some readers pointed out, this version lacks some significant features, so in this article, I'll explain how to update Terraform to the more feature-rich version 0.12.
|
||||
|
||||
You may be surprised to learn that many people still use Terraform 0.11, including large organizations and stubborn users who like to stay on tried-and-true technology. Converting from Terraform 0.11 to 0.12 can be very complex. If you want to take advantage of the newer features but think you're not ready to update, this article should help make the conversion easier.
|
||||
|
||||
In this article, I'll use the code from my "getting started" article and the [tfenv][3] tool, which enables you to use different versions of Terraform on the same machine. I'll also assume that you're familiar with two versions of Terraform (the one you're using, and the one you're migrating to), and how to use the `terraform` command in general.
|
||||
|
||||
### Code changes needed for version 12
|
||||
|
||||
Some things work in Terraform version 0.11 that do not work in version 0.12. Here is an example of code I used in my previous article:
|
||||
|
||||
|
||||
```
|
||||
resource "kubernetes_namespace" "1-minikube-namespace" {
|
||||
metadata {
|
||||
name = "my-first-terraform-namespace"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
As one reader pointed out, this code block does not work in version 0.12 due to changes in the way the latest Terraform works. This is a simple example, and it gets more complicated. Here are some examples of how much things may need to change in a production environment.
|
||||
|
||||
The new Terraform needs slightly different syntax and structure. For starters, add a `vars.tf` file:
|
||||
|
||||
|
||||
```
|
||||
variable "namespace" {
|
||||
type = "string"
|
||||
default = "helloworld"
|
||||
}
|
||||
|
||||
variable "cluster" {
|
||||
type = "string"
|
||||
default = "minikube"
|
||||
}
|
||||
```
|
||||
|
||||
Then, change parts of the `main.tf` file to incorporate the new `vars.tf` file. The Kubernetes provider now looks like this:
|
||||
|
||||
|
||||
```
|
||||
provider "kubernetes" {
|
||||
config_context_cluster = "${var.cluster}"
|
||||
}
|
||||
```
|
||||
|
||||
Here is the revised namespace resource:
|
||||
|
||||
|
||||
```
|
||||
resource "kubernetes_namespace" "1-minikube-namespace" {
|
||||
metadata {
|
||||
name = "${var.namespace}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Finally, the changed [Helm provider][4]:
|
||||
|
||||
|
||||
```
|
||||
provider "helm" {
|
||||
kubernetes {
|
||||
config_context_cluster = "${var.cluster}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Beware! These small changes will matter when switching between versions.
|
||||
|
||||
### Deploy before conversion
|
||||
|
||||
Before moving forward, [set up tfenv][5] to use the correct version of Terraform:
|
||||
|
||||
|
||||
```
|
||||
jess@Athena:~/terraform_doc$ tfenv list
|
||||
0.12.29
|
||||
0.11.15-oci
|
||||
jess@Athena:~/terraform_doc$ tfenv use 0.11.15-oci
|
||||
Switching default version to v0.11.15-oci
|
||||
Switching completed
|
||||
jess@Athena:~/terraform_doc$ terraform --version
|
||||
Terraform v0.11.15-oci
|
||||
\+ provider.helm v1.2.2
|
||||
\+ provider.kubernetes v1.11.2
|
||||
|
||||
Your version of Terraform is out of date! The latest version
|
||||
is 0.xx.y. You can update by downloading from [www.terraform.io/downloads.html][6]
|
||||
```
|
||||
|
||||
If you (like me) have done other work with Terraform after using the code in my previous Terraform article, you need to redeploy everything. Set up the Minikube cluster for this Terraform deployment by starting a new, clean cluster:
|
||||
|
||||
|
||||
```
|
||||
$ minikube delete
|
||||
🔥 Deleting "minikube" in kvm2 ...
|
||||
💀 Removed all traces of the "minikube" cluster.
|
||||
jess@Athena:~/terraform_doc$ minikube start
|
||||
😄 minikube v1.14.0 on Ubuntu 18.04
|
||||
```
|
||||
|
||||
After the cluster is set up, you can deploy your modified Terraform code. Start with the `init` command:
|
||||
|
||||
|
||||
```
|
||||
$ terraform init
|
||||
|
||||
Initializing provider plugins...
|
||||
|
||||
The following providers do not have any version constraints in configuration,
|
||||
so the latest version was installed.
|
||||
|
||||
To prevent automatic upgrades to new major versions that may contain breaking
|
||||
changes, it is recommended to add version = "..." constraints to the
|
||||
corresponding provider blocks in configuration, with the constraint strings
|
||||
suggested below.
|
||||
|
||||
* provider.helm: version = "~> 1.2"
|
||||
* provider.kubernetes: version = "~> 1.11"
|
||||
|
||||
Terraform has been successfully initialized!
|
||||
|
||||
You may now begin working with Terraform. Try running "terraform plan" to see
|
||||
any changes that are required for your infrastructure. All Terraform commands
|
||||
should now work. [...]
|
||||
```
|
||||
|
||||
Next, run your plan:
|
||||
|
||||
|
||||
```
|
||||
$ terraform plan
|
||||
Refreshing Terraform state in-memory prior to plan...
|
||||
helm_release.local: Refreshing state... (ID: buildachart)
|
||||
kubernetes_namespace.1-minikube-namespace: Refreshing state... (ID: my-first-terraform-namespace) [...]
|
||||
|
||||
Terraform will perform the following actions:
|
||||
|
||||
+ helm_release.local
|
||||
id: <computed>
|
||||
atomic: "false"
|
||||
chart: "./buildachart"
|
||||
cleanup_on_fail: "false"
|
||||
create_namespace: "false"
|
||||
dependency_update: "false"
|
||||
disable_crd_hooks: "false"
|
||||
disable_openapi_validation: "false"
|
||||
[...]
|
||||
+ kubernetes_namespace.1-minikube-namespace
|
||||
id: <computed>
|
||||
metadata.#: "1"
|
||||
[...]
|
||||
|
||||
Note: You didn't specify an "-out" parameter to save this plan, so Terraform
|
||||
can't guarantee that exactly these actions will be performed if
|
||||
"terraform apply" is subsequently run.
|
||||
```
|
||||
|
||||
Finally, apply the Terraform:
|
||||
|
||||
|
||||
```
|
||||
$ terraform apply --auto-approve
|
||||
helm_release.local: Refreshing state... (ID: buildachart)
|
||||
kubernetes_namespace.1-minikube-namespace: Refreshing state... (ID: my-first-terraform-namespace)
|
||||
kubernetes_namespace.1-minikube-namespace: Creating...
|
||||
metadata.#: "" => "1"
|
||||
metadata.0.generation: "" => "<computed>"
|
||||
[...]
|
||||
helm_release.local: Creating...
|
||||
atomic: "" => "false"
|
||||
chart: "" => "./buildachart"
|
||||
cleanup_on_fail: "" => "false"
|
||||
create_namespace: "" => "false"
|
||||
[...]
|
||||
version: "" => "0.1.0"
|
||||
wait: "" => "true"
|
||||
kubernetes_namespace.1-minikube-namespace: Creation complete after 1s (ID: helloworld)
|
||||
helm_release.local: Still creating... (10s elapsed)
|
||||
helm_release.local: Creation complete after 13s (ID: buildachart)
|
||||
|
||||
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
|
||||
```
|
||||
|
||||
Now you have a local backup of the Terraform state:
|
||||
|
||||
|
||||
```
|
||||
$ ls -lrt
|
||||
|
||||
drwxr-xr-x 6 jess jess 4096 May 16 14:15 buildachart
|
||||
-rw-r--r-- 1 jess jess 363 Oct 24 13:06 main.tf
|
||||
-rw-rw-r-- 1 jess jess 132 Oct 24 13:17 vars.tf
|
||||
-rw-rw-r-- 1 jess jess 3897 Oct 24 13:20 terraform.tfstate.backup
|
||||
-rw-rw-r-- 1 jess jess 3821 Oct 24 13:21 terraform.tfstate
|
||||
```
|
||||
|
||||
### Convert from Terraform 0.11 to 0.12
|
||||
|
||||
Once everything is deployed using Terraform 0.11, you must work through the conversion process without damaging what you have in your new production cluster. First, change your Terraform version to 0.12 using tfenv:
|
||||
|
||||
|
||||
```
|
||||
$ tfenv list
|
||||
0.12.29
|
||||
* 0.11.15-oci (set by /home/jess/.tfenv/version)
|
||||
jess@Athena:~/terraform_doc$ tfenv use 0.12.29
|
||||
Switching default version to v0.12.29
|
||||
Switching completed
|
||||
jess@Athena:~/terraform_doc$ terraform --version
|
||||
Terraform v0.12.29
|
||||
\+ provider.helm v1.2.2
|
||||
\+ provider.kubernetes v1.11.2
|
||||
```
|
||||
|
||||
Now that you're on Terraform 0.12, you're ready to convert. Luckily, Terraform has a built-in command for this, as shown in this snippet from the Terraform command list:
|
||||
|
||||
|
||||
```
|
||||
All other commands:
|
||||
0.12upgrade Rewrites pre-0.12 module source code for v0.12
|
||||
```
|
||||
|
||||
Test the `upgrade` command to see what will be rewritten, then enter `yes` to do the upgrade:
|
||||
|
||||
|
||||
```
|
||||
$ terraform 0.12upgrade
|
||||
|
||||
This command will rewrite the configuration files in the given directory so
|
||||
that they use the new syntax features from Terraform v0.12, and will identify
|
||||
any constructs that may need to be adjusted for correct operation with
|
||||
Terraform v0.12.
|
||||
[...]
|
||||
Would you like to upgrade the module in the current directory?
|
||||
Only 'yes' will be accepted to confirm.
|
||||
|
||||
Enter a value: yes
|
||||
|
||||
\-----------------------------------------------------------------------------
|
||||
|
||||
Upgrade complete!
|
||||
|
||||
The configuration files were upgraded successfully. Use your version control
|
||||
system to review the proposed changes, make any necessary adjustments, and
|
||||
then commit.
|
||||
```
|
||||
|
||||
It seems to have gone well. It may have rewritten some things, but that will not account for everything that needs to be changed with the Terraform files. However, it does a great job of making notes within the files. Here are the changes it made to the `vars.tf` file:
|
||||
|
||||
|
||||
```
|
||||
variable "namespace" {
|
||||
type = string
|
||||
default = "helloworld"
|
||||
}
|
||||
|
||||
variable "cluster" {
|
||||
type = string
|
||||
default = "minikube"
|
||||
}
|
||||
```
|
||||
|
||||
The `type` changed to remove quotes around the word `string` (quoting in Terraform files has changed over time). Next, look at the `main.tf` file:
|
||||
|
||||
|
||||
```
|
||||
provider "kubernetes" {
|
||||
config_context_cluster = var.cluster
|
||||
}
|
||||
|
||||
# TF-UPGRADE-TODO: In Terraform v0.11 and earlier, it was possible to begin a
|
||||
# resource name with a number, but it is no longer possible in Terraform v0.12.
|
||||
#
|
||||
# Rename the resource and run `terraform state mv` to apply the rename in the
|
||||
# state. Detailed information on the `state move` command can be found in the
|
||||
# documentation online: <https://www.terraform.io/docs/commands/state/mv.html>
|
||||
resource "kubernetes_namespace" "1-minikube-namespace" {
|
||||
metadata {
|
||||
name = var.namespace
|
||||
}
|
||||
}
|
||||
|
||||
provider "helm" {
|
||||
kubernetes {
|
||||
config_context_cluster = var.cluster
|
||||
}
|
||||
}
|
||||
|
||||
resource "helm_release" "local" {
|
||||
name = "buildachart"
|
||||
chart = "./buildachart"
|
||||
}
|
||||
```
|
||||
|
||||
The quotes changed here, too, and variables are no longer wrapped in `${}` characters. The biggest section is a large TODO note that the conversion command placed in the code to show what needs to change in the resource name to be acceptable in version 0.12. Even better, it explains how to fix this issue and the command you need to run. The other major changes are the new `versions.tf` file and a new backup file:
|
||||
|
||||
|
||||
```
|
||||
$ ls -lrt
|
||||
drwxr-xr-x 6 jess jess 4096 May 16 14:15 buildachart
|
||||
-rw-rw-r-- 1 jess jess 3897 Oct 24 13:20 terraform.tfstate.backup
|
||||
-rw-r--r-- 1 jess jess 46 Oct 24 13:28 versions.tf
|
||||
-rw-rw-r-- 1 jess jess 140 Oct 24 13:55 vars.tf
|
||||
-rw-r--r-- 1 jess jess 369 Oct 24 13:56 main.tf
|
||||
-rw-rw-r-- 1 jess jess 3821 Oct 24 13:56 terraform.tfstate.1603562212.backup
|
||||
-rw-rw-r-- 1 jess jess 3827 Oct 24 13:56 terraform.tfstate
|
||||
```
|
||||
|
||||
To update your production cluster, start with a different name that is better suited for this version:
|
||||
|
||||
|
||||
```
|
||||
resource "kubernetes_namespace" "upgrade-minikube-namespace" {
|
||||
metadata {
|
||||
name = var.namespace
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Smoothing the rough edges
|
||||
|
||||
After that change, you must run the `terraform state mv` command (as referenced in the large TODO note). But first, run `state list` to see what you're working with:
|
||||
|
||||
|
||||
```
|
||||
$ terraform state list
|
||||
helm_release.local
|
||||
Kubernetes_namespace.1-minikube-namespace
|
||||
```
|
||||
|
||||
The namespace is still set in the state as `1-minikube-namespace`, and that's the state you need to move. This can be done by ensuring you have the new and old resource names, then running the `terraform state mv` command. But before that, you must switch back to 0.11, using tfenv to make those changes, because this was deployed using Terraform 0.11, and 0.12 doesn't recognize the numbers at the start of the resource name (as the TODO says). You'll have to revert all the code changes the Terraform upgrade made except for the resource name change:
|
||||
|
||||
**main.tf**
|
||||
|
||||
|
||||
```
|
||||
provider "kubernetes" {
|
||||
config_context_cluster = "${var.cluster}"
|
||||
}
|
||||
|
||||
resource "kubernetes_namespace" "upgrade-minikube-namespace" {
|
||||
metadata {
|
||||
name = "${var.namespace}"
|
||||
}
|
||||
}
|
||||
|
||||
provider "helm" {
|
||||
kubernetes {
|
||||
config_context_cluster = "${var.cluster}"
|
||||
}
|
||||
}
|
||||
resource "helm_release" "local" {
|
||||
name = "buildachart"
|
||||
chart = "./buildachart"
|
||||
}
|
||||
```
|
||||
|
||||
**Vars.tf**
|
||||
|
||||
|
||||
```
|
||||
variable "namespace" {
|
||||
type = "string"
|
||||
default = "helloworld"
|
||||
}
|
||||
|
||||
variable "cluster" {
|
||||
type = "string"
|
||||
default = "minikube"
|
||||
}
|
||||
```
|
||||
|
||||
Once the changes are back in place, switch tfenv back to version 0.11, and run the `state mv` command:
|
||||
|
||||
|
||||
```
|
||||
$ tfenv use 0.11.15-oci
|
||||
Switching default version to v0.11.15-oci
|
||||
Switching completed
|
||||
jess@Athena:~/terraform_doc$ terraform state mv 'kubernetes_namespace.1-minikube-namespace' 'kubernetes_namespace.upgrade-minikube-namespace'
|
||||
Moved kubernetes_namespace.1-minikube-namespace to kubernetes_namespace.upgrade-minikube-namespace
|
||||
```
|
||||
|
||||
### Final steps
|
||||
|
||||
After this is complete, change tfenv back to version 0.12, and then remove your `versions.tf` file to make sure the conversion completes. If you don't remove this file, you'll get an error message:
|
||||
|
||||
|
||||
```
|
||||
$ terraform 0.12upgrade
|
||||
Error: Module already upgraded
|
||||
|
||||
on versions.tf line 3, in terraform:
|
||||
3: required_version = ">= 0.12"
|
||||
|
||||
The module in directory . has a version constraint that suggests it has
|
||||
already been upgraded for v0.12. If this is incorrect, either remove this
|
||||
constraint or override this heuristic with the -force argument. Upgrading a
|
||||
module that was already upgraded may change the meaning of that module.
|
||||
```
|
||||
|
||||
Remove the file and run the command:
|
||||
|
||||
|
||||
```
|
||||
$ terraform 0.12upgrade
|
||||
|
||||
This command will rewrite the configuration files in the given directory so
|
||||
that they use the new syntax features from Terraform v0.12, and will identify
|
||||
any constructs that may need to be adjusted for correct operation with
|
||||
Terraform v0.12. [...]
|
||||
|
||||
Would you like to upgrade the module in the current directory?
|
||||
Enter a value: yes
|
||||
|
||||
\-----------------------------------------------------------------------------
|
||||
|
||||
Upgrade complete!
|
||||
```
|
||||
|
||||
#### Test the conversion with another deployment
|
||||
|
||||
Test your new conversion by re-running your `init`, `plan`, and `apply` commands (I omitted chunks of the output in these snippets):
|
||||
|
||||
|
||||
```
|
||||
$ terraform init
|
||||
|
||||
Initializing the backend...
|
||||
Initializing provider plugins...
|
||||
[...]
|
||||
Terraform has been successfully initialized!
|
||||
|
||||
$ terraform plan
|
||||
Refreshing Terraform state in-memory prior to plan...
|
||||
The refreshed state will be used to calculate this plan, but will not be
|
||||
persisted to local or remote state storage.
|
||||
|
||||
helm_release.local: Refreshing state... [id=buildachart]
|
||||
kubernetes_namespace.upgrade-minikube-namespace: Refreshing state... [id=helloworld]
|
||||
|
||||
\------------------------------------------------------------------------
|
||||
|
||||
No changes. Infrastructure is up-to-date
|
||||
|
||||
$ terraform apply
|
||||
helm_release.local: Refreshing state... [id=buildachart]
|
||||
kubernetes_namespace.upgrade-minikube-namespace: Refreshing state... [id=helloworld]
|
||||
|
||||
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
|
||||
```
|
||||
|
||||
As this shows, once everything was preconfigured and the state moved and reapplied during the conversion, no other changes were made because the infrastructure is in place.
|
||||
|
||||
### Final thoughts
|
||||
|
||||
Code and application upgrades are hard to do, especially in a live production environment. This is very true when converting from Terraform 0.11 to 0.12. I've done this on a large scale, and it involved extensive planning over a two-week timeframe.
|
||||
|
||||
If you're going to do this in your production environment, make sure you:
|
||||
|
||||
* Start by removing any resources or modules with prepended numbers.
|
||||
* Move the state before running the upgrade.
|
||||
* Keep your upgraded Terraform files in a forked repo for safety.
|
||||
|
||||
|
||||
|
||||
I hope this article helps you move forward more quickly and easily than I did.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/update-terraform
|
||||
|
||||
作者:[Jessica Cherry][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/cherrybomb
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/metrics_lead-steps-measure.png?itok=DG7rFZPk (Green graph of measurements)
|
||||
[2]: https://opensource.com/article/20/7/terraform-kubernetes
|
||||
[3]: https://github.com/tfutils/tfenv
|
||||
[4]: https://opensource.com/article/20/3/helm-kubernetes-charts
|
||||
[5]: https://opensource.com/article/20/11/tfenv
|
||||
[6]: http://www.terraform.io/downloads.html
|
||||
@@ -0,0 +1,99 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (My top 7 Rust commands for using Cargo)
|
||||
[#]: via: (https://opensource.com/article/20/11/commands-rusts-cargo)
|
||||
[#]: author: (Mike Bursell https://opensource.com/users/mikecamel)
|
||||
|
||||
My top 7 Rust commands for using Cargo
|
||||
======
|
||||
Spend some time investigating Rust's package manager, Cargo.
|
||||
![Person drinking a hot drink at the computer][1]
|
||||
|
||||
I've been using Rust for a little over six months now. I'm far from an expert, but I have stumbled across many, many gotchas and learned many, many things along the way; things that I hope will be of use to those who are learning what is easily my favourite programming language.
|
||||
|
||||
This is the third article in my miniseries for Rust newbs like me. You can find my other excursions into Rust in:
|
||||
|
||||
* [My top 7 keywords in Rust][2]
|
||||
* [My top 7 functions in Rust][3]
|
||||
|
||||
|
||||
|
||||
I plan to write more, and this article is about Rust's package manager, [Cargo][4]. I'm ashamed to admit that I don't use Cargo's power as widely as I should, but researching this article gave me a better view of its commands' capabilities. In fact, I wasn't even aware of some of the options available until I started looking in more detail.
|
||||
|
||||
For this list of my top seven Cargo commands, I'll assume you have basic familiarity with Cargo—that you have it installed, and you can create a package using `cargo new <package>`, for instance. I could have provided more commands (there are many options!), but here are my "lucky 7."
|
||||
|
||||
1. **cargo help <command>:** You can always find out more about a command with the `--help` option. The same goes for Cargo itself: `cargo --help` will give you a quick intro to what's out there. To get more information on a command (more like a man page), you can try using the command `new`. For instance, `cargo help new` will give extended information about `cargo new`. This behaviour is pretty typical for command-line tools, particularly in the Linux/Unix world, but it's very expressively implemented for Cargo, and you can gain lots of quick information with it.
|
||||
|
||||
2. **cargo build --bin <target>:** What happens when you have multiple .rs files in your package, but you want to build just one of them? I have a package called `test-and-try` that I use for, well, testing and trying functionality, features, commands, and crates. It has around a dozen different files in it. By default, `cargo build` will try to build _all_ of them, and as they're often in various states of repair (some of them generating lots of warnings, some of them not even fully compiling), this can be a real pain. Instead, I place a section in my `Cargo.toml` file for each one like this: [code]
|
||||
|
||||
[[bin]]
|
||||
name = "warp-body"
|
||||
path = "src/warp-body.rs"
|
||||
|
||||
[/code] I can then use `cargo build --bin warp-body` to build _just_ this file (and any dependencies). I can then run it with a similar command: `cargo run --bin warp-body`.
|
||||
|
||||
3. **cargo test:** I have an admission; I am not as assiduous about creating automatic tests in my Rust code as I ought to be. This is because I'm currently mainly writing proof of concept rather than production code, and also because I'm lazy. Maybe changing this behaviour should be a New Year's resolution, but when I _do_ get round to writing tests, Cargo is there to help me (as it is for you). All you need to do is add a line before the test code in your .rs file: [code]`#[cfg(test)]`[/code] When you run `cargo test`, Cargo will "automagically" find these tests, run them, and tell you if you have problems. As with many of the commands here, you'll find much more information online, but it's particularly worth familiarising yourself with the basics of this capability in the relevant [Rust By Example section][5].
|
||||
|
||||
4. **cargo search <query>:** This is one of the commands that I didn't even know existed until I started researching this article—and which would have saved me so much time over the past few months if I'd known about it. It searches [Crates.io][6], Rust's repository of public (and _sometimes_ maintained) packages and tells you which ones may be relevant. (You can specify a different repository if you want, with the intuitively named `--registry` option.) I've recently been doing some work on network protocols for non-String data, so I've been working with Concise Binary Object Representation ([CBOR][7]). Here's what happens if I use `cargo search`:
|
||||
|
||||
![Cargo search output][8]
|
||||
|
||||
(Mike Bursell, [CC BY-SA 4.0][9])
|
||||
|
||||
This is great! I can, of course, also combine this command with tools like grep to narrow down the search yet further, like so: `cargo search cbor --limit 70 | grep serde`.
|
||||
|
||||
5. **cargo tree:** Spoiler alert: this one may scare you. You've probably noticed that when you first build a new package, or when you add a new dependency, or just do a `cargo clean` and then `cargo build`, you see a long list of crates printed out as Cargo pulls them down from the relevant repositories and compiles them. How can you tell ahead of time, however, what will be pulled down and what version it will be? More importantly, how can you know what other dependencies a new crate has pulled into your build? The answer is `cargo tree`. Just to warn you: For any marginally complex project, you can expect to have a _lot_ of dependencies. I tried `cargo tree | wc -l` to count the number of dependent crates for a smallish project I'm working on and got an answer of 350! I tried providing an example, but it didn't display well, so I recommend that you try it yourself—be prepared for lots of output!
|
||||
|
||||
6. **cargo clippy:** If you try running this and it doesn't work, that's because I cheated a little with these last two commands: you may have to install them explicitly (depending on your setup). For this one, run `cargo install clippy`—you'll be glad you did. Clippy is Rust's linter; it goes through your code, looking at ways to reduce and declutter it by removing or changing commands. I try to run `cargo clippy` before every `git commit`—partly because the Git repositories I tend to commit to have automatic actions to reject files that need linting, and partly to keep my code generally more tidy. Here's an example:
|
||||
|
||||
![Cargo clippy output][10]
|
||||
|
||||
(Mike Bursell, [CC BY-SA 4.0][9])
|
||||
|
||||
Let's face it; this isn't a major issue (though clippy will find errors, too, if you run it on non-compiling code), but it's an easy fix, so you might as well deal with it—either by removing the code or prefixing the variable with an underscore. As I plan to use this variable later but haven't yet implemented the function to consume it, I will perform the latter fix.
|
||||
|
||||
7. **cargo readme:** While it's not the most earth-shattering of commands, this is another that is very useful (and that, as with `cargo clippy`, you may need to install explicitly). If you add the relevant lines to your .rs files, you can output README files from Cargo. For instance, I have the following lines at the beginning of my main.rs file:
|
||||
|
||||
![Cargo readme input][11]
|
||||
|
||||
(Mike Bursell, [CC BY-SA 4.0][9])
|
||||
|
||||
I'll leave the `cargo readme` command's output as an exercise for the reader, but it's interesting to me that the Licence (or "License," if you must) declaration is added. Use this to create simple documentation for your users and make them happy with minimal effort (always a good approach!).
|
||||
|
||||
|
||||
|
||||
|
||||
I've just scratched the surface of Cargo's capabilities in this article; all the commands above are actually way more powerful than I described. I heartily recommend that you spend some time investigating Cargo and finding out how it can make your life better.
|
||||
|
||||
* * *
|
||||
|
||||
_This article was originally published on [Alice, Eve, and Bob][12] and is reprinted with the author's permission._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/commands-rusts-cargo
|
||||
|
||||
作者:[Mike Bursell][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/mikecamel
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/coffee_tea_laptop_computer_work_desk.png?itok=D5yMx_Dr (Person drinking a hot drink at the computer)
|
||||
[2]: https://opensource.com/article/20/10/keywords-rust
|
||||
[3]: https://opensource.com/article/20/10/rust-functions
|
||||
[4]: https://doc.rust-lang.org/cargo/
|
||||
[5]: https://doc.rust-lang.org/stable/rust-by-example/testing/unit_testing.html
|
||||
[6]: https://crates.io/
|
||||
[7]: https://cbor.io/
|
||||
[8]: https://opensource.com/sites/default/files/uploads/cargo-search-output-5.png (Cargo search output)
|
||||
[9]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[10]: https://opensource.com/sites/default/files/uploads/cargo-clippy-output-1.png (Cargo clippy output)
|
||||
[11]: https://opensource.com/sites/default/files/uploads/cargo-readme-input.png (Cargo readme input)
|
||||
[12]: https://aliceevebob.com/2020/11/03/my-top-7-cargo-rust-commands/
|
||||
@@ -0,0 +1,170 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Apply the Scientific Method to agile development)
|
||||
[#]: via: (https://opensource.com/article/20/11/hypothesis-driven-development)
|
||||
[#]: author: (Alex Bunardzic https://opensource.com/users/alex-bunardzic)
|
||||
|
||||
Apply the Scientific Method to agile development
|
||||
======
|
||||
Hypothesis-driven development allows constant analysis of new
|
||||
information to implement new insights (and deliver new customer value)
|
||||
on an ongoing basis.
|
||||
![Science lab with beakers][1]
|
||||
|
||||
> "The only way it’s all going to go according to plan is if you don’t learn anything." —Kent Beck
|
||||
|
||||
Experimentation is the foundation of the scientific method, which is a systematic means of exploring the world around us. But experimentation is not only reserved for the field of scientific research. It has a central place in the world of business too.
|
||||
|
||||
Most of us are by now familiar with the business methodology called [Minimum Viable Product (MVP)][2]. This Minimum Viable Product is basically just an experiment. By building and launching MVPs, business operations are engaging in a systematic means of exploring the markets.
|
||||
|
||||
If we look at market leaders today, we learn that they’re not doing projects anymore; the only thing they’re doing is experiments. Customer discovery and lean strategies are only used to test assumptions about the markets. Such an approach is equivalent to Test-Driven Development (TDD), which is the process we are intimately familiar with. In TDD, we write the hypothesis (the test) first. We then use that test to guide our implementation. Ultimately, product or service development is no different than TDD—we first write a hypothesis, then that hypothesis guides our implementation, which serves as measurable validation of the hypothesis.
|
||||
|
||||
### Information discovery
|
||||
|
||||
Back in the pre-agile days, requirements gathering was an important activity that used to always kick off the project. A bunch of subject matter experts (SMEs) would get assigned to the project and be tasked with gathering the requirements. After a prolonged period of upfront information discovery, the gathered requirements got reviewed and, if agreed upon, signed off and frozen. No more changes allowed!
|
||||
|
||||
Back then, it seemed a perfectly reasonable thing to do. The fly in the ointment always showed up once the build phase commenced. Sooner or later, as the project progresses, new information comes to light. Suddenly, what we initially viewed as incontrovertible truth gets challenged by the newly acquired information and evidence.
|
||||
|
||||
But the clincher was in the gated phases. Remember, once requirements get signed off, they get frozen—no more changes, no scope creep allowed—which means newly obtained market insights get willfully ignored.
|
||||
|
||||
Well, that’s kind of foolish neglect. The newly emerging evidence could be of critical importance to the health of the business operation. Can we afford to ignore it? Absolutely not! We have no choice but to embrace the change.
|
||||
|
||||
After a number of prominent fiascos in the industry, many software development projects switched to the agile approach. With agile, information discovery is partial. With agile, we never claim that we have gathered the requirements and are now ready to implement them. We discover information and implement it on an ongoing basis. We do it in tiny steps, keeping our efforts interruptible and steerable at all times.
|
||||
|
||||
### How to leverage the scientific method
|
||||
|
||||
The scientific method is empirical and consists of the following steps:
|
||||
|
||||
Step 1: Make and record careful observations.
|
||||
|
||||
Step 2: Perform orientation with regard to observed evidence.
|
||||
|
||||
Step 3: Formulate a hypothesis, including measurable indicators for hypothesis evaluation.
|
||||
|
||||
Step 4: Design an experiment that will enable testing of the hypothesis.
|
||||
|
||||
Step 5: Conduct the experiment (i.e., release the partial implementation).
|
||||
|
||||
Step 6: Collect the telemetry that results from running the experiment.
|
||||
|
||||
Step 7: Evaluate the results of the experiment.
|
||||
|
||||
Step 8: Accept or reject the hypothesis.
|
||||
|
||||
Step 9: Return to Step 1.
|
||||
|
||||
### How to formulate a hypothesis
|
||||
|
||||
When switching from project to experiments, the traditional user story framework (As a__I want to__so that__) has proven insufficient. The traditional user story format does not expose the signals needed in order to evaluate the outcomes. Instead, the old school user story format is focused on outputs.
|
||||
|
||||
The problem with doing an experiment without first formulating a hypothesis is that there is a danger of introducing a bias when interpreting the results of an experiment. Defining the measurable signals that will enable us to corroborate our hypothesis must be done before we conduct the experiment. That way, we can remain completely impartial when interpreting the results of the experiment. We cannot be swayed by wishful thinking.
|
||||
|
||||
The best way to proceed with formulating a hypothesis is to use the following format:
|
||||
|
||||
We believe [this capability] will result in [this outcome]. We will have the confidence to proceed when [we see a measurable signal].
|
||||
|
||||
### Working software is not a measure of progress
|
||||
|
||||
Output-based metrics and concepts (definition of "done," acceptance criteria, burndown charts, and velocity) are good for detecting working software but fall miserably when it comes to detecting if working software adds value.
|
||||
|
||||
"Done" only matters if it adds value. Working software that doesn’t add value cannot be declared "done."
|
||||
|
||||
### The forgotten column
|
||||
|
||||
Technology-centric projects break activities down into four columns:
|
||||
|
||||
1. Backlog of ideas
|
||||
2. Analysis
|
||||
3. In progress
|
||||
4. Shipped
|
||||
|
||||
|
||||
|
||||
The above structure is based on the strong belief that all software that works is valuable. That focus must now shift toward continuously delivering real value, something that serves customers. Agilists value outcomes (value to the customers) over features.
|
||||
|
||||
The new breakdown for hypothesis-driven development looks something like this:
|
||||
|
||||
Ideas Backlog
|
||||
|
||||
|
|
||||
|
||||
Analysis
|
||||
|
||||
|
|
||||
|
||||
In Progress
|
||||
|
||||
|
|
||||
|
||||
Shipped
|
||||
|
||||
|
|
||||
|
||||
Achieved Desired Outcome
|
||||
|
||||
---|---|---|---|---
|
||||
|
||||
Hypothesis 11
|
||||
|
||||
Hypothesis 12
|
||||
|
||||
Hypothesis 13
|
||||
|
||||
Hypothesis 14
|
||||
|
||||
Hypothesis 15
|
||||
|
||||
Hypothesis 16
|
||||
|
||||
Hypothesis 17
|
||||
|
||||
Hypothesis 18
|
||||
|
||||
Hypothesis 19
|
||||
|
||||
|
|
||||
|
||||
Hypothesis 20
|
||||
|
||||
Hypothesis 21
|
||||
|
||||
|
|
||||
|
||||
Hypothesis 26
|
||||
|
||||
|
|
||||
|
||||
Hypothesis 2
|
||||
|
||||
Hypothesis 5
|
||||
|
||||
Hypothesis 9
|
||||
|
||||
Hypothesis 10
|
||||
|
||||
|
|
||||
|
||||
Hypothesis 1
|
||||
|
||||
Hypothesis 5
|
||||
|
||||
All eyes must remain on the Achieved Desired Outcome column.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/hypothesis-driven-development
|
||||
|
||||
作者:[Alex Bunardzic][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/alex-bunardzic
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/science_experiment_beaker_lab.png?itok=plKWRhlU (Science lab with beakers)
|
||||
[2]: https://en.wikipedia.org/wiki/Minimum_viable_product#:~:text=A%20minimum%20viable%20product%20%28MVP,feedback%20for%20future%20product%20development.&text=The%20concept%20can%20be%20used,developments%20of%20an%20existing%20product.
|
||||
@@ -0,0 +1,134 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Cloud control vs local control: What to choose for your home automation)
|
||||
[#]: via: (https://opensource.com/article/20/11/cloud-vs-local-home-automation)
|
||||
[#]: author: (Steve Ovens https://opensource.com/users/stratusss)
|
||||
|
||||
Cloud control vs local control: What to choose for your home automation
|
||||
======
|
||||
Cloud may be more convenient, but local control gives you more privacy
|
||||
and other options in your Home Assistant ecosystem.
|
||||
![clouds in windows][1]
|
||||
|
||||
There are a lot of factors to consider when investing in a home automation ecosystem. In my first article in this series, I explained [why I picked Home Assistant][2], and in this article, I'll explain some of the foundational issues and technologies in home automation, which may influence how you approach and configure your Internet of Things (IoT) devices.
|
||||
|
||||
### Cloud connectivity
|
||||
|
||||
Most devices you can buy today are tied to some type of cloud service. While the cloud brings a certain level of convenience, it also opens a host of problems. For starters, there are privacy issues related to a company having access to your personal habits—when you are home, what shows you watch, what time you go to bed, etc. Although most people are not as concerned about these issues as I am, privacy should still be a consideration, even if it is a small one.
|
||||
|
||||
Cloud access also creates issues around being reliant on something outside your control. In 2019, Sonos came under fire for [remotely bricking][3] older smart speakers. Speakers usually continue to work for years after their warranty ends; in fact, they usually function until they physically break. There's also the case of Automatic, which produced a cloud-based car tracker. When it announced in May 2020 that it would be [shutting down][4] its services, it advised customers to "please discard your adapter by following standard electronic recycling procedures."
|
||||
|
||||
Being dependent on a third-party provider for critical functionality can come back to bite you. [IFTTT][5], a popular service for programming events based on external conditions, recently altered its free plan's [terms and conditions][6] to severely limit the number of events you can create—from an unlimited number to three. This is even though IFTTT charges device manufacturers for certification with its system, which allows products like [Meross smart bulbs][7] to proudly display their compatibility with IFTTT.
|
||||
|
||||
![Meross screenshot from Amazon][8]
|
||||
|
||||
(Amazon screenshot by Steve Ovens, [CC BY-SA 4.0][9])
|
||||
|
||||
Some of these decisions are purely financial, but there are more than a few anecdotal cases where a company blocks a person's access to a device they purchased simply because they [did not like what the user said][10] about them. How crazy is that?
|
||||
|
||||
Another consideration with cloud connectivity is a device's responsivity if its signals must travel from your home to a cloud server (which may be halfway around the world) and then back to the device. This can lead to a two-second (or more) delay on any action. For some people, this is not a deal-breaker. For others, that delay is unbearable.
|
||||
|
||||
Finally, what happens if there is an internet outage? While most modern home internet connections are quite reliable, they do happen. [Some large][11], well-known cloud [service providers][12] have experienced outages this year. Are you OK trading convenience for possibly having your automations break and losing control of your smart devices for periods of time?
|
||||
|
||||
### Local control
|
||||
|
||||
There are several ways you can regain control over your smart devices. Commercially, you could try something like [Hubitat][13], which is a proprietary platform that emphasizes local control. I have no experience with these devices, as I don't like to rely on an intermediary.
|
||||
|
||||
In my home, I standardized on WiFi (although I may branch out to [Zigbee][14] in the future) and [Home Assistant][15]. Using WiFi means I need to buy or make my devices based on their compatibility with alternative open source firmware, such as [Tasmota][16] or [ESPHome][17]. I admit that neither of these options is "plug-and-play friendly" unless you buy devices from sources like [Shelly][18], which is very friendly to the community, or [CloudFree][19], which has Tasmota installed by default.
|
||||
|
||||
(As a small aside, I have both flashed my own devices and purchased them from CloudFree. There are some savings with the DIY approach, but I buy pre-flashed devices for my father's house because this eliminates a lot of hassle.)
|
||||
|
||||
I won't go into more detail about alternative firmware, how to flash it, and so on. I simply want to introduce you to the idea that there are options for local control.
|
||||
|
||||
### Achieving local control with MQTT
|
||||
|
||||
A local control device probably uses either a direct [API][20] call, where Home Assistant talks directly to the device, or Message Queuing Telemetry Transport ([MQTT][21]).
|
||||
|
||||
MQTT is one of the most widely used protocols for local IoT communication. I'll share some of the basics, but the Hook Up has an [in-depth video][22] you can watch if you want to learn more, and HiveMQ has an [entire series][23] on MQTT essentials.
|
||||
|
||||
MQTT uses three components for communication. The first, the **sender**, is the component that triggers the action. The second, the **broker**, is kind of like a bulletin board where messages are posted. The final component is the **device** that will perform the action. This process is called the _publish-subscribe_ model.
|
||||
|
||||
Say you have a button on the wall that you want to use to turn on the projector, lower the blinds, and turn on a fan. The button (sender) posts the _message_ **ON** to a specific section of the broker, called a _topic_. The topic might be something like `/livingroom/POWER`. The fan, the projector, and the blinds _subscribe_ to this topic. When the message **ON** is posted to the topic, all of the devices activate their respective functions, turning on the projector, lowering the blinds, and starting the fan.
|
||||
|
||||
Unlike a message board, messages have different Quality of Service (QoS) states. The HiveMQ website has a good explanation of the [three QoS levels][24]. In short:
|
||||
|
||||
* **QoS 0:** The message is sent to the broker in a fire-and-forget way. No attempt is made to verify that the broker received the message.
|
||||
|
||||
|
||||
|
||||
![MQTTT QoS 0][25]
|
||||
|
||||
(© 2015 [HiveMQ][24], reused with permission)
|
||||
|
||||
* **QoS 1**: The message is posted, and the broker replies once the message is received. Multiple messages can be sent before the broker replies. For example, if you are trying to raise the projector's brightness, multiple brightness bars may be inadvertantly adjusted before the broker tells the sender to stop publishing messages.
|
||||
|
||||
|
||||
|
||||
![MQTTT QoS 1][26]
|
||||
|
||||
(© 2015 [HiveMQ][24], reused with permission)
|
||||
|
||||
* **QoS 2:** This is the slowest but safest level. It guarantees that the message is received only once. Similar to TCP, if a message is lost, the sender will resend the message.
|
||||
|
||||
|
||||
|
||||
![MQTTT QoS 2][27]
|
||||
|
||||
(© 2015 [HiveMQ][24], reused with permission)
|
||||
|
||||
In addition, MQTT has a **retain** flag that can be enabled on the messages, but it is not set by default. Going back to the bulletin board analogy, it's like if someone posts a message to a bulletin board, but another person walks up to the board, takes the message down, reads it, and throws it away. If a third person looks at the bulletin board five minutes later, they would have no knowledge of the message. However, if the **retain** flag is set to true, it's like leaving the message pinned on the board until a new message is received. This means that no matter when people come to read messages, they will all know the latest message.
|
||||
|
||||
In home automation terms, whether or not the **retain** flag is set depends completely on the use case.
|
||||
|
||||
In this series, I will use Home Assistant's [Mosquitto MQTT broker][28] add-on. Most of my devices use MQTT; however, I do have a couple of non-critical Tuya devices that require a cloud account. I may replace them with locally controllable ones in the future.
|
||||
|
||||
### Wrapping up
|
||||
|
||||
Home Assistant is a large, wonderful piece of software. It is complex in some areas, and it will help you to be familiar with these fundamental technologies when you need to troubleshoot and coordinate your setup.
|
||||
|
||||
In the next article, I will talk about the "big three" wireless protocols that you are likely to encounter in smart devices: Zigbee, Z-Wave, and WiFi. Don't worry—I'm almost done with the underlying theories, and soon I'll get on with installing Home Assistant.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/cloud-vs-local-home-automation
|
||||
|
||||
作者:[Steve Ovens][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/stratusss
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/cloud-windows-building-containers.png?itok=0XvZLZ8k (clouds in windows)
|
||||
[2]: https://opensource.com/article/20/11/home-assistant
|
||||
[3]: https://www.bbc.com/news/technology-51768574
|
||||
[4]: https://www.cnet.com/roadshow/news/automatic-connected-car-service-dead-may-coronavirus/
|
||||
[5]: https://ifttt.com/
|
||||
[6]: https://ifttt.com/plans
|
||||
[7]: https://www.amazon.ca/meross-Dimmable-Equivalent-Compatible-Required/dp/B07WN2J3C7
|
||||
[8]: https://opensource.com/sites/default/files/uploads/ifttt_add.png (Meross screenshot from Amazon)
|
||||
[9]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[10]: https://www.techrepublic.com/article/iot-company-bricks-customers-device-after-negative-review/
|
||||
[11]: https://www.theverge.com/2020/9/28/21492688/microsoft-outlook-office-teams-azure-outage-down
|
||||
[12]: https://www.cnn.com/2020/08/30/tech/internet-outage-cloudflare/index.html
|
||||
[13]: https://hubitat.com/
|
||||
[14]: https://zigbeealliance.org/
|
||||
[15]: https://www.home-assistant.io/
|
||||
[16]: https://tasmota.github.io/docs/
|
||||
[17]: https://esphome.io/
|
||||
[18]: https://shelly.cloud/
|
||||
[19]: https://cloudfree.shop/
|
||||
[20]: https://en.wikipedia.org/wiki/API
|
||||
[21]: https://en.wikipedia.org/wiki/MQTT
|
||||
[22]: https://www.youtube.com/watch?v=NjKK5ab0-Kk
|
||||
[23]: https://www.hivemq.com/tags/mqtt-essentials/
|
||||
[24]: https://www.hivemq.com/blog/mqtt-essentials-part-6-mqtt-quality-of-service-levels/
|
||||
[25]: https://opensource.com/sites/default/files/uploads/ha-config8-qos0.png (MQTTT QoS 0)
|
||||
[26]: https://opensource.com/sites/default/files/uploads/ha-config8-qos1.png (MQTTT QoS 1)
|
||||
[27]: https://opensource.com/sites/default/files/uploads/ha-config9-qos2.png (MQTTT QoS 2)
|
||||
[28]: https://mosquitto.org/
|
||||
@@ -0,0 +1,66 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Day 8: Start with something that works)
|
||||
[#]: via: (https://jvns.ca/blog/2020/11/18/how-to-do-hard-projects--start-with-something-that-works/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
Day 8: Start with something that works
|
||||
======
|
||||
|
||||
Today at RC I’m a little stuck so here’s a very short reflection on how to do hard programming problems :)
|
||||
|
||||
I was talking to a friend yesterday about how to do programming projects that are a bit out of your comfort zone, and I realized that there’s a pattern to how I approach new-to-me topics! Here I’m especially thinking about little side projects where you want to get the thing done pretty efficiently.
|
||||
|
||||
When I start on a new project using some technology I haven’t worked with before, I often:
|
||||
|
||||
1. Find some code on the internet that already does something a little like what I want
|
||||
2. Incrementally modify that code until it does what I want, often completely changing everything about the original code in the process
|
||||
|
||||
|
||||
|
||||
Here are a couple of quick thoughts about this process:
|
||||
|
||||
### it’s important that the initial code _works_
|
||||
|
||||
Often when I’m out looking for examples, I’ll find a lot of code that I can’t get to work quickly, often because the code is kind of old and things have changed since then. Whenever possible, I try to find code that I can get to work on my computer pretty quickly.
|
||||
|
||||
It’s been pretty helpful to me to give up relatively quickly on code that I can’t get to work right away and look for another example – often there is something out there that’s more recent and that I can get to work more quickly!
|
||||
|
||||
### you have to be able to incrementally change the code into what you want
|
||||
|
||||
Today I’ve been working with some neural network code, and one thing I’m really struggling with for the last couple of days is that I find it pretty easy to find somewhat relevant Jupyter notebooks that do RNN things, and pretty hard to modify those examples to do something closer to what I want. They keep breaking and I then don’t know how to fix them.
|
||||
|
||||
Last week I was working on a Rails app, which I think is something that’s very easy to incrementally change into the program you want: `rails new` gives you a webserver that does almost nothing, but it works! And then you just need to change it one tiny step at a time into the website you want to build.
|
||||
|
||||
### examples of “something that works”
|
||||
|
||||
* If you want to write a window manager, [tinywm][1] is a window manager in 50 lines of C!
|
||||
* this tiny kernel written in Rust that does nothing was a fun starting point for an operating system <https://github.com/charliesome/rustboot> (probably it’s not a good starting point today)
|
||||
* `rails new`, like I talked about above
|
||||
* I love that <https://glitch.com/> projects let you “view source” on the backend of any Glitch project
|
||||
* Jupyter notebooks, like [these great NLP tutorials by Allison Parrish][2]
|
||||
|
||||
|
||||
|
||||
### that’s all!
|
||||
|
||||
I think little starting points like this are so important and can be really magical. Finding the right starting point can be hard, but when I find a good one it makes everything so much easier!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2020/11/18/how-to-do-hard-projects--start-with-something-that-works/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: http://incise.org/tinywm.html
|
||||
[2]: https://twitter.com/aparrish/status/876117075567284225
|
||||
@@ -0,0 +1,138 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to Write, Compile and Run a C Program in Ubuntu and Other Linux Distributions [Beginner’s Tip])
|
||||
[#]: via: (https://itsfoss.com/run-c-program-linux/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
|
||||
How to Write, Compile and Run a C Program in Ubuntu and Other Linux Distributions [Beginner’s Tip]
|
||||
======
|
||||
|
||||
How do you program in C on Linux? It is indeed very easy and consists of three simple steps.
|
||||
|
||||
**Step 1**: You write your program and save the file with a .c extension. For example, my_program.c.
|
||||
|
||||
**Step 2**: You compile the program and generate the object file using gcc compiler in a terminal like this:
|
||||
|
||||
```
|
||||
gcc -o my_program my_program.c
|
||||
```
|
||||
|
||||
**Step 3**: You run the generated object file to run your C program in Linux:
|
||||
|
||||
```
|
||||
./my_program
|
||||
```
|
||||
|
||||
![][1]
|
||||
|
||||
This was just the quick summary on how to compile and run C program in Linux. If you are new to either C or Linux, I’ll show these steps in detail so that you feel comfortable coding C program in Linux environment.
|
||||
|
||||
In fact, I’ll discuss how to run C programs in Linux terminal as well as in code editor.
|
||||
|
||||
![][2]
|
||||
|
||||
### Method 1: How to run C programs in Linux terminal
|
||||
|
||||
In order to run a C program in Linux, you need to have a C compiler present on your systems. The most popular compiler is gcc ([GNU Compiler Collection][3]).
|
||||
|
||||
You can install gcc using your distribution’s package manager. In Debian and Ubuntu-based Linux distributions, use the apt command:
|
||||
|
||||
```
|
||||
sudo apt install gcc
|
||||
```
|
||||
|
||||
Switch to directory where you have kept your C program (or provide the path) and then generate the object file by compiling the program:
|
||||
|
||||
```
|
||||
gcc -o my_program my_program.c
|
||||
```
|
||||
|
||||
Keep in mind that it is optional to provide the output object file (-o my_program). If you won’t do that, an object file named a.out will be automatically generated. But this is not good because it will be overwritten for each C program and you won’t be able to know which program the a.out object file belongs to.
|
||||
|
||||
Once you have your object file generated, run it to run the C program. It is already executable. Simple use it like this:
|
||||
|
||||
```
|
||||
./my_program
|
||||
```
|
||||
|
||||
And it will display the desired output, if your program is correct. As you can see, this is not very different from [running C++ programs in Linux][4].
|
||||
|
||||
_**Every time you make a change in your program, you have to compile it first and then run the generated object file to run the C program.**_
|
||||
|
||||
### Method 2: How to run C programs in Linux using a code editor like Visual Studio Code
|
||||
|
||||
Not everyone is comfortable with command line and terminal and I totally understand that.
|
||||
|
||||
You can use a proper C/C++ IDE like Eclipse or Code Blocks but they are often too heavy programs and more suitable for large projects.
|
||||
|
||||
I recommend using an open source code editor like Visual Studio Code or Atom. These are basically text editors and you can install add-ons to compile and run programs directly from the graphical code editor.
|
||||
|
||||
I am using [Visual Studio Code editor][5] in this example. It’s a hugely [popular open source code editor][6] from Microsoft.
|
||||
|
||||
First thing first, [install Visual Studio Code in Ubuntu][7] from the software center. For other distributions, please check your Linux distribution’s package manager or software center. You may also check the official website for more information.
|
||||
|
||||
Start Visual Studio Code and open/create a project and create your C program here. I am using a sample Hello World program.
|
||||
|
||||
![][8]
|
||||
|
||||
You must ensure that you have gcc compiler installed on your Linux system.
|
||||
|
||||
```
|
||||
sudo apt install gcc
|
||||
```
|
||||
|
||||
Next thing you would want is to use an extension that allows you to run the C code. Microsoft may prompt you for installing its own extension for C/C++ program but it is complicated to setup and hence I won’t recommend it.
|
||||
|
||||
Instead, I suggest using the Code Runner extension. It’s a no-nonsense extension and you can run C and C++ code easily without additional configuration.
|
||||
|
||||
Go to the Extensions tab and search for ‘Code Runner’ and install it.
|
||||
|
||||
![Install Code Runner extension for running C/C++ program][9]
|
||||
|
||||
Restart Visual Studio Code. Now, you should be able to run the C code by using one of the following way:
|
||||
|
||||
* Using the shortcut Ctrl+Alt+N.
|
||||
* Press F1 and then select or type Run Code.
|
||||
* Right click the text editor and the click Run code from context menu.
|
||||
|
||||
|
||||
|
||||
![Right click the program file and choose Run Code][10]
|
||||
|
||||
When you run the program, it is compiled automatically and then run. You can see the output in terminal that is opened at the bottom of the editor. What could be better than this?
|
||||
|
||||
![Program output is displayed in the bottom section of the editor][11]
|
||||
|
||||
Which method do you prefer?
|
||||
|
||||
Running a few C programs in Linux command line is okay but using a code editor is much easier and saves time. Won’t you agree?
|
||||
|
||||
I let you decide whichever method you want to use.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/run-c-program-linux/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/abhishek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/running-c-program-linux.png?resize=795%2C399&ssl=1
|
||||
[2]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/Run-C-Program-Linux.png?resize=800%2C450&ssl=1
|
||||
[3]: https://gcc.gnu.org/
|
||||
[4]: https://itsfoss.com/c-plus-plus-ubuntu/
|
||||
[5]: https://code.visualstudio.com
|
||||
[6]: https://itsfoss.com/best-modern-open-source-code-editors-for-linux/
|
||||
[7]: https://itsfoss.com/install-visual-studio-code-ubuntu/
|
||||
[8]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/c-program-visual-studio-code-linux.png?resize=800%2C441&ssl=1
|
||||
[9]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/running-c-program-in-linux-with-visual-studio-code.png?resize=800%2C500&ssl=1
|
||||
[10]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/running-c-program-in-linux-with-visual-studio-code.jpg?resize=800%2C500&ssl=1
|
||||
[11]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/run-c-program-in-linux-with-visual-studio-code.jpg?resize=800%2C500&ssl=1
|
||||
275
sources/tech/20201118 Secure your containers with SELinux.md
Normal file
275
sources/tech/20201118 Secure your containers with SELinux.md
Normal file
@@ -0,0 +1,275 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Secure your containers with SELinux)
|
||||
[#]: via: (https://opensource.com/article/20/11/selinux-containers)
|
||||
[#]: author: (Mike Calizo https://opensource.com/users/mcalizo)
|
||||
|
||||
Secure your containers with SELinux
|
||||
======
|
||||
Hack your system to understand why it's important to configure SELinux
|
||||
to be your first line of container defense.
|
||||
![Three closed doors][1]
|
||||
|
||||
When things aren't working correctly in your Linux environment, the easiest thing to do is disable Security-Enhanced Linux ([SELinux][2]). Things suddenly begin to work, and you forget about it—but this is a common pitfall that means you've lost a very powerful security tool.
|
||||
|
||||
Threats are rising alongside the rise of containers, microservices, and distributed architecture. This is due to an old, well-known issue: velocity. The advantage of containers is that they enable you to move fast, do more, and change quickly. This means container adoption has gone off the roof, but the speed it affords also means you will encounter more issues and vulnerabilities. This happens naturally when you're doing more things faster and quicker.
|
||||
|
||||
### How to mitigate threats
|
||||
|
||||
As Sun Tzu said, "The wise warrior avoids the battle." This quote really resonates when it comes to containers' basic defense. To avoid problems (battles), make sure that your container host is secure and that you can use SELinux as your first line of defense.
|
||||
|
||||
SELinux is an open source project released in 2000 and integrated into the Linux kernel in 2003. According to [Red Hat's explainer][3], "SELinux is a security architecture for [Linux systems][4] that allows administrators to have more control over who can access the system. It was originally developed by the United States National Security Agency (NSA) as a series of patches to the [Linux kernel][5] using Linux Security Modules (LSM)."
|
||||
|
||||
### Get started
|
||||
|
||||
When you think about containers, the first thing that probably comes into mind is [Docker][6]. Docker started a container adoption revolution after it emerged in 2013. It is one of the main reasons that containers exploded in popularity, but as mentioned above, the high level of adoption increased users' vulnerability to security risks.
|
||||
|
||||
Before you can secure your Docker containers with SELinux, you need to set some things up.
|
||||
|
||||
#### Prerequisites:
|
||||
|
||||
* CentOS 8/RHEL 8 installed and configured
|
||||
* Docker CE installed and configured
|
||||
* Two accounts created: root and non-root (`mcalizo` in the examples below)
|
||||
|
||||
|
||||
|
||||
If you need to set up Docker on your RHEL 8/CentOS 8 server, you can follow these [instructions][7]. If you're running RHEL 8, you need to remove the pre-installed Podman and runc packages before beginning.
|
||||
|
||||
First, make sure SELinux is enabled:
|
||||
|
||||
|
||||
```
|
||||
[mcalizo@Rhel82 ~]$ sestatus
|
||||
SELinux status: enabled
|
||||
SELinuxfs mount: /sys/fs/selinux
|
||||
SELinux root directory: /etc/selinux
|
||||
Loaded policy name: targeted
|
||||
Current mode: enforcing
|
||||
Mode from config file: enforcing
|
||||
Policy MLS status: enabled
|
||||
Policy deny_unknown status: allowed
|
||||
Memory protection checking: actual (secure)
|
||||
Max kernel policy version: 31
|
||||
[mcalizo@Rhel82 ~]$
|
||||
```
|
||||
|
||||
Then, verify your OS version and that Docker is running. Log in as root and run:
|
||||
|
||||
|
||||
```
|
||||
[root@rhel82 ~]# cat /etc/redhat-release
|
||||
Red Hat Enterprise Linux release 8.2 (Ootpa)
|
||||
[root@rhel82 ~]#
|
||||
|
||||
[root@rhel82 ~]# systemctl status docker
|
||||
● docker.service - Docker Application Container Engine
|
||||
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
|
||||
Active: active (running) since Wed 2020-10-28 19:10:14 EDT; 15s ago
|
||||
Docs: <https://docs.docker.com>
|
||||
Main PID: 30768 (dockerd)
|
||||
Tasks: 8
|
||||
Memory: 39.0M
|
||||
CGroup: /system.slice/docker.service
|
||||
└─30768 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
|
||||
|
||||
Oct 28 19:10:13 rhel82.home.labs.com dockerd[30768]: time="2020-10-28T19:10:13.889602941-04:00" level=error msg=">
|
||||
Oct 28 19:10:13 rhel82.home.labs.com dockerd[30768]: time="2020-10-28T19:10:13.903413613-04:00" level=warning msg>
|
||||
Oct 28 19:10:13 rhel82.home.labs.com dockerd[30768]: time="2020-10-28T19:10:13.903427451-04:00" level=warning msg>
|
||||
Oct 28 19:10:13 rhel82.home.labs.com dockerd[30768]: time="2020-10-28T19:10:13.903538271-04:00" level=info msg="L>
|
||||
Oct 28 19:10:14 rhel82.home.labs.com dockerd[30768]: time="2020-10-28T19:10:14.132060506-04:00" level=info msg="D>
|
||||
Oct 28 19:10:14 rhel82.home.labs.com dockerd[30768]: time="2020-10-28T19:10:14.308943088-04:00" level=info msg="L>
|
||||
Oct 28 19:10:14 rhel82.home.labs.com dockerd[30768]: time="2020-10-28T19:10:14.319438549-04:00" level=info msg="D>
|
||||
Oct 28 19:10:14 rhel82.home.labs.com dockerd[30768]: time="2020-10-28T19:10:14.319570298-04:00" level=info msg="D>
|
||||
Oct 28 19:10:14 rhel82.home.labs.com dockerd[30768]: time="2020-10-28T19:10:14.333419209-04:00" level=info msg="A>
|
||||
Oct 28 19:10:14 rhel82.home.labs.com systemd[1]: Started Docker Application Container Engine
|
||||
```
|
||||
|
||||
Check your Docker version:
|
||||
|
||||
|
||||
```
|
||||
[root@rhel82 ~]# docker --version
|
||||
Docker version 19.03.13, build 4484c46d9d
|
||||
```
|
||||
|
||||
### Hack your host
|
||||
|
||||
One of the best ways to understand a problem is to experience it. So, I'll show you how easy it is to inject malicious code into a Docker host if your security is not set up properly.
|
||||
|
||||
To be able to do something bad on the Docker host, the malicious non-root user (`mcalizo` in this tutorial) must be part of the group that can instantiate Docker containers.
|
||||
|
||||
First, confirm what group the `mcalizo` user belongs to:
|
||||
|
||||
|
||||
```
|
||||
[root@Rhel82 ~]# groups mcalizo
|
||||
mcalizo : mcalizo
|
||||
```
|
||||
|
||||
The output shows that `mcalizo` belongs only to its own group. This means `mcalizo` can't instantiate Docker containers and will get this error if it tries:
|
||||
|
||||
|
||||
```
|
||||
[mcalizo@Rhel82 ~]$ docker run -it --rm centos:latest /bin/sh
|
||||
docker: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.40/containers/create: dial unix /var/run/docker.sock: connect: permission denied.
|
||||
See 'docker run --help'.
|
||||
```
|
||||
|
||||
To allow `mcalizo` to instantiate the container, add the user to the `docker` group:
|
||||
|
||||
|
||||
```
|
||||
[root@Rhel82 ~]# usermod -G docker -a mcalizo
|
||||
[root@Rhel82 ~]# groups mcalizo
|
||||
mcalizo : mcalizo docker
|
||||
```
|
||||
|
||||
Next, deploy a `fedora:latest` container and log into the instantiated container to explore it:
|
||||
|
||||
|
||||
```
|
||||
[mcalizo@Rhel82 ~]$ docker run -it --rm fedora:latest /bin/sh
|
||||
Unable to find image 'fedora:latest' locally
|
||||
latest: Pulling from library/fedora
|
||||
ee7e89337106: Pull complete
|
||||
Digest: sha256:b9ec86d36fca7b1d3de39cd7c258e8d90c377d312c21a7748071ce49069b8db4
|
||||
Status: Downloaded newer image for fedora:latest
|
||||
sh-5.0# cat /etc/redhat-release
|
||||
Fedora release 33 (Thirty Three)
|
||||
```
|
||||
|
||||
While you're logged into the newly created container, you can see you are automatically logged in as root:
|
||||
|
||||
|
||||
```
|
||||
sh-5.0# whoami
|
||||
root
|
||||
sh-5.0#
|
||||
```
|
||||
|
||||
As `root` user, you can do anything in this container, which means you can exploit the container host and do a lot of damage. Because you can instantiate a container, you can do things to the host even if you are not part of the host's sudoers account.
|
||||
|
||||
Exit the container you just created, and create a new container to demonstrate the exploit:
|
||||
|
||||
|
||||
```
|
||||
[mcalizo@Rhel82 ~]$ docker run -it --rm -v /:/exploit fedora:latest /bin/bash
|
||||
[root@131043f2e306 /]#
|
||||
```
|
||||
|
||||
The [-v option][8] mounts the Docker host's `/` directory to the container under the `/exploit` directory:
|
||||
|
||||
|
||||
```
|
||||
[root@131043f2e306 /]#ls exploit/
|
||||
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
|
||||
```
|
||||
|
||||
Because it is mounted, you can do _anything_ on the Docker host. For example, you can delete files, edit specific configurations to harm the system, or even install a Trojan horse application or other malware to steal important information.
|
||||
|
||||
### Why does this happen?
|
||||
|
||||
You may be wondering why this is possible since SELinux is in enforcing mode. Dig deeper into SELinux to see where things went wrong.
|
||||
|
||||
Verify that SELinux has a [Docker context][9]:
|
||||
|
||||
|
||||
```
|
||||
[mcalizo@Rhel82 ~]$ ps -eZ | grep docker
|
||||
system_u:system_r:container_runtime_t:s0 30768 ? 00:00:04 dockerd
|
||||
[mcalizo@Rhel82 ~]$
|
||||
```
|
||||
|
||||
As expected, it does. This means SELinux manages the Docker daemon. Inspect the Docker daemon to see if SELinux is enabled by default:
|
||||
|
||||
|
||||
```
|
||||
[mcalizo@Rhel82 ~]$ docker info | grep Security -A3
|
||||
Security Options:
|
||||
seccomp
|
||||
Profile: default
|
||||
Kernel Version: 4.18.0-193.el8.x86_64
|
||||
```
|
||||
|
||||
SELinux is _not_ enabled by default. This is the problem! To fix it, enable SELinux to control and manage Docker by updating or creating the file `/etc/docker/daemon.json` as [documented here][10] (you must have root access to do this):
|
||||
|
||||
|
||||
```
|
||||
[root@Rhel82 ~]# cat /etc/docker/daemon.json
|
||||
{
|
||||
"selinux-enabled": true
|
||||
}
|
||||
[root@Rhel82 ~]#
|
||||
[root@Rhel82 ~]# systemctl restart docker
|
||||
```
|
||||
|
||||
After creating or updating the file and restarting Docker, you should see that SELinux support is enabled in the Docker daemon:
|
||||
|
||||
|
||||
```
|
||||
[root@Rhel82 ~]# systemctl restart docker
|
||||
[mcalizo@Rhel82 root]$ docker info | grep Security -A3
|
||||
Security Options:
|
||||
seccomp
|
||||
Profile: default
|
||||
selinux
|
||||
[mcalizo@Rhel82 root]$
|
||||
```
|
||||
|
||||
While it's still possible to mount a specific filesystem in your Docker host on your Docker container, updating or accessing the file is no longer allowed:
|
||||
|
||||
|
||||
```
|
||||
[mcalizo@Rhel82 root]$ docker run -it --rm -v /:/exploit fedora:latest /bin/bash
|
||||
[root@ecb5836da1f6 /]# touch /exploit/etc/shadow.sh
|
||||
touch: cannot touch '/exploit/etc/shadow.sh': Permission denied
|
||||
[root@ecb5836da1f6 /]#
|
||||
```
|
||||
|
||||
### Learn more
|
||||
|
||||
Your first line of defense in the container world depends on how strongly you set up your container hosts' operating system. There are numerous ways to implement Linux security, including options available on the market to augment your security posture.
|
||||
|
||||
SELinux is an additional layer of security that is built into [Linux distributions][11] by default. To take advantage of it and protect your system against compromise, make sure SELinux remains on.
|
||||
|
||||
If you want to learn more, see:
|
||||
|
||||
* [How to install Docker CE on CentOS 8 / RH][7]
|
||||
* [Docker security cheat sheet][12]
|
||||
* [dockerd documentation][10]
|
||||
* [Use volumes documentation][8]
|
||||
* [What is SELinux?][3]
|
||||
|
||||
|
||||
|
||||
Few things in the Linux world evoke a strong reaction like SELinux , the security enhancement for...
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/selinux-containers
|
||||
|
||||
作者:[Mike Calizo][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/mcalizo
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/EDU_UnspokenBlockers_1110_A.png?itok=x8A9mqVA (Three closed doors)
|
||||
[2]: https://en.wikipedia.org/wiki/Security-Enhanced_Linux
|
||||
[3]: https://www.redhat.com/en/topics/linux/what-is-selinux
|
||||
[4]: https://www.redhat.com/en/topics/linux/what-is-linux
|
||||
[5]: https://www.redhat.com/en/topics/linux/what-is-the-linux-kernel
|
||||
[6]: https://opensource.com/resources/what-docker
|
||||
[7]: https://www.linuxtechi.com/install-docker-ce-centos-8-rhel-8/
|
||||
[8]: https://docs.docker.com/storage/volumes/
|
||||
[9]: https://docs.docker.com/engine/reference/commandline/context/
|
||||
[10]: https://docs.docker.com/engine/reference/commandline/dockerd/
|
||||
[11]: https://www.redhat.com/en/topics/linux/whats-the-best-linux-distro-for-you
|
||||
[12]: https://cheatsheetseries.owasp.org/cheatsheets/Docker_Security_Cheat_Sheet.html
|
||||
@@ -0,0 +1,224 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Automate your tasks with this Ansible cheat sheet)
|
||||
[#]: via: (https://opensource.com/article/20/11/ansible-cheat-sheet)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
Automate your tasks with this Ansible cheat sheet
|
||||
======
|
||||
Start automating your repetitive tasks by getting to know Ansible's
|
||||
modules, YAML structure, and more.
|
||||
![Cheat Sheet cover image][1]
|
||||
|
||||
Ansible is one of the primary tools in the world of [automation and orchestration][2] because of its broad usefulness and flexibility. However, those same traits are the very reason it can be difficult to get started with [Ansible][3]. It isn't a graphical application, and yet it also isn't a scripting or programming language. But like a programming language, the answer to the common question of "what can I do with it?" is "everything," which makes it difficult to know where to begin doing _anything_.
|
||||
|
||||
Here's how I view Ansible: It's an "engine" that uses other people's modules to accomplish complex tasks you describe in a special "pseudo-code" text format called YAML. This means you need to have three things to get started with Ansible:
|
||||
|
||||
1. Ansible
|
||||
2. A repetitive task you want to automate
|
||||
3. A basic understanding of YAML
|
||||
|
||||
|
||||
|
||||
This article aims to help you get started with these three things.
|
||||
|
||||
### Install Ansible
|
||||
|
||||
Part of Ansible's widespread popularity can be attributed to how it lets you (the user) completely ignore what operating system (OS) you're targeting. Generally, you don't have to think about whether your Ansible task will be executed on Linux, macOS, Windows, or BSD. Ansible takes care of the messy platform-specific bits for you.
|
||||
|
||||
However, to _run_ Ansible, you do need to have Ansible installed somewhere. The computer where Ansible is installed is called the _control node_. Any computer that Ansible targets is called a _host_.
|
||||
|
||||
Only the control node needs to have Ansible installed.
|
||||
|
||||
If you're on Linux, you can install Ansible from your software repository with your package manager.
|
||||
|
||||
As yet, Windows is unable to serve as an Ansible control node, although the more progress it makes toward [POSIX][4], the better things look for it, so keep a close watch on Microsoft's [Windows Subsystem for Linux (WSL)][5] product.
|
||||
|
||||
On macOS, you can use a third-party package manager like [Homebrew][6] or [MacPorts][7].
|
||||
|
||||
### Ansible modules
|
||||
|
||||
Ansible is just an engine. The parts that do 90% of the work are [Ansible modules][8]. These modules are programmed by lots of different people all over the world. Some have become so popular that the Ansible team adopts them and helps maintain them.
|
||||
|
||||
As a user, much of your interaction with Ansible is directed to its modules. Choosing a module is like choosing an app on your phone or computer: you have a task you want done, so you look for an Ansible module that claims to assist.
|
||||
|
||||
Most modules are tied to specific applications. For instance, the [file][9] module helps create and manage files. The [authorized_key][10] module helps manage SSH keys, [Database][11] modules help control and manipulate databases, and so on.
|
||||
|
||||
Part of deciding on a task to offload onto Ansible is finding the module that will help you accomplish it. Ansible plays run _tasks_, and tasks consist of Ansible keywords or Ansible modules.
|
||||
|
||||
### YAML and Ansible
|
||||
|
||||
The YAML text format is a highly structured way to feed instructions to an application, making it almost a form of code. Like a programming language, you must write YAML according to a specific set of syntax rules. A YAML file intended for Ansible is called a _playbook_, and it consists of one or more Ansible _plays_.
|
||||
|
||||
An Ansible play, like YAML, has a very limited structure. There are two kinds of instructions: a _sequence_ and a _mapping_. An Ansible play, as with YAML, always starts with 3 dashes (`---`).
|
||||
|
||||
#### Sequences
|
||||
|
||||
A _sequence_ element is a list. For example, here's a list of penguin species in YAML:
|
||||
|
||||
|
||||
```
|
||||
\---
|
||||
\- Emperor
|
||||
\- Gentoo
|
||||
\- Yellow-eyed
|
||||
\----
|
||||
```
|
||||
|
||||
#### Mapping
|
||||
|
||||
A _mapping_ element consists of two parts: a key and a value. A _key_ in Ansible is usually a keyword defined by an Ansible module, and the value is sometimes Boolean (`true` or `false`) or some choice of parameters defined by the module, or something arbitrary, a variable, depending on what's being set.
|
||||
|
||||
Here's a simple mapping in YAML:
|
||||
|
||||
|
||||
```
|
||||
\---
|
||||
\- Name: "A list of penguin species"
|
||||
\----
|
||||
```
|
||||
|
||||
#### Sequences and mapping
|
||||
|
||||
These two data types aren't mutually exclusive.
|
||||
|
||||
You can put a sequence into a mapping. In such a case, the sequence is a value for a mapping's key. When placing a sequence into a mapping, you indent the sequence so that it is a "descendent" (or "child") of its key:
|
||||
|
||||
|
||||
```
|
||||
\---
|
||||
\- Penguins:
|
||||
- Emperor
|
||||
- Gentoo
|
||||
- Yellow-eyed
|
||||
\----
|
||||
```
|
||||
|
||||
You can also place mappings in a sequence:
|
||||
|
||||
|
||||
```
|
||||
\---
|
||||
\- Penguin: Emperor
|
||||
\- Mammal: Gnu
|
||||
\- Planar: Demon
|
||||
\----
|
||||
```
|
||||
|
||||
Those are all the rules you need to be familiar with to write valid YAML.
|
||||
|
||||
### Write an Ansible play
|
||||
|
||||
For Ansible plays, whether you use a sequence or a mapping (or a mapping in a sequence, or a sequence in a mapping) is dictated by Ansible or the Ansible module you're using. The "language" of Ansible mostly speaks to configuration options to help you determine how and where your play will run. A quick reference to all Ansible keywords is available in the [Ansible playbook documentation][12].
|
||||
|
||||
From the list of keywords, you can create an opening for your play. You start with three dashes because that's how a YAML file always starts. Then you give your play a name in a mapping block. You must also define what hosts (computers) you want the play to run on, and how Ansible is meant to reach the computer.
|
||||
|
||||
For this example, I set the host to `localhost`, so the play runs only on _this_ computer, and the connection type to `local` (the default is `ssh`):
|
||||
|
||||
|
||||
```
|
||||
\---
|
||||
\- name: "My first Ansible play"
|
||||
hosts: localhost
|
||||
connection: local
|
||||
\----
|
||||
```
|
||||
|
||||
Most of the YAML you'll write in a play is probably configuration options for a specific Ansible module. To find out what instructions a module expects from your Ansible play, refer to that module's documentation. [Modules maintained by Ansible][8] are documented on Ansible's website.
|
||||
|
||||
For this example, I'll use the debug module.
|
||||
|
||||
![Documentation for Ansible debugger module][13]
|
||||
|
||||
On [debug's documentation page][14], three parameters are listed:
|
||||
|
||||
* `msg` is an optional string to print to the terminal.
|
||||
* `var` is an optional variable, interpreted as a string. This is mutually exclusive with `msg`, so you can use one or the other—not both.
|
||||
* `verbosity` is an integer you can use to control how verbose this debugger is. Its default is 0, so there is no threshold to pass.
|
||||
|
||||
|
||||
|
||||
It's a simple module, but the thing to look for is the YAML data type of each parameter. Can you determine from my description whether these parameters are a sequence (a list) or a mapping (a key and value pair)? Knowing what kind of YAML block to use in your play helps you write valid plays.
|
||||
|
||||
Here's a simple "hello world" Ansible play:
|
||||
|
||||
|
||||
```
|
||||
\---
|
||||
\- name: "My first Ansible play"
|
||||
hosts: localhost
|
||||
connection: local
|
||||
tasks:
|
||||
- name: "Print a greeting"
|
||||
debug:
|
||||
msg: "Hello world"
|
||||
\----
|
||||
```
|
||||
|
||||
Notice that the play contains a `task`. This task is a mapping that contains a sequence of exactly one item. The item in this task is `name` (and its value), the module being used by the task, and a `msg` parameter (along with its value). These are all part of the task mapping, so they're indented to show inheritance.
|
||||
|
||||
You can test this Ansible play by using the `ansible-playbook` command with the `--check` option:
|
||||
|
||||
|
||||
```
|
||||
$ ansible-playbook --check hello.yaml
|
||||
PLAY [My first Ansible play] *************************
|
||||
|
||||
TASK [Gathering Facts] *******************************
|
||||
ok: [localhost]
|
||||
|
||||
TASK [Print a greeting] ******************************
|
||||
ok: [localhost] => {
|
||||
"msg": "Hello world"
|
||||
}
|
||||
|
||||
PLAY RECAP *******************************************
|
||||
localhost: ok=2 changed=0 unreachable=0 failed=0
|
||||
```
|
||||
|
||||
It's verbose, but you can debug the message in your "Print a greeting" task, right where you put it.
|
||||
|
||||
### Testing modules
|
||||
|
||||
Using a new Ansible module is like trying out a new Linux command. You read its documentation, study its syntax, and then try some tests.
|
||||
|
||||
There are at least two other modules you could use to write a "hello world" play: [assert][15] and [meta][16]. Try reading through the documentation for these modules, and see if you can create a simple test play based on what you learned above.
|
||||
|
||||
For further examples of how modules are used to get work done, visit [Ansible Galaxy][17], an open source repository of community-contributed plays.
|
||||
|
||||
### For a quick reference of important Ansible commands, download our [Ansible cheat sheet][18].
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/ansible-cheat-sheet
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/coverimage_cheat_sheet.png?itok=lYkNKieP (Cheat Sheet cover image)
|
||||
[2]: https://opensource.com/article/20/11/orchestration-vs-automation
|
||||
[3]: https://opensource.com/resources/what-ansible
|
||||
[4]: https://opensource.com/article/19/7/what-posix-richard-stallman-explains
|
||||
[5]: https://docs.microsoft.com/en-us/windows/wsl/install-win10
|
||||
[6]: https://opensource.com/article/20/6/homebrew-mac
|
||||
[7]: https://opensource.com/article/20/11/macports
|
||||
[8]: https://docs.ansible.com/ansible/2.8/modules/modules_by_category.html
|
||||
[9]: https://docs.ansible.com/ansible/2.8/modules/file_module.html#file-module
|
||||
[10]: https://docs.ansible.com/ansible/2.8/modules/authorized_key_module.html#authorized-key-module
|
||||
[11]: https://docs.ansible.com/ansible/2.8/modules/list_of_database_modules.html
|
||||
[12]: https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html
|
||||
[13]: https://opensource.com/sites/default/files/screenshot_from_2020-11-13_20-44-15.png (Documentation for Ansible debugger module)
|
||||
[14]: https://docs.ansible.com/ansible/2.8/modules/debug_module.html
|
||||
[15]: https://docs.ansible.com/ansible/2.8/modules/assert_module.html
|
||||
[16]: https://docs.ansible.com/ansible/2.8/modules/meta_module.html
|
||||
[17]: https://galaxy.ansible.com/
|
||||
[18]: https://opensource.com/downloads/ansible-cheat-sheet
|
||||
@@ -0,0 +1,151 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Day 9: Generating a lot of nonsense with an RNN)
|
||||
[#]: via: (https://jvns.ca/blog/2020/11/19/day-9--generating-a-lot-of-nonsense-with-an-rnn/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
Day 9: Generating a lot of nonsense with an RNN
|
||||
======
|
||||
|
||||
Hello! On Monday I posted about [generating faces with sketch-rnn][1], which I did using a pre-trained RNN model.
|
||||
|
||||
I want to train that model to genreate more complicated faces (which may or may not work!), but I decided that since I knew literally nothing about neural networks it would be good to start with something simpler: [this char-rnn model from Karpathy that generates text that sounds vaguely Shakespearean][2].
|
||||
|
||||
After spending some time playing with Tensorflow, I decided to use PyTorch with the [fast.ai][3] helper libraries because it’s what my friend Ray was using for his project.
|
||||
|
||||
Here are some initial things I’ve learned about training neural networks. All of this is pretty disjointed and I still have no idea what I’m doing.
|
||||
|
||||
### there are a lot of tensors
|
||||
|
||||
All the data seems to be tensors! A 1-d tensor is a vector, a 2-d tensor is a matrix, and a 3-d tensor is, well, who knows. This is a little new but I have some vague intuition about tensor products from learning about quantum computing ten [years][4] ago so this seems okay.
|
||||
|
||||
They seem not too bad to manipulate, like `tensor.flatten()` will flatten a multidimensional tensor into a vector. I still feel a bit uncertain about the exact order things get flattened in, I need to experiment & think it through.
|
||||
|
||||
The word “dimension” for tensors is also used in a different way than I expected, like I’d usually think that the “dimension” of a 8x9 matrix is 72 (becuase that’s the dimension of the vector space of 8x9 matrices), but in Torch land the “dimension” of a 8x9 matrix seems to be 2. That seems fine though.
|
||||
|
||||
### there are a lot of dimension mismatches
|
||||
|
||||
I’ve spent a lot of hours over the last couple of days staring at error messages like
|
||||
|
||||
```
|
||||
ValueError: Expected target size (77, 64) got torch.Size (77, 70)
|
||||
```
|
||||
|
||||
Some reasons I’ve gotten errors like this so far
|
||||
|
||||
* I tried to pass a 3-dimensional tensor to a loss function that wanted a 2-dimensional tensor
|
||||
* I forgot to embed my input data (which is a bunch of class labels) into a higher dimensional space so that every number turns into a 64-dimensional vector
|
||||
* I multiplied a vector by a matrix with the wrong dimensions
|
||||
|
||||
|
||||
|
||||
Something that I find a bit confusing about the tensors and dimension mismatches is that a lot of the time you seem to be able to pass in both a 2-dimensional tensor and a 3-dimensional tensor to the same method. For example, if I have a 2x3 matrix, I can multiply that by a 3x4 tensor, or by a 3x4x89 tensor, or by a 3x92x12x238 tensor, or whatever. This corresponds to what I remember about tensors from quantum computing, but I find a bit harder to think about in terms of numbers in a matrix on a computer.
|
||||
|
||||
I tweeted about this and a bunch of people agreed with me that they have also spent a bunch of time debugging dimension mismatches so at least I’m not alone :)
|
||||
|
||||
### the cross entropy loss in pytorch isn’t the cross entropy
|
||||
|
||||
A “loss function” is basically a function you use to check how similar 2 vectors are. Lower is better.
|
||||
|
||||
Today I got pretty confused because I was trying to compute the cross entropy loss for two identical vectors, and the result wasn’t 0! I thought that the result was going to be 0, because the vectors were identical!
|
||||
|
||||
It turns out that in PyTorch the “cross entropy loss” of x and y isn’t actually the [cross entropy][5] of x and y (which would be 0 if x and y are identical!), instead it’s `cross_entropy(softmax(x), y)` – you apply a “softmax” function to x first.
|
||||
|
||||
### it goes a LOT faster with a GPU
|
||||
|
||||
At some point I was training a model on a CPU, and then I switched to a GPU and every batch trained literally 10x faster.
|
||||
|
||||
### colab is pretty useful
|
||||
|
||||
I’ve been using Google’s [Colab][6], which seems to be a fork of Jupyter notebook. It comes with some free GPUs that you can use, which is nice.
|
||||
|
||||
The main annoying thing I’ve run into about Colab is that they pretty aggressively kill your running notebooks if they’re idle to reduce resource usage. This is actually fine on its own (you can save your data to Google Drive and restore it!).
|
||||
|
||||
BUT as far as I can tell, if I want to use the Google Drive to get my files, I need to reauthenticate the notebook to Google Drive every single time by clicking a link and pasting in an OAuth (or something) code. I don’t really understand why it can’t just authenticate me once and then have it work forever.
|
||||
|
||||
### it’s bad if your training loss never goes down
|
||||
|
||||
I’ve been having the same problem for most of yesterday and today, which is that I have a model and some training data, and when I try to train the model my training loss never improves, which measn that basically the model isn’t training.
|
||||
|
||||
And then when I make predictions from the model, I get results like this:
|
||||
|
||||
```
|
||||
eto e enaih eet codosueonites st tne esee ob nmnoesnrertieieeu ooe
|
||||
```
|
||||
|
||||
which makes it seem like it’s learned _something_ – those letters are common letters in the English language, sure! It’s better than generating `zxisqqqqxw`, which is more like the results I’d expect if the network hadn’t learned anything at all. But it definitely hasn’t learned a lot.
|
||||
|
||||
### some code that does not work
|
||||
|
||||
If you’re interested in what some code for an RNN that DOES NOT WORK looks like, here’s [the code I’ve written so far][7]
|
||||
|
||||
the neural network part looks like this:
|
||||
|
||||
```
|
||||
class RNN(nn.Module):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.i2h = nn.Linear(nv, nh) # Wxh
|
||||
self.h2h = nn.Linear(nh, nh) # Whh
|
||||
self.h2o = nn.Linear(nh, nv) # Why
|
||||
self.hidden = torch.zeros(1, nh).cuda()
|
||||
|
||||
def forward(self, input):
|
||||
x = self.i2h(torch.nn.functional.one_hot(input, num_classes=nv).type(torch.FloatTensor).cuda())
|
||||
y = self.h2h(self.hidden)
|
||||
hidden = torch.tanh(y + x)
|
||||
self.hidden = hidden.detach()
|
||||
z = self.h2o(hidden)
|
||||
return z
|
||||
```
|
||||
|
||||
and it basically sets up a bunch of matrices that are meant to correspond to this code from Karpathy’s blog post:
|
||||
|
||||
```
|
||||
def step(self, x):
|
||||
# update the hidden state
|
||||
self.h = np.tanh(np.dot(self.W_hh, self.h) + np.dot(self.W_xh, x))
|
||||
# compute the output vector
|
||||
y = np.dot(self.W_hy, self.h)
|
||||
return y
|
||||
```
|
||||
|
||||
but unlike his code, it does not generate text that looks vaguely Shakespeare after I train it, it generates gibberish! Maybe tomorrow I will find out why.
|
||||
|
||||
Here’s a snippet of code that samples from the model’s output probability vector using a “temperature” – at a very low temperature it just always picks the letter that the model thinks is most likely (which by the way right now in my case is LITERALLY ALWAYS A SPACE which is also a sign that something is wrong). At higher temperatures it might pick another likely letter.
|
||||
|
||||
```
|
||||
temperature = 1
|
||||
prediction_vector = F.softmax(learn.model(x)[0]/temperature)
|
||||
v.textify(torch.multinomial(prediction_vector, 1).flatten(), sep='')
|
||||
```
|
||||
|
||||
### that’s all!
|
||||
|
||||
As usual when I learn things I am mostly trying to do it without reading any books or watching any videos – there’s this whole video course from <https://fast.ai> that seems pretty good, but for whatever reason I prefer to just bang my head against a problem I’m trying to solve until I get VERY CONFUSED and then resort to reading things that might help me understand what’s going on then. So that’s the plan, we’ll see how it goes.
|
||||
|
||||
It’s been pretty fun so far, I know a bunch of things about loss functions that I didn’t know before at least, and now I kind of know what a softmax is!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2020/11/19/day-9--generating-a-lot-of-nonsense-with-an-rnn/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://lots-of-sketchrnn-faces.netlify.app/
|
||||
[2]: https://karpathy.github.io/2015/05/21/rnn-effectiveness/
|
||||
[3]: https://www.fast.ai/
|
||||
[4]: https://github.com/jvns/masters-thesis/
|
||||
[5]: https://en.wikipedia.org/wiki/Cross_entropy
|
||||
[6]: https://colab.research.google.com/
|
||||
[7]: https://gist.github.com/jvns/ce24d85c9d645c32b0d552b69359979f
|
||||
@@ -0,0 +1,51 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (The relationship between labor and open source)
|
||||
[#]: via: (https://opensource.com/article/20/11/working-public-review)
|
||||
[#]: author: (Joshua Allen Holm https://opensource.com/users/holmja)
|
||||
|
||||
The relationship between labor and open source
|
||||
======
|
||||
Readers of all levels of involvement in open source will find value in
|
||||
this informative and illustrative book.
|
||||
![Stack of books for reading][1]
|
||||
|
||||
The open source software ecosystem is a fascinating blend of personal passion projects and massive, collaborative corporate efforts. Sometimes there is even overlap when the passion projects are actually key components of the huge corporate projects or when a corporate project is abandoned by the original maintainers, but someone takes up the cause and makes it their personal passion project. Regardless of where an open source project falls on that spectrum, there is a lot of labor involved in the development and maintenance of open source projects. [_Working in Public: The Making and Maintenance of Open Source Software_][2] by Nadia Eghbal thoroughly examines the relationship between labor and open source.
|
||||
|
||||
In addition to an introduction and conclusion, _Working in Public_ consists of five chapters split between two parts: "Part 1: How People Make" and "Part 2: How People Maintain." The first part covers "GitHub as a platform," "The Structure of an Open Source Project," and "Roles, Incentives, and Relationships." The second part explores "The Work Required by Software" and "Managing the Costs of Production." Each chapter deftly covers the topic at hand and provides copious footnotes and end-notes to support the information presented.
|
||||
|
||||
**
|
||||
|
||||
**
|
||||
|
||||
**
|
||||
|
||||
_![Book cover][3]_
|
||||
|
||||
_Working in Public_ begins with a brief overview of the history of open software development that covers the free software movement, the open source movement, and the modern, GitHub-centered version of open, which Eghbal notes is more focused on the practical aspects of open than philosophical aspects that are key parts of the free software and open source movements. The book provides a solid history of open source software development before transitioning to an examination of how things—and people—work in open source. There are many examples of the whys and the hows of working in open source, often including amusing analogies to make these complex topics easy to understand for readers who are not already enmeshed in open source. Eghbal’s writing manages to strike a balance between informative and entertaining.
|
||||
|
||||
There is sometimes a tendency to treat coding as the only form of open source labor, but _Working in Public_ does not make that mistake. For example, there is an interesting discussion in the introduction about maintainers having to spend time dealing with minor pull requests instead of writing in-depth, substantive code of their own. Throughout the book, Eghbal explores labor in open source beyond just code. It provides valuable insights for readers of all levels and all manners of open source involvement—project maintainers, casual contributors, and users.
|
||||
|
||||
The only flaw with _Working in Public_ is that it tries to serve as both an introduction to open source and an exploration of the labor involved in open source projects. This makes the book extremely approachable for readers with limited knowledge of open source, but that means that more experienced readers might find themselves skipping over lengthy passages that explain basic concepts. For example, half of the first full paragraph on page 12 is a parenthetical explanation of what software libraries are. The tendency to overexplain basic concepts does not distract from the overarching narrative too much, but it might turn some readers off before they get to the interesting parts.
|
||||
|
||||
Overall, I really recommend picking up a copy of this book. It is enjoyable to read and does a good job of covering its topic, though there are issues brought up in some of the footnotes that are worthy of further exploration by the author or by other researchers. Even the parts of the book that overexplain basic concepts are interesting but, as noted above, may fail to capture the attention of readers who are already well versed in open source development. Minor issues aside, the book provides an engaging overview of the history of open source and an insightful examination of the labor involved in open source development. In short, _Working in Public_ is worth reading whether you are a maintainer, contributor, or user of open source.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/working-public-review
|
||||
|
||||
作者:[Joshua Allen Holm][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/holmja
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/books_read_list_stack_study.png?itok=GZxb9OAv (Stack of books for reading)
|
||||
[2]: https://www.amazon.com/dp/0578675862/
|
||||
[3]: https://opensource.com/sites/default/files/uploads/working_in_public.jpg (Book cover)
|
||||
@@ -0,0 +1,56 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Day 10: Training an RNN to count to three)
|
||||
[#]: via: (https://jvns.ca/blog/2020/11/20/day-10--training-an-rnn-to-count-to-three/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
Day 10: Training an RNN to count to three
|
||||
======
|
||||
|
||||
Yesterday I was trying to train an RNN to generate English that sounds kind of like Shakespeare. That was not working, so today I instead tried to do something MUCH simpler: train an RNN to generate sequences like
|
||||
|
||||
```
|
||||
0 1 2 0 1 2 0 1 2 0 1 2
|
||||
```
|
||||
|
||||
and slightly more complicated sequences like
|
||||
|
||||
```
|
||||
0 1 2 1 0 1 2 1 0 1 2 1 0 1 2 1 0
|
||||
```
|
||||
|
||||
I used (I think) the exact same RNN that I couldn’t get to work yesterday to generate English by training it on Shakespeare, so it was cool to see that I could at least use it for this much simpler task (memorize short sequences of numbers).
|
||||
|
||||
### the jupyter notebook
|
||||
|
||||
It’s late so I won’t explain all the code in this blog post, but here’s the PyTorch code I wrote to train the RNN to count to three.
|
||||
|
||||
* Here it is as a [github gist][1]
|
||||
* and [here it is on Colab][2] if you want to run it yourself
|
||||
|
||||
|
||||
|
||||
In the gist there are a few experiments with different sequence lengths, like (unsurprisingly) it takes longer to train it to memorize a sequence of length 20 than a sequence of length 5.
|
||||
|
||||
### simplifying is nice
|
||||
|
||||
I’m super happy that I got an RNN to do something that I actually understand! I feel pretty hopeful that on Monday I’ll be able to go back to the character RNN problem of trying to get the RNN to generate English words now that I have this simpler thing working.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2020/11/20/day-10--training-an-rnn-to-count-to-three/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://gist.github.com/jvns/b8804fb9d0672ce147a28d22648b4bd7
|
||||
[2]: https://colab.research.google.com/gist/jvns/b8804fb9d0672ce147a28d22648b4bd7/rnn-123.ipynb
|
||||
@@ -0,0 +1,98 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How we develop success metrics for open source events)
|
||||
[#]: via: (https://opensource.com/article/20/11/chaoss-open-source-events)
|
||||
[#]: author: (Neofytos Kolokotronis https://opensource.com/users/neofytosk)
|
||||
|
||||
How we develop success metrics for open source events
|
||||
======
|
||||
The CHAOSS App Ecosystem Working Group is establishing ways to measure
|
||||
how well virtual and in-person events meet their goals.
|
||||
![Metrics and a graph illustration][1]
|
||||
|
||||
As many open source communities grow larger and older, they may face problems managing members' engagement. People turn towards metrics to understand large systems and prioritize resources, but there has not been a consensus set of metrics for understanding open source communities.
|
||||
|
||||
The Community Health Analytics Open Source Software ([CHAOSS][2]) project, a Linux Foundation-sponsored community of industry professionals and academics, is working to solve this problem by defining metrics for open source projects. The CHAOSS project focused first on developing metrics for open source event organizers because open source communities often depend on events like hackathons, meetups, conferences, and user group meetings to grow their communities and work on important project updates.
|
||||
|
||||
The [CHAOSS App Ecosystem Working Group][3], which developed the metrics for events and worked together on this article, is comprised of [members][4] who have organized and participated in many open source events. While we developed these metrics to help the GNOME and KDE communities, we believe they can help other open source event organizers create their own metrics strategy. We also hope that more people will be inspired by this work and join us to improve it.
|
||||
|
||||
### How we began
|
||||
|
||||
The CHAOSS App Ecosystem Working Group emerged from the [SCALE 18x][5] conference in March 2020, when CHAOSS and GNOME members began talking about how to measure the [Linux App Summit][6] (LAS) community, an event co-hosted by GNOME and KDE.
|
||||
|
||||
We realized that we did not have sufficient data to measure our progress towards LAS's goals, and that hindered our ability to make important decisions to support those goals. For LAS (and the whole Linux app ecosystem) to thrive, we recognized the need to be more data-driven in our approach. We also realized the importance of extending this mindset to other similarly organized communities.
|
||||
|
||||
From our experience at [CHAOSScon][7], we found opportunities to partner with the CHAOSS community around open source metrics. Therefore, we organized ourselves under the CHAOSS project, which provides a platform for working on metrics.
|
||||
|
||||
We chose the name App Ecosystem Working Group because one of the GNOME and KDE communities' primary goals is to grow the Linux app ecosystem. Although we had the GNOME and KDE communities in mind at the start, we are creating the metrics to help everyone involved in the effort to grow the Linux app ecosystem.
|
||||
|
||||
We chose to begin with the event organizer use case because of the nature of events: Events tend to have clearly defined boundaries, with a set start and end date, a list of registered attendees, and activities like talks, presentations, and workshops. This clarity does not generally exist in open source projects and communities, where the various projects, contributors, and users are less often strictly defined.
|
||||
|
||||
The GNOME and KDE communities both had events coming up in 2020, so we believed we could iterate faster using feedback gathered from the events we organized, separately and together.
|
||||
|
||||
### Approach to data gathering
|
||||
|
||||
The CHAOSS project uses the [goal-question-metric][8] (GQM) approach to gathering data. One problem with metrics is that often we try to measure everything without understanding how the data will be helpful. But data should help inform decisions. Therefore, the GQM approach starts with a list of high-level goals that are important to a particular persona.
|
||||
|
||||
The goals are the community's strategic objectives. For each goal, we look at questions that help determine whether we are achieving the goal. Metrics then provide quantitative information that helps answer those questions.
|
||||
|
||||
Before diving into metrics, the App Ecosystem Working Group brainstormed goals and the personas that those goals affect. We collected [17 different goals][9], spread across seven stakeholder personas, that a community or project ecosystem might have.
|
||||
|
||||
We collected and curated these goals from community members' experience in major open source projects like GNOME and KDE. Although each community is different, we think most of these goals are relevant to and will help a wide variety of open source projects.
|
||||
|
||||
### Metrics for event organizers
|
||||
|
||||
The [full list of metrics for event organizers][10] focus on three goals that event organizers care about:
|
||||
|
||||
* Attracting and retaining contributors
|
||||
* Understanding company contributions to an event
|
||||
* Ensuring events contribute towards diversity goals and closing skill gaps in the community
|
||||
|
||||
|
||||
|
||||
We came up with 19 questions that event organizers have about how well they are doing in reaching these goals. The metrics are directly linked to these questions to give the event organizers actionable insights.
|
||||
|
||||
### Privacy implications
|
||||
|
||||
While this work was developed by and for the GNOME and KDE communities, we hope that the metrics will help other open source communities.
|
||||
|
||||
While GNOME and KDE have not implemented the metrics yet (and do not yet have a timeline to do so), one known limitation is privacy concerns around data collection. Every geographic location has laws that may limit data collection, which open source and free software projects must take into account.
|
||||
|
||||
Once GNOME and KDE implement these metrics in their communities, they plan to share the legal considerations they took into account.
|
||||
|
||||
### Join us
|
||||
|
||||
We are hopeful that these metrics will be useful to open source event organizers interested in integrating virtual and in-person events into their community-building and engagement strategies.
|
||||
|
||||
If you'd like to participate in developing these metrics, we welcome your experience, insight, and voice! The CHAOSS App Ecosystem Working Group [meets biweekly][11]; please join us.
|
||||
|
||||
You can also communicate with us asynchronously through our [GitHub repository][3]. For more information on other ways to contribute or connect with us, we encourage you to visit the [CHAOSS community participation page][12].
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/chaoss-open-source-events
|
||||
|
||||
作者:[Neofytos Kolokotronis][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/neofytosk
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/metrics_graph_stats_blue.png?itok=OKCc_60D (Metrics and a graph illustration)
|
||||
[2]: https://chaoss.community/
|
||||
[3]: https://github.com/chaoss/wg-app-ecosystem
|
||||
[4]: https://github.com/chaoss/wg-app-ecosystem#contributors
|
||||
[5]: https://www.socallinuxexpo.org/scale/18x
|
||||
[6]: https://linuxappsummit.org/
|
||||
[7]: https://chaoss.community/chaosscon-2020-eu/
|
||||
[8]: https://en.wikipedia.org/wiki/GQM
|
||||
[9]: https://docs.google.com/document/d/1ghREXIO5C9PLiwXMtouOR4AjPLGz9pD34LIxO8N2-xo/edit
|
||||
[10]: https://github.com/chaoss/wg-app-ecosystem/blob/master/event-organizers.md
|
||||
[11]: https://github.com/chaoss/wg-app-ecosystem#workflow
|
||||
[12]: https://chaoss.community/participate
|
||||
113
sources/tech/20201120 What do open source product teams do.md
Normal file
113
sources/tech/20201120 What do open source product teams do.md
Normal file
@@ -0,0 +1,113 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (What do open source product teams do?)
|
||||
[#]: via: (https://opensource.com/article/20/11/open-source-product-teams)
|
||||
[#]: author: (Scott McCarty https://opensource.com/users/fatherlinux)
|
||||
|
||||
What do open source product teams do?
|
||||
======
|
||||
Product managers play an essential role in creating differentiated value
|
||||
that customers will pay for.
|
||||
![a checklist for a team][1]
|
||||
|
||||
If you go to any hip product management conference, you'll hear about product teams. At a minimum, a product team has a product manager, but it often includes roles in marketing, technical architecture, and even user experience (UX). Previous articles in this series have covered [open source as a supply chain model][2] and [defining products in the open source software supply chain][3], and this article specifically focuses on the role of product management within the product team.
|
||||
|
||||
### Who's on the product team?
|
||||
|
||||
Product managers and product marketing managers are the two most common product management roles, but product management can be further split into any number of roles, including competitive analysis, business strategy, sales enablement, revenue growth, content creation, sales tools, and more. With a very large product, even the product management role may be broken up into separate roles. You may even hear titles like technical marketing manager, product evangelist, and business owner, not to mention people-management roles for groups of individual contributor roles. For the purpose of this article, I refer to all of these roles collectively as "product management."
|
||||
|
||||
Product management is a [tough career][4], and there are many frameworks for learning and understanding it. One of the oldest and most mature is the [Pragmatic Framework][5], which defines 37 different areas of responsibility. The Pragmatic Framework is a bit too complex for this article. Instead, I'll emphasize a subset of tasks that are applicable in open source products:
|
||||
|
||||
* **Market problems:** Talk to customers and figure out what they need
|
||||
* **Product roadmap:** Determine what features will be added to the product and when
|
||||
* **Build:** Invest in building technology in-house
|
||||
* **Buy:** Purchase technology from another company
|
||||
* **Partner:** Deliver a solution to a customer by leveraging a partner's technology
|
||||
* **Pricing:** Determine the price
|
||||
* **Packaging:** Determine what's included in the price
|
||||
* **Channel training:** Train the salespeople so that they can educate potential customers
|
||||
|
||||
|
||||
|
||||
The rest of this series will look into how these different roles affect and are affected by an open source supply chain.
|
||||
|
||||
### Build, buy, or partner?
|
||||
|
||||
Which is more important, the business need or the technology? This is probably the classic paradox of business strategy. The answer is neither. Execution is what matters. The product management team is tasked with creating and retaining customers. This can be done by building technology, buying technology, or partnering to acquire technology or services that, when combined, provide value to customers. For example, if customers need an encryption feature that's missing from a software product, the product manager can:
|
||||
|
||||
* Ask engineering to build it, test it, document it, and maintain it.
|
||||
* Influence the executive team to buy a company or software package that provides it. (However, less than 2% of product managers have access to P&L data, [much less the budget to buy companies][6].)
|
||||
* Deliver it to the customer through a verified partner. If a partner already provides a solution, this is the quickest way to deliver a solution, but it could raise the product's price or require the customer to purchase additional software.
|
||||
|
||||
|
||||
|
||||
With traditional proprietary software products and services, this could mean building, buying, or partnering for a foundational piece of software, like a database. With products built on open source software, this can be thought of as choosing an open source project as a supplier. The purchase is made by contributing engineering time, code, documentation, testing, infrastructure, etc. Because open source is not free as in beer, somebody has to write it, test it, document it, etc. It's very difficult to provide value to customers if you don't contribute upstream.
|
||||
|
||||
This combination of built, bought, and partner-delivered capabilities is what differentiates a product, whether open source or proprietary. Proprietary licensing does not differentiate a product. Let me repeat: _proprietary licensing does not differentiate a product_. People confuse proprietary licensing with providing value to a customer. Proprietary licenses are a perfectly valid and useful way to monetize users, but they do not provide customers with more value. Licenses do not create value; they help extract it. If you believe [open core][7] or hybrid licensing are the only way to make money with open source, read this paragraph five times until it sinks in (hint, focus on creating value).
|
||||
|
||||
Both open source and proprietary products must create value. Customers buy capabilities as part of a solution (i.e., new things they couldn't do before). If product management spends more brainpower on delivering capabilities than determining what can be held back with proprietary licensing, the customer will be happier, more loyal, and receive more value.
|
||||
|
||||
### Types of products built on open source
|
||||
|
||||
Most modern software products are delivered by adding new value to the value provided by the open source supply chain. This could include extra downstream testing, documentation, quality engineering, performance testing, security testing, industry certifications, a partner ecosystem, training, professional services, or even extra proprietary code not included upstream (open core). By considering this new model, many of the old debates about open source can be clarified:
|
||||
|
||||
* **Open source products:** The entire supply chain of code that goes into the product is open source. This can include multiple upstream projects like enterprise Linux distributions or sophisticated products like [Red Hat Satellite][8] or [OpenShift][9].
|
||||
* **Open core products:** Some of the supply chain of code that goes into the product is open source while other parts are proprietary. This mix of licensing can be used to control pricing, packaging, and distribution. It can also have the downside of putting engineering contributions to the product at odds with the open source supply chain (see _[Goodbye open core—good riddance to bad rubbish][10]_).
|
||||
* **Paid software-as-a-service products:** The supply chain of SaaS products can be made up of open source languages and libraries, while the business logic built in-house is often proprietary. This allows product managers to tightly control pricing and packaging through very measurable distribution channels. There are many examples of online companies using this model, including customer resource management platforms, databases, caching layers, identity management, document management, and office and email solutions.
|
||||
* **Free SaaS products:** The supply chain of free SaaS products (e.g., Facebook, Google Search, YouTube, etc.) is essentially the same as paid SaaS products. Instead of tightly controlling the pricing and packaging, the product is monetized through user data or advertisements.
|
||||
* **Cloud providers vs. software vendors:** The recent interest in and creation of new quasi-open source licenses like the [Server Side Public License][11], [Redis Source Available License][12], or [PolyForm][13] are better understood by thinking of open source as a supply chain and SaaS as a pricing and packaging model. These new licenses exert some control on how buyers from the open source supply chain can price and package their products (e.g., limiting how a large cloud provider can deliver a service built on freely available code and binaries). This is not unheard of, even in traditional manufacturing supply chains. It's a defensive play because these licenses don't deliver new value to customers.
|
||||
* **Open source as awareness:** In this model, the buzz around the upstream project is used to deliver awareness for the products built on it. In marketing, awareness of a technology is a critical first step for having a product's customers build on it. For example, if users are aware of and believe in Kubernetes, they are potential customers for products built on Kubernetes; when people looking for a Kubernetes solution hear that your product is built on Kubernetes, they immediately become potential customers. In a way, this is similar to Lenovo laptops advertising "Intel inside" or [Arm & Hammer laundry detergent advertising OxiClean][14] as part of their supply chain. If you like OxiClean, you'll love Arm & Hammer detergent.
|
||||
* **Open core as marketing:** This goes a step further than open source as awareness. A single vendor almost always controls the upstream open source projects that go into open core products. They attempt to use the supply chain, often unsuccessfully, to generate market awareness in what's perceived to be free or inexpensive marketing and lead generation. Open core products advertise that they include the open source project to provide core value propositions. Going back to the Arm & Hammer example: If you like open source, you'll love our proprietary software with open source goodness inside.
|
||||
|
||||
|
||||
|
||||
### The supply chain
|
||||
|
||||
Continuing the analogy from my [last article][3], when General Motors develops a car, the product team doesn't tell Bosch what fuel injectors they want. They tell Bosch how much power the new vehicle will generate, how much towing capacity it needs to have, etc. They give Bosch a set of technical requirements. Then Bosch provides GM with a fuel-injection solution that not only includes the fuel injectors but also the wiring harnesses and perhaps even software that makes it run. It's cheaper and often better quality to rely on a supply chain for components that are shared among virtually every vehicle in the marketplace.
|
||||
|
||||
Like an automobile, the sum of a software product is greater than the individual parts. When a manufacturer delivers a car, it's more than the braking, steering, power plant, infotainment system, financing, and mechanical service program. It has an associated brand, build quality, reliability, and an experience. Most of the parts aren't differentiated between vendors. Software products, especially ones built on an open source supply chain, are no different. Product management needs to differentiate their products from the underlying software components in the supply chain. The value of a software product is a layer of differentiation built on top of a supply chain of dependencies. This value is what product management must focus on.
|
||||
|
||||
### Differentiated value
|
||||
|
||||
Product management is not about picking and choosing what bugs are fixed upstream or downstream. It's not about holding back enough value in the open source project so that users purchase the product. It's not about coming up with special licenses to monetize an open source project's user base. It's about creating differentiated value that customers will pay for. It's about listening to their needs, internalizing them, and knowing them intimately. It's about influencing a supply chain, switching supply chains, and building a partner ecosystem that gives your product gravity.
|
||||
|
||||
Product managers who think about differentiated value on top of an open source supply chain can easily answer the following questions:
|
||||
|
||||
* As an open source product manager, should I attend conferences for the upstream projects? _Sure, because it's like attending a trade show for one of your suppliers._
|
||||
* How should product management handle a situation where the upstream project isn't delivering what their customers need? _Add more investment. If the open source community is healthy, it will produce what you need._
|
||||
* What should product management do when an upstream community is struggling with contributions or is unhealthy? _The same thing that a manufacturer would do if their supplier lost contracts with their two biggest competitors because they were failing: switch suppliers._
|
||||
|
||||
|
||||
|
||||
In the next article, I will delve into the distinct value created in products, focusing on the value that upstream projects can't provide. If product management is done well, there is no unnatural tension between upstream suppliers and downstream products. When done right, both the upstream projects and downstream products create unique and differentiated value that satisfies the needs of users and customers alike.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/open-source-product-teams
|
||||
|
||||
作者:[Scott McCarty][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/fatherlinux
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/checklist_hands_team_collaboration.png?itok=u82QepPk (a checklist for a team)
|
||||
[2]: https://opensource.com/article/20/10/open-source-supply-chain
|
||||
[3]: https://opensource.com/article/20/10/defining-product-open-source
|
||||
[4]: https://www.mindtheproduct.com/forget-product-management-tough-career/
|
||||
[5]: https://www.pragmaticinstitute.com/framework
|
||||
[6]: http://developmentcorporate.com/2019/04/02/the-myth-of-the-product-management-pl/
|
||||
[7]: https://medium.com/open-consensus/2-open-core-definition-examples-tradeoffs-e4d0c044da7c
|
||||
[8]: https://en.wikipedia.org/wiki/Satellite_(software)
|
||||
[9]: https://en.wikipedia.org/wiki/OpenShift
|
||||
[10]: https://medium.com/@adamhjk/goodbye-open-core-good-riddance-to-bad-rubbish-ae3355316494
|
||||
[11]: https://www.mongodb.com/licensing/server-side-public-license
|
||||
[12]: https://redislabs.com/wp-content/uploads/2019/03/Redis-Source-Available-License-PDF-2.pdf
|
||||
[13]: https://polyformproject.org/licenses/
|
||||
[14]: https://www.armandhammer.com/laundry/liquid-laundry-detergent/liquid-laundry-detergent/plus-oxiclean-with-fade-defense-liquid-laundry-detergent
|
||||
@@ -0,0 +1,67 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Open source brings musicians together virtually)
|
||||
[#]: via: (https://opensource.com/article/20/11/open-source-drum-bugle-corps)
|
||||
[#]: author: (Vicki Walker https://opensource.com/users/vicki-walker)
|
||||
|
||||
Open source brings musicians together virtually
|
||||
======
|
||||
The open source ethos is embedded in many areas of life, including music
|
||||
and art.
|
||||
![Drums ][1]
|
||||
|
||||
When the COVID-19 pandemic began canceling live music events in spring 2020, it wasn't just the big arena shows, music festivals, and small, local venues that suffered—the big annual marching band competition leagues, like [Drum Corps International][2] (DCI) and [WGI World Championships][3], were also called off. This was a huge disappointment for the thousands of musicians and band directors who were already preparing for the spring and summer competition season. But the members of the [Drumcorps subreddit][4] saw it as an opportunity to take drum corps virtual.
|
||||
|
||||
The [Open Source Drum and Bugle Corps][5] (OSDBC) is one such organization bringing open source to drum corps. The group was founded on the principles of openness, inclusiveness, and collaboration. And, like most things in open source, OSDBC was created to solve a problem.
|
||||
|
||||
OSDBC launched in early April 2020, in the early weeks of US pandemic-related shutdowns, and immediately had 100 members in the group's Discord; within half a year, its membership approached 400 brass and percussion players across the United States. To date, the organization has released two performances and is working on its third.
|
||||
|
||||
All of the content OSDBC produces—including guides, documentation, sheet music, clicktracks, and virtual performances—is released under [Creative Commons][6] licenses so that other groups can replicate the project if they wish.
|
||||
|
||||
### Who's involved?
|
||||
|
||||
Most OSDBC members are professional musicians, teachers, and high school and college students. Because the drum corps community is relatively small, there's a strong possibility that students and their teachers might be participating together on the same project, leading to uncomfortableness or even potential legal issues relating to students and teachers being in the same group chats. Therefore, OSDBC members work anonymously, wearing hats and sunglasses in their performance videos, and many use pseudonyms within the group. It's an imperfect solution, but it does provide "plausible deniability" about someone's identity, says one member, a high school senior who serves on the project's all-volunteer staff.
|
||||
|
||||
Anonymity also levels the playing field among musicians with different levels of experience, which helps open up collaboration and personal growth opportunities, including the ability to ask for help without fear of embarrassment or judgment.
|
||||
|
||||
Members come from multiple disciplines—musicians, artists, composers, and audio engineers—volunteering their time and talent to produce multimedia content. Because everyone is a volunteer, there is no cost to be involved in the project.
|
||||
|
||||
### How it works
|
||||
|
||||
Unlike a typical drum corps, OSDBC can't perform together in person, first, because of the pandemic, and second because of the members' geographical distribution. Selecting a composition is a community effort, with votes taken both to pick a public domain musical piece to play and then to choose a composer (based on members' original compositions of the selected piece). The winner of the composition contest distributes sheet music, clicktracks, and advice for playing the piece, and the audio and video editors share [submission guidelines][7] about how to record and submit videos for inclusion in the project. Approximately a fifth of the members have submitted performances for each of the first three projects.
|
||||
|
||||
Once the submission deadline has passed and all the performances are collected, the design team begins to mix the individual videos into a cohesive performance.
|
||||
|
||||
Because editing a performance is a significant amount of work that requires specialized audio and video production knowledge and tools, the work is distributed among section leaders (e.g., trumpets, low brass, percussion, etc.). They use a mix of open source and proprietary software, chiefly [Audacity][8], Reaper, and FL Studios, to produce the videos; while open source is the preference, the members must use the applications that they are familiar with and have access to at their universities or jobs.
|
||||
|
||||
### Get involved
|
||||
|
||||
OSDBC plans to continue working together even after the COVID-19 pandemic. Given the uncertainty around the 2021 drum corps season, with WGI planning a virtual season and DCI weighing the feasibility of an abbreviated season, OSDBC provides a valuable option for the tight-knit community to collaborate and make music together.
|
||||
|
||||
The project eagerly welcomes new performers, organizers, arrangers, and others. If you would like to get involved, visit the [website][5] and join the project's [Discord][9] for updated information and opportunities to participate in the next project.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/open-source-drum-bugle-corps
|
||||
|
||||
作者:[Vicki Walker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/vicki-walker
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/drums-beat.png?itok=vhr6E_f1 (Drums )
|
||||
[2]: https://www.dci.org/
|
||||
[3]: https://www.wgi.org/
|
||||
[4]: https://www.reddit.com/r/drumcorps/
|
||||
[5]: https://opensourcedbc.org/
|
||||
[6]: https://creativecommons.org/
|
||||
[7]: https://opensourcedbc.org/info-for-members/
|
||||
[8]: https://opensource.com/education/16/9/audacity-classroom
|
||||
[9]: https://discord.gg/6QmCSK3
|
||||
@@ -0,0 +1,114 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to Save the Output of a Command to a File in Linux Terminal [Beginner’s Tip])
|
||||
[#]: via: (https://itsfoss.com/save-command-output-to-file-linux/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
|
||||
How to Save the Output of a Command to a File in Linux Terminal [Beginner’s Tip]
|
||||
======
|
||||
|
||||
When you run a command or script in the Linux terminal, it prints the output on the screen for your immediate viewing.
|
||||
|
||||
There will be times when you need to save the output to a file for future references. Now, [you can surely copy and paste in Linux terminal][1] but there are better ways to save the output of a shell script or command in Linux command line. Let me show them to you.
|
||||
|
||||
### Method 1: Use redirection to save command output to file in Linux
|
||||
|
||||
You can [use redirection in Linux for this purpose][2]. With redirection operator, instead of showing the output on the screen, it goes to the provided file.
|
||||
|
||||
* The > redirects the command output to a file replacing any existing content on the file.
|
||||
* The >> redirects adds the command output at the end of the existing content (if any) of the file.
|
||||
|
||||
|
||||
|
||||
Use the STDOUT redirection operator > for redirecting the output to a file like this:
|
||||
|
||||
```
|
||||
command > file.txt
|
||||
```
|
||||
|
||||
If the file.txt doesn’t exist, it will be created automatically. If you use the > redirect again with the same file, the file content is replaced by the new output.
|
||||
|
||||
The example below demonstrates it better. It first saves the output of _ls -l_ command. And then later, it replaces the content of the file with the output of _ls *.c_ command.
|
||||
|
||||
![Redirecting command output to file][3]
|
||||
|
||||
If you don’t want to lose the content of the existing file while saving the output of a script or command, use the redirection operation in append mode with >>.
|
||||
|
||||
```
|
||||
command >> file.txt
|
||||
```
|
||||
|
||||
This example demonstrates it better:
|
||||
|
||||
![Redirecting command output to file in append mode][4]
|
||||
|
||||
Even here if the file doesn’t exist, it is created automatically.
|
||||
|
||||
Bonus Tip: Save Linux command output as well as error to a file
|
||||
|
||||
If your Linux command returns an error, it doesn’t get saved in the file. You can save both the command output and command error in the same file using 2>&1 like this:
|
||||
|
||||
**command > file.txt 2>&1**
|
||||
|
||||
Basically, 0 stands for standard input, 1 for standard output and 2 for standard error. Here, you are redirecting (>) standard error (2) to same address (&) as standard output (1).
|
||||
|
||||
### Method 2: Use tee command to display the output and save it to a file as well
|
||||
|
||||
By the way, did you notice that when you send the command output to a file, you cannot see it anymore on the display? The [tee command in Linux][5] solves this problem for you.
|
||||
|
||||
Like a tee pipe that sends water stream into two directions, the tee command send the output to the display as well as to a file (or as input to another command). You can use it like this:
|
||||
|
||||
```
|
||||
command | tee file.txt
|
||||
```
|
||||
|
||||
Again, the file will be created automatically, if it doesn’t exist already.
|
||||
|
||||
You may also use the tee command in append mode with option -a in this manner:
|
||||
|
||||
```
|
||||
command | tee -a file.txt
|
||||
```
|
||||
|
||||
Let me demonstrate it with some easy to follow examples:
|
||||
|
||||
![][6]
|
||||
|
||||
I have used simple Linux commands in my examples. But rest assured, you can use these methods to save the output of bash scripts as well.
|
||||
|
||||
### Note: Avoid pipe pitfall while saving command output to file
|
||||
|
||||
You probably are familiar with pipe redirection. You may use it to combine Linux commands but you cannot pipe the output to a file. It will result in error that filename command not found:
|
||||
|
||||
![][7]
|
||||
|
||||
This is because pipe redirects the output of one command to input of another command. And in this case, you give it a file name while it was expecting a command.
|
||||
|
||||
If you are new to Linux command line, I hope this quick tutorial added to your Linux knowledge a bit. [I/O redirection][8] is an essential concept that one should be aware of.
|
||||
|
||||
As always, questions and suggestions are always welcome.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/save-command-output-to-file-linux/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/abhishek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/copy-paste-linux-terminal/
|
||||
[2]: https://linuxhandbook.com/redirection-linux/
|
||||
[3]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/redirecting_command_output_to_file_in_linux.png?resize=741%2C456&ssl=1
|
||||
[4]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/redirecting_command_output_to_file.png?resize=741%2C494&ssl=1
|
||||
[5]: https://linuxhandbook.com/tee-command/
|
||||
[6]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/display-and-save-linux-command-output.png?resize=741%2C494&ssl=1
|
||||
[7]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/pipe-output-to-file-linux.png?resize=687%2C266&ssl=1
|
||||
[8]: https://tldp.org/LDP/abs/html/io-redirection.html#FTN.AEN17894
|
||||
@@ -0,0 +1,152 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (6 predictions for JavaScript build tools)
|
||||
[#]: via: (https://opensource.com/article/20/11/javascript-build-tools)
|
||||
[#]: author: (Shedrack Akintayo https://opensource.com/users/shedrack-akintayo)
|
||||
|
||||
6 predictions for JavaScript build tools
|
||||
======
|
||||
The JavaScript frontend tooling ecosystem is dynamic and competitive,
|
||||
and only the best survive.
|
||||
![Magnifying glass on code][1]
|
||||
|
||||
Code used in production is different from development code. In production, you need to build packages that run fast, manage dependencies, automate tasks, load external modules, and more. [JavaScript][2] tools that make it possible to turn development code into production code are called _build tools._
|
||||
|
||||
The reason frontend code is "built" can be explained by looking into the various build steps and their importance.
|
||||
|
||||
### Steps in building frontend code
|
||||
|
||||
There are four steps involved in building frontend code:
|
||||
|
||||
#### 1\. Transpiling
|
||||
|
||||
Transpiling lets developers take advantage of the newest, hottest updates to languages and extensions and maintain browser compatibility. Here is an example using [Babel][3]:
|
||||
|
||||
|
||||
```
|
||||
// arrow function syntax in array map
|
||||
const double = [1, 2, 3].map((num) => num * 2);
|
||||
// after being transpiled
|
||||
const double = [1, 2, 3].map(function(num) {
|
||||
return num * 2;
|
||||
});
|
||||
```
|
||||
|
||||
#### 2\. Bundling
|
||||
|
||||
Bundling is the process of taking all the "import" or "require" statements; finding the matching JavaScript snippets, packages, and libraries; adding them to the appropriate scope; and packaging it all into one big JavaScript file. Commonly used bundlers include Browserify, Webpack, and Parcel.
|
||||
|
||||
#### 3\. Minifing
|
||||
|
||||
Minifying reduces the final file size by removing white space and code comments. You can take this a step further by adding an obfuscate step, which changes variable names and method names, obscuring the code, so it is less human-readable once it's delivered to the client. Here is an example using Grunt:
|
||||
|
||||
|
||||
```
|
||||
// before minifying
|
||||
const double = [1, 2, 3].map(function(num) {
|
||||
return num * 2;
|
||||
});
|
||||
// after minifying
|
||||
const double = [1, 2, 3].map(function(num) {
|
||||
return num * 2;
|
||||
});
|
||||
```
|
||||
|
||||
#### 4\. Packaging
|
||||
|
||||
After all the steps above are finished, the compatible, bundled, minified/obfuscated file must be put somewhere. Packaging is the process of putting the results of the above steps somewhere specified by the developer. This is usually done by the bundler.
|
||||
|
||||
### Frontend build tools
|
||||
|
||||
Frontend tooling and build tools can be split into the following categories:
|
||||
|
||||
* Package managers: NPM, Yarn
|
||||
* Transpilers: Babel, etc.
|
||||
* Bundlers: Webpack, Parcel, Browserify
|
||||
* Minifiers: UglifyJS, Packer, Minify, etc.
|
||||
|
||||
|
||||
|
||||
There are a variety of build tools you can use in the JavaScript ecosystem, including the following.
|
||||
|
||||
#### Grunt and Bower
|
||||
|
||||
[Grunt][4] was introduced as a command-line tool that provided just one script to specify and configure tasks. [Bower][5] followed shortly after as a way to manage client-side packages. The two, along with NPM, seemed to fulfill the majority of automation needs and were used regularly together. The problem with Grunt was that it didn't provide developers the freedom to configure more complex task chains, while Bower made developers manage twice as many packages as usual because it separates frontend and backend packages (i.e., Bower components vs. Node modules).
|
||||
|
||||
**The future of Grunt and Bower:** Grunt and Bower are on their way out of the JavaScript tooling ecosystem, but there are several replacements.
|
||||
|
||||
#### Gulp and Browserify
|
||||
|
||||
[Gulp][6] was released a year and a half after Grunt. It felt natural. Writing a build script in JavaScript compared to JSON gave freedom. You could write functions, create variables on the fly, use conditionals anywhere—not that this would make for a particularly good-looking build script, but it was possible. [Browserify][7] and Gulp can be used in tandem. Browserify allows NPM packages (which are for backend Node servers) to be brought into the frontend, making Bower obsolete. It also looks and feels better, with one package manager for the frontend and backend.
|
||||
|
||||
**The future of Gulp:** Gulp can be improved to match the current popular build tools, but this is entirely up to the creators. It is still in use but not as popular as it was before.
|
||||
|
||||
#### Webpack and NPM/Yarn scripts
|
||||
|
||||
[Webpack][8] is the hottest kid on the block in modern frontend development tooling. Webpack is an open-source JavaScript module bundler. It is made primarily for JavaScript, but it can transform frontend assets like HTML, CSS, and images if the corresponding loaders are included. With Webpack, you can also write scripts like Gulp and execute them with [NPM/Yarn][9].
|
||||
|
||||
**The future of Webpack:** Webpack is currently the hottest thing in the JavaScript tooling ecosystem, and all the JS cool kids are using React and Webpack these days. It is currently in version 4 and not going anywhere anytime soon.
|
||||
|
||||
#### Parcel
|
||||
|
||||
[Parcel][10] is a web application bundler that launched in 2018 and is differentiated by its developer experience. It offers blazing-fast performance utilizing multicore processing and requires zero configuration. Parcel is also a new kid on the block, but adoption hasn't been fast, especially for large applications. Developers prefer to use Webpack over Parcel because of the former's extensive support and customizability.
|
||||
|
||||
**The future of Parcel:** Parcel is very easy to use, it is faster than Webpack if you measure bundle and build time, and it also offers a better developer experience. The reason Parcel hasn't been adopted much might be because it's still relatively new. Parcel has a very bright future in the frontend build tools ecosystem, and it will be around for a while.
|
||||
|
||||
#### Rollup
|
||||
|
||||
[Rollup][11] is a module bundler for JavaScript that compiles small pieces of code into something larger and more complex, such as a library or an application. It is advisable to use Rollup when building a library with minimal third-party imports.
|
||||
|
||||
**The future of Rollup:** Rollup is super-cool and is being adopted rapidly. It has great features and will be part of the frontend tooling ecosystem for a long time.
|
||||
|
||||
### Learn more
|
||||
|
||||
The JavaScript tooling ecosystem is dynamic and competitive, and only the best tools survive. In the future, we will see tools that require less (or no) configuration, better customizability, more extensibility, and higher speed.
|
||||
|
||||
The tools you use for an application's frontend are a personal call that you need to make based on your project's requirements. Choose what works best for you, and most of the time, there are tradeoffs.
|
||||
|
||||
For more information, see:
|
||||
|
||||
* [JavaScript tooling: The evolution and future of JS/frontend build tools][12]
|
||||
* [Tools and modern workflow for frontend developers][13]
|
||||
* [Modern frontend: The tools and build process explained][14]
|
||||
* [Best build tools in frontend development][15]
|
||||
|
||||
|
||||
|
||||
* * *
|
||||
|
||||
_This article originally appeared on [Shedrack Akintayo's blog][16] and is republished with his permission._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/javascript-build-tools
|
||||
|
||||
作者:[Shedrack Akintayo][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/shedrack-akintayo
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/find-file-linux-code_magnifying_glass_zero.png?itok=E2HoPDg0 (Magnifying glass on code)
|
||||
[2]: https://www.javascript.com/
|
||||
[3]: https://babeljs.io/
|
||||
[4]: https://gruntjs.com/
|
||||
[5]: https://bower.io/
|
||||
[6]: https://gulpjs.com/
|
||||
[7]: http://browserify.org/
|
||||
[8]: https://webpack.js.org/
|
||||
[9]: https://github.com/yarnpkg/yarn
|
||||
[10]: https://parceljs.org/
|
||||
[11]: https://rollupjs.org/guide/en/
|
||||
[12]: https://qmo.io/blog/javascript-tooling-the-evolution-and-future-of-js-front-end-build-tools/
|
||||
[13]: https://blog.logrocket.com/tools-and-modern-workflow-for-front-end-developers-505c7227e917/
|
||||
[14]: https://medium.com/@trevorpoppen/modern-front-end-the-tools-and-build-process-explained-36641b5c1a53
|
||||
[15]: https://www.developerdrive.com/best-build-tools-frontend-development/
|
||||
[16]: https://www.sheddy.xyz/posts/javascript-build-tools-past-and-beyond
|
||||
@@ -0,0 +1,233 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (A beginner's guide to Kubernetes Jobs and CronJobs)
|
||||
[#]: via: (https://opensource.com/article/20/11/kubernetes-jobs-cronjobs)
|
||||
[#]: author: (Mike Calizo https://opensource.com/users/mcalizo)
|
||||
|
||||
A beginner's guide to Kubernetes Jobs and CronJobs
|
||||
======
|
||||
Use Jobs and CronJobs to control and manage Kubernetes pods and
|
||||
containers.
|
||||
![Ships at sea on the web][1]
|
||||
|
||||
[Kubernetes][2] is the default orchestration engine for containers. Its options for controlling and managing pods and containers include:
|
||||
|
||||
1. Deployments
|
||||
2. StatefulSets
|
||||
3. ReplicaSets
|
||||
|
||||
|
||||
|
||||
Each of these features has its own purpose, with the common function to ensure that pods run continuously. In failure scenarios, these controllers either restart or reschedule pods to ensure the services in the pods continue running.
|
||||
|
||||
As the [Kubernetes documentation explains][3], a Kubernetes Job creates one or more pods and ensures that a specified number of the pods terminates when the task (Job) completes.
|
||||
|
||||
Just like in a typical operating system, the ability to perform automated, scheduled jobs without user interaction is important in the Kubernetes world. But Kubernetes Jobs do more than just run automated jobs, and there are multiple ways to utilize them through:
|
||||
|
||||
1. Jobs
|
||||
2. CronJobs
|
||||
3. Work queues (this is beyond the scope of this article)
|
||||
|
||||
|
||||
|
||||
Sounds simple right? Well, maybe. Anyone who works on containers and microservice applications knows that some require services to be transient so that they can do specific tasks for applications or within the Kubernetes clusters.
|
||||
|
||||
In this article, I will go into why Kubernetes Jobs are important, how to create Jobs and CronJobs, and when to use them for applications running on the Kubernetes cluster.
|
||||
|
||||
### Differences between Kubernetes Jobs and CronJobs
|
||||
|
||||
Kubernetes Jobs are used to create transient pods that perform specific tasks they are assigned to. [CronJobs][4] do the same thing, but they run tasks based on a defined schedule.
|
||||
|
||||
Jobs play an important role in Kubernetes, especially for running batch processes or important ad-hoc operations. Jobs differ from other Kubernetes controllers in that they run tasks until completion, rather than managing the desired state such as in Deployments, ReplicaSets, and StatefulSets.
|
||||
|
||||
### How to create Kubernetes Jobs and CronJobs
|
||||
|
||||
With that background in hand, you can start creating Jobs and CronJobs.
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
To do this exercise, you need to have the following:
|
||||
|
||||
1. A working Kubernetes cluster; you can install it with either:
|
||||
* [CentOS 8][5]
|
||||
* [Minikube][6]
|
||||
2. The [kubectl][7] Kubernetes command line
|
||||
|
||||
|
||||
|
||||
Here is the Minikube deployment I used for this demonstration:
|
||||
|
||||
|
||||
```
|
||||
$ minikube version
|
||||
minikube version: v1.8.1
|
||||
|
||||
$ kubectl cluster-info
|
||||
Kubernetes master is running at <https://172.17.0.59:8443>
|
||||
KubeDNS is running at <https://172.17.0.59:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy>
|
||||
|
||||
$ kubectl get nodes
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
minikube Ready master 88s v1.17.3
|
||||
```
|
||||
|
||||
#### Kubernetes Jobs
|
||||
|
||||
Just like anything else in the Kubernetes world, you can create Kubernetes Jobs with a definition file. Create a file called `sample-jobs.yaml` using your favorite editor.
|
||||
|
||||
Here is a snippet of the file that you can use to create an example Kubernetes Job:
|
||||
|
||||
|
||||
```
|
||||
apiVersion: batch/v1 ## The version of the Kubernetes API
|
||||
kind: Job ## The type of object for jobs
|
||||
metadata:
|
||||
name: job-test
|
||||
spec: ## What state you desire for the object
|
||||
template:
|
||||
metadata:
|
||||
name: job-test
|
||||
spec:
|
||||
containers:
|
||||
- name: job
|
||||
image: busybox ## Image used
|
||||
command: ["echo", "job-test"] ## Command used to create logs for verification later
|
||||
restartPolicy: OnFailure ## Restart Policy in case container failed
|
||||
```
|
||||
|
||||
Next, apply the Jobs in the cluster:
|
||||
|
||||
|
||||
```
|
||||
`$ kubectl apply -f sample-jobs.yaml`
|
||||
```
|
||||
|
||||
Wait a few minutes for the pods to be created. You can view the pod creation's status:
|
||||
|
||||
|
||||
```
|
||||
`$ kubectl get pod –watch`
|
||||
```
|
||||
|
||||
After a few seconds, you should see your pod created successfully:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
job-test 0/1 Completed 0 11s
|
||||
```
|
||||
|
||||
Once the pods are created, verify the Job's logs:
|
||||
|
||||
|
||||
```
|
||||
`$ kubectl logs job-test job-test`
|
||||
```
|
||||
|
||||
You have created your first Kubernetes Job, and you can explore details about it:
|
||||
|
||||
|
||||
```
|
||||
`$ kubectl describe job job-test`
|
||||
```
|
||||
|
||||
Clean up the Jobs:
|
||||
|
||||
|
||||
```
|
||||
`$ kubectl delete jobs job-test`
|
||||
```
|
||||
|
||||
#### Kubernetes CronJobs
|
||||
|
||||
You can use CronJobs for cluster tasks that need to be executed on a predefined schedule. As the [documentation explains][8], they are useful for periodic and recurring tasks, like running backups, sending emails, or scheduling individual tasks for a specific time, such as when your cluster is likely to be idle.
|
||||
|
||||
As with Jobs, you can create CronJobs via a definition file. Following is a snippet of the CronJob file `cron-test.yaml`. Use this file to create an example CronJob:
|
||||
|
||||
|
||||
```
|
||||
apiVersion: batch/v1beta1 ## The version of the Kubernetes API
|
||||
kind: CronJob ## The type of object for Cron jobs
|
||||
metadata:
|
||||
name: cron-test
|
||||
spec:
|
||||
schedule: "*/1 * * * *" ## Defined schedule using the *nix style cron syntax
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: cron-test
|
||||
image: busybox ## Image used
|
||||
args:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- date; echo Hello this is Cron test
|
||||
restartPolicy: OnFailure ## Restart Policy in case container failed
|
||||
```
|
||||
|
||||
Apply the CronJob to your cluster:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl apply -f cron-test.yaml
|
||||
cronjob.batch/cron-test created
|
||||
```
|
||||
|
||||
Verify that the CronJob was created with the schedule in the definition file:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl get cronjob cron-test
|
||||
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
|
||||
cron-test */1 * * * * False 0 <none> 10s
|
||||
```
|
||||
|
||||
After a few seconds, you can find the pods that the last scheduled job created and view the standard output of one of the pods:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl logs cron-test-1604870760
|
||||
Sun Nov 8 21:26:09 UTC 2020
|
||||
Hello from the Kubernetes cluster
|
||||
```
|
||||
|
||||
You have created a Kubernetes CronJob that creates an object once per execution based on the schedule `schedule: "*/1 * * * *"`. Sometimes the creation can be missed because of environmental issues in the cluster. Therefore, they need to be [idempotent][9].
|
||||
|
||||
### Other things to know
|
||||
|
||||
Unlike deployments and services in Kubernetes, you can't change the same Job configuration file and reapply it at once. When you make changes in the Job configuration file, you must delete the previous Job from the cluster before you apply it.
|
||||
|
||||
Generally, creating a Job creates a single pod and performs the given task, as in the example above. But by using completions and [parallelism][10], you can initiate several pods, one after the other.
|
||||
|
||||
### Use your Jobs
|
||||
|
||||
You can use Kubernetes Jobs and CronJobs to manage your containerized applications. Jobs are important in Kubernetes application deployment patterns where you need a communication mechanism along with interactions between pods and the platforms. This may include cases where an application needs a "controller" or a "watcher" to complete tasks or needs to be scheduled to run periodically.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/kubernetes-jobs-cronjobs
|
||||
|
||||
作者:[Mike Calizo][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/mcalizo
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/kubernetes_containers_ship_lead.png?itok=9EUnSwci (Ships at sea on the web)
|
||||
[2]: https://kubernetes.io/
|
||||
[3]: https://kubernetes.io/docs/concepts/workloads/controllers/job/
|
||||
[4]: https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/
|
||||
[5]: https://phoenixnap.com/kb/how-to-install-kubernetes-on-centos
|
||||
[6]: https://minikube.sigs.k8s.io/docs/start/
|
||||
[7]: https://kubernetes.io/docs/reference/kubectl/kubectl/
|
||||
[8]: https://v1-18.docs.kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/
|
||||
[9]: https://en.wikipedia.org/wiki/Idempotence
|
||||
[10]: https://kubernetes.io/docs/concepts/workloads/controllers/job/#parallel-jobs
|
||||
105
sources/tech/20201123 Day 11- learning about learning rates.md
Normal file
105
sources/tech/20201123 Day 11- learning about learning rates.md
Normal file
@@ -0,0 +1,105 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Day 11: learning about learning rates)
|
||||
[#]: via: (https://jvns.ca/blog/2020/11/23/day-11--learning-about-learning-rates/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
Day 11: learning about learning rates
|
||||
======
|
||||
|
||||
Hello!
|
||||
|
||||
On Friday I trained an RNN to count to 3 (1 2 3 1 2 3 1 2 3), thanks to some great advice from another Recurser. I figured that once I got that working, I could then extend that and train the same RNN on a bunch of Shakespearean text to get it to generate vaguely Shakespeare-y text.
|
||||
|
||||
But on Friday I couldn’t get that to work! I was puzzled by this, but today I figured out what was happening.
|
||||
|
||||
### what’s a learning rate?
|
||||
|
||||
First, here’s a very short “deep learning for math majors” explanation of how training for a deep learning model works in general. I wrote this to help consolidate my own understanding on Friday.
|
||||
|
||||
* The model takes the training data and weights and outputs a single number, the output of the loss function
|
||||
* The model’s “weights” are the parameters of all the matrices in the model, like if there’s a 64 x 64 matrix then there are 4096 weights
|
||||
* For optimization purposes, this function should be thought of as a function of the weights (not the training data), since the weights are going to change and the function isn’t
|
||||
* Training is basically gradient descent. You take the derivative of the function (aka gradient), with respect to the weights of all the matrices/various functions in the model
|
||||
* The way you take this derivative is using the chain rule, the algorithm for applying the chain rule to a neural network is called “backpropagation”
|
||||
* Then you adjust the parameters by a multiple of the gradient (since this is gradient descent). The multiple of the gradient that you use is called the **learning rate** – it’s basically `parameters -= learning_rate * gradient`
|
||||
* machine learning model training is a lot like general continuous function optimization in that finding the “right” step size to do gradient descent is basically impossible so there are a lot of heuristics for picking step learning rates that will work. One of these heuristics is called [Adam][1]
|
||||
|
||||
|
||||
|
||||
### if you set your learning rate too high, the model won’t learn anything
|
||||
|
||||
So back to our original problem: when I was training my model to generate Shakespeare, I noticed that my model wasn’t learning anything! By “not learning anything”, I mean that the value of the loss function was not going down over time.
|
||||
|
||||
I eventually figured out that this was because my learning rate was too high! It was 0.01 or something, and changing it to more like 0.002 resulted in more learning progress. Hooray!
|
||||
|
||||
I started to generate text like this:
|
||||
|
||||
```
|
||||
erlon, w oller. is. d y ivell iver ave esiheres tligh? e ispeafeink
|
||||
teldenauke'envexes. h exinkes ror h. ser. sat ly. spon, exang oighis yn, y
|
||||
hire aning is's es itrt. for ineull ul'cl r er. s unt. y ch er e s out twiof
|
||||
uranter h measaker h exaw; speclare y towessithisil's aches? s es, tith s aat
|
||||
```
|
||||
|
||||
which is a big improvement over what I had previously, which was:
|
||||
|
||||
```
|
||||
kf ;o 'gen '9k ',nrhna 'v ;3; ;'rph 'g ;o kpr ;3;tavrnad 'ps ;]; ;];oraropr
|
||||
;9vnotararaelpot ;9vr ;9
|
||||
```
|
||||
|
||||
But then training stalled again, and I felt like I could still do better.
|
||||
|
||||
### resetting the state of the optimizer is VERY BAD
|
||||
|
||||
It turned out that the reason training had stalled the second time was that my code looked like this:
|
||||
|
||||
```
|
||||
for i in range(something):
|
||||
optimizer = torch.optim.Adam(rnn.parameters())
|
||||
... do training things
|
||||
```
|
||||
|
||||
I’d written the code this way because I didn’t realize that the state of the optimizer (“Adam”) was important, so I just reset it sometimes because it seemed convenient at the time.
|
||||
|
||||
It turns out that the optimizer’s state is very important, I think because it slowly reduces the training rate as training progresses. So I reorganized my code so that I only initialized the optimizer once at the beginning of training.
|
||||
|
||||
I also made sure that when I saved my model, I also saved the optimizer’s state:
|
||||
|
||||
```
|
||||
torch.save({'model_state_dict': rnn.state_dict(), 'optimizer_dict': optimizer.state_dict()}, MODEL_PATH)
|
||||
```
|
||||
|
||||
Here’s the “Shakespeare” the model was generating after I stopped resetting the optimizer all the time:
|
||||
|
||||
```
|
||||
at soerin, I kanth as jow gill fimes, To metes think our wink we in fatching
|
||||
and, Drose, How the wit? our arpear War, our in wioken alous, To thigh dies wit
|
||||
stain! navinge a sput pie, thick done a my wiscian. Hark's king, and Evit night
|
||||
and find. Woman steed and oppet, I diplifire, and evole witk ud
|
||||
```
|
||||
|
||||
It’s a big improvement! There are some actual English words in there! “Woman steed and oppet!”
|
||||
|
||||
### that’s it for today!
|
||||
|
||||
Tomorrow my goal is to learn what “BPTT” means and see if I can use it to train this model more quickly and maybe give it a bigger hidden state than 87 parameters. And once I’ve done that, maybe I can start to train more interesting models!!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2020/11/23/day-11--learning-about-learning-rates/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.tensorflow.org/api_docs/python/tf/keras/optimizers/Adam
|
||||
@@ -0,0 +1,284 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (A beginner's guide to developing with React)
|
||||
[#]: via: (https://opensource.com/article/20/11/reactjs-tutorial)
|
||||
[#]: author: (Shedrack Akintayo https://opensource.com/users/shedrack-akintayo)
|
||||
|
||||
A beginner's guide to developing with React
|
||||
======
|
||||
A step-by-step guide to using React in your web and mobile user
|
||||
interfaces.
|
||||
![Gears connecting][1]
|
||||
|
||||
[React][2] is a JavaScript user interface (UI) library that was built and is maintained by Facebook. React helps JavaScript developers think logically and functionally about how they want to build a UI.
|
||||
|
||||
With React, you can build:
|
||||
|
||||
1. Single-page applications
|
||||
2. Applications that are easy to understand
|
||||
3. Scalable applications
|
||||
4. Cross-platform applications
|
||||
|
||||
|
||||
|
||||
React allows developers to build applications declaratively and offers a unidirectional flow of data.
|
||||
|
||||
### React's advantages
|
||||
|
||||
The following features explain why React is one of the [most popular][3] web frameworks.
|
||||
|
||||
* **It is declarative:** React makes it extremely painless to build interactive user interfaces, design basic views for your application based on various states, and update and render new views when the data in your application changes.
|
||||
* **It is component-based:** React gives you the ability to build encapsulated components that can manage their own state, then puts them together to build complex UIs. The logic of these components is written in JavaScript instead of templates, so you easily pass actual data and keep state out of the [document object model][4] (DOM).
|
||||
* **You can learn once, write anywhere:** React gives you the ability to build for both mobile (React Native) and the web. There's no need to rewrite your existing codebase; you can just integrate React with your existing code.
|
||||
* **The virtual DOM:** React introduced a wrapper around the regular DOM called the virtual DOM (VDOM). This allows React to render elements and update its state faster than the regular DOM.
|
||||
* **Performance:** React has great performance benefits due to the VDOM and one-way flow of data.
|
||||
|
||||
|
||||
|
||||
### The virtual DOM
|
||||
|
||||
React's VDOM is like a virtual copy of the original DOM. It offers one-way data binding, which makes manipulating and updating the VDOM quicker than updating the original DOM. The VDOM can handle multiple operations in milliseconds without affecting the general page performance.
|
||||
|
||||
This VDOM supports React's declarative API: You basically tell React what state you want the UI to be in, and it ensures that the DOM matches that state.
|
||||
|
||||
### Prerequisites for learning React
|
||||
|
||||
Learning React requires basic knowledge of JavaScript, HTML, and CSS. To use React's power effectively, it helps to be familiar with [ECMAScript 6][5] (ES6) and functional and object-oriented programming.
|
||||
|
||||
You also need the following things installed on your computer:
|
||||
|
||||
* [NodeJS][6]
|
||||
* [npm][7] (comes bundled with NodeJS)
|
||||
* [Yarn][8] (an alternative to NPM)
|
||||
|
||||
|
||||
|
||||
### Basic React concepts
|
||||
|
||||
It also helps to have an understanding of React's concepts.
|
||||
|
||||
#### Components
|
||||
|
||||
Components are standalone, reusable pieces of code. They have the same purpose as JavaScript functions but work alone and return HTML via a built-in render function. They are two main types of components:
|
||||
|
||||
* **Class components** offer more control in the form of lifecycle hooks, managing and handling state, and API calls. For example: [code] class MyComponent extends React.Component {
|
||||
render() {
|
||||
return <div>This is a class component</div>;
|
||||
}
|
||||
}
|
||||
```
|
||||
* **Functional components** were used for rendering just views without any form of state management or data request until [React Hooks][9] was introduced. For example: [code] Function myComponent() {
|
||||
return (
|
||||
<div>A functional Component</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### Props
|
||||
|
||||
React props are like function arguments in JavaScript and attributes in HTML. They are read-only. For example:
|
||||
|
||||
|
||||
```
|
||||
function Welcome(props) {
|
||||
return <h1>Hello, {props.name}</h1>;
|
||||
}
|
||||
```
|
||||
|
||||
#### State
|
||||
|
||||
React components have a built-in object called _state_, which is where you store property values that belong to a particular component. If a component's state changes at any point in time, the component re-renders. For example:
|
||||
|
||||
|
||||
```
|
||||
class Car extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { brand: 'Ford' };
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<h1>My Car</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### JSX
|
||||
|
||||
JSX is a syntax extension to JavaScript. It is similar to a template language but has the full power of JavaScript. JSX is compiled to `React.createElement()` calls, which return plain JavaScript objects called _React elements_. For example:
|
||||
|
||||
|
||||
```
|
||||
return (
|
||||
<div>
|
||||
<h1>My Car</h1>
|
||||
</div>
|
||||
);
|
||||
```
|
||||
|
||||
The code between the return method that looks like HTML is JSX.
|
||||
|
||||
### How to use React
|
||||
|
||||
Ready to get started? I'll go step-by-step through two options for using React in your app:
|
||||
|
||||
* Adding its content delivery network (CDN) to your HTML file
|
||||
* Starting a blank React app with Create React App
|
||||
|
||||
|
||||
|
||||
#### Add its CDN to your HTML file
|
||||
|
||||
You can quickly use React in your HTML page by adding its CDN directly to your HTML file using the following steps:
|
||||
|
||||
**Step 1:** In the HTML page you want to add React to, add an empty `<div>` tag to create a container where you want to render something with React. For example:
|
||||
|
||||
|
||||
```
|
||||
<!-- ... old HTML ... -->
|
||||
|
||||
<[div][10] id="button_container"></[div][10]>
|
||||
|
||||
<!-- ... old HTML ... -->
|
||||
```
|
||||
|
||||
**Step 2:** Add three `<script>` tags to the HTML page just before the closing `</body>` tag. For example:
|
||||
|
||||
|
||||
```
|
||||
<!-- ... Some other HTML ... -->
|
||||
<!-- Initiate React. -->
|
||||
<!-- Note: when deploying, replace "development.js" with "production.min.js". -->
|
||||
|
||||
<[script][11] src="<https://unpkg.com/react@16/umd/react.development.js>" crossorigin></[script][11]>
|
||||
<[script][11] src="<https://unpkg.com/react-dom@16/umd/react-dom.development.js>" crossorigin></[script][11]>
|
||||
|
||||
<!-- Load our React component. -->
|
||||
|
||||
<[script][11] src="button.js"></[script][11]>
|
||||
|
||||
</[body][12]>
|
||||
```
|
||||
|
||||
The first two script tags load React, and the last one loads your React component code.
|
||||
|
||||
**Step 3:** Create a file called `button.js` in the same folder as your HTML page to hold the code for your React component. Paste the following code inside your `button.js` file:
|
||||
|
||||
|
||||
```
|
||||
'use strict';
|
||||
const e = React.createElement;
|
||||
class Button extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { clicked: false };
|
||||
}
|
||||
render() {
|
||||
if (this.state.clicked) {
|
||||
return 'You clicked this button.';
|
||||
}
|
||||
return e(
|
||||
'button',
|
||||
{ onClick: () => this.setState({ clicked: true }) },
|
||||
'Click Me'
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This code creates a button component that returns a message when the button is clicked.
|
||||
|
||||
**Step 4:** To use this component in your HTML page, add the code snippet below at the end of your `button.js` file:
|
||||
|
||||
|
||||
```
|
||||
const domContainer = document.querySelector('#button_container');
|
||||
ReactDOM.render(e(Button), domContainer);
|
||||
```
|
||||
|
||||
The code snippet above targets the `<div>` you added to your HTML in the first step and render your React button component inside it.
|
||||
|
||||
#### Start a blank React app with Create React App
|
||||
|
||||
If you want to start with a blank React app, use [Create React App][13]. This is the recommended way to quickly create single-page React applications, as it provides a modern build setup without any configuration.
|
||||
|
||||
To generate a new React app using Create React App, enter one of the following commands in your terminal. This will create a new React app called `my-app:`
|
||||
|
||||
* [npx][14] (this is the recommended way to use create-react-app): [code]`npx create-react-app my-app`
|
||||
```
|
||||
* npm: [code]`npm i -g create-react-app && npm create-react-app my-app`
|
||||
```
|
||||
* Yarn: [code]`yarn add create-react-app && yarn create-react-app my-app`[/code] ` `
|
||||
|
||||
|
||||
|
||||
To run your newly created app, navigate into the app folder (by typing `cd my-app` into your terminal) and enter one of the following commands:
|
||||
|
||||
* npm:
|
||||
|
||||
```
|
||||
npm start
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
* Yarn:
|
||||
```
|
||||
yarn start
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
These will run the app you just created in development mode. You can open `http://localhost:3000` to view it in the browser.
|
||||
|
||||
When you navigate to `http://localhost:3000`, you should see a page like the one below. Any change you make in the React code will automatically render here.
|
||||
|
||||
![React gif][15]
|
||||
|
||||
I hope this guide to getting started with React has been helpful. There are many more things to discover in the world of JavaScript, so please explore on your own and share what you learn.
|
||||
|
||||
* * *
|
||||
|
||||
_This article originally appeared on [Shedrack Akintayo's blog][16] and is republished with his permission._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/reactjs-tutorial
|
||||
|
||||
作者:[Shedrack Akintayo][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/shedrack-akintayo
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/gears_wheels.png?itok=KRvpBttl (Gears connecting)
|
||||
[2]: https://reactjs.org/
|
||||
[3]: https://insights.stackoverflow.com/survey/2020#technology-web-frameworks
|
||||
[4]: https://en.wikipedia.org/wiki/Document_Object_Model
|
||||
[5]: https://en.wikipedia.org/wiki/ECMAScript
|
||||
[6]: https://nodejs.org/
|
||||
[7]: https://www.npmjs.com/
|
||||
[8]: https://yarnpkg.com/
|
||||
[9]: https://reactjs.org/docs/hooks-intro.html
|
||||
[10]: http://december.com/html/4/element/div.html
|
||||
[11]: http://december.com/html/4/element/script.html
|
||||
[12]: http://december.com/html/4/element/body.html
|
||||
[13]: https://create-react-app.dev/docs/getting-started/
|
||||
[14]: https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b
|
||||
[15]: https://opensource.com/sites/default/files/uploads/react.gif (React gif)
|
||||
[16]: https://www.sheddy.xyz/posts/react-js-the-first-time
|
||||
@@ -0,0 +1,295 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Build a motion detection system with a Raspberry Pi)
|
||||
[#]: via: (https://opensource.com/article/20/11/motion-detection-raspberry-pi)
|
||||
[#]: author: (Lukas Janėnas https://opensource.com/users/lukasjan)
|
||||
|
||||
Build a motion detection system with a Raspberry Pi
|
||||
======
|
||||
Set up an inexpensive home security system to alert you when someone is
|
||||
lurking around your house.
|
||||
![Houses in a row][1]
|
||||
|
||||
If you want a home security system to tell you if someone is lurking around your property, you don't need an expensive, proprietary solution from a third-party vendor. You can set up your own system using a Raspberry Pi, a passive infrared (PIR) motion sensor, and an LTE modem that will send SMS messages whenever it detects movement.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
You will need:
|
||||
|
||||
* A Raspberry Pi with Ethernet connection and Raspberry Pi OS
|
||||
* An HC-SR501 PIR motion sensor
|
||||
* 1 red LED
|
||||
* 1 green LED
|
||||
* An LTE modem (I used the Teltonika [TRM240][2])
|
||||
* A SIM card
|
||||
|
||||
|
||||
|
||||
#### The PIR motion sensor
|
||||
|
||||
The PIR motion sensor will sense motion when something that emits infrared rays (e.g., a human, animal, or anything that emits heat) moves in the range of the sensor's field or reach. PIR motion sensors are low power and inexpensive, so they're used in many products that detect motion. They can't say how many people are in the area and how close they are to the sensor; they just detect motion.
|
||||
|
||||
![PIR sensor][3]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][4])
|
||||
|
||||
A PIR sensor has two potentiometers, one for setting the delay time and another for sensitivity. The delay time adjustment sets how long the output should remain high after detecting motion; it can be anywhere from five seconds to five minutes. The sensitivity adjustment sets the detection range, which can be anywhere from three to seven meters.
|
||||
|
||||
#### The LTE modem
|
||||
|
||||
Long-term evolution (LTE) is a standard for wireless broadband communication based on the GSM/EDGE and UMTS/HSPA technologies. The LTE modem I'm using is a USB device that can add 3G or 4G (LTE) cellular connectivity to a Raspberry PI computer. In this project, I'm not using the modem for cellular connectivity, but to send messages to my phone when motion is detected. I can control the modem with serial communication and AT commands; the latter send messages from the modem to my phone number.
|
||||
|
||||
![LTE modem][5]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][4])
|
||||
|
||||
### How to set up your home security system
|
||||
|
||||
#### Step 1: Install the software
|
||||
|
||||
First, install the necessary software on your Raspberry Pi. In the Raspberry Pi's terminal, enter:
|
||||
|
||||
|
||||
```
|
||||
`sudo apt install python3 python3-gpiozero python-serial -y`
|
||||
```
|
||||
|
||||
#### Step 2: Set up the modem
|
||||
|
||||
Insert your SIM card into your LTE modem by following these [instructions][6] for the TRM240. Make sure to mount the antenna on the modem for a better signal.
|
||||
|
||||
#### Step 3: Connect the modem to the Raspberry Pi
|
||||
|
||||
Connect the LTE modem to one of the Raspberry Pi's USB ports, then wait for the device to boot up. You should see four new USB ports in the `/dev` directory. You can check them by executing this command in the terminal:
|
||||
|
||||
|
||||
```
|
||||
`ls /dev/ttyUSB*`
|
||||
```
|
||||
|
||||
You should now see these devices:
|
||||
|
||||
![USB ports output][7]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][4])
|
||||
|
||||
You will use the **ttyUSB2** port to communicate with the device by sending AT commands.
|
||||
|
||||
#### Step 4: Connect the sensors to the Raspberry Pi
|
||||
|
||||
1. **Connect the PIR sensor:**
|
||||
Connect the **VCC** and **GND** pins to the respective pins on the Raspberry Pi, and connect the motion sensor's output pin to the **8 pin** on the Raspberry Pi. See below for a schematic on these connections, and you can learn more about [Raspberry Pi pin numbering][8] in the GPIO Zero docs.
|
||||
|
||||
2. **Connect the LED lights:**
|
||||
If you want indicator LEDs to light up when motion is detected, connect the cathode (short leg, flat side) of the LED to a ground pin; connect the anode (longer leg) to a current-limiting resistor; and connect the other side of the resistor to a GPIO pin (the limiting resistor can be placed either side of the LED). Connect the red LED to the **38 pin** on the board and the green LED to the **40 pin**.
|
||||
|
||||
|
||||
|
||||
|
||||
Note that this step is optional. If you don't want indicator LEDs when motion is detected, delete the LED sections from the example code below.
|
||||
|
||||
![Raspberry Pi wiring diagram][9]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][4])
|
||||
|
||||
#### Step 5: Launch the program
|
||||
|
||||
Using the terminal (or any text editor), create a file named `motion_sensor.py`, and paste in the [example code][10] below.
|
||||
|
||||
Find and change these fields:
|
||||
|
||||
* `phone_number`
|
||||
* `message`
|
||||
|
||||
|
||||
|
||||
If you used different pins to connect the sensors, make sure to change the code accordingly.
|
||||
|
||||
When everything is set and ready to go, start the program from the terminal by entering:
|
||||
|
||||
|
||||
```
|
||||
`python3 motion_sensor.py`
|
||||
```
|
||||
|
||||
If you don't have the required privileges to start the program, try this command:
|
||||
|
||||
|
||||
```
|
||||
`sudo python3 motion_sensor.py`
|
||||
```
|
||||
|
||||
![Motion sensor hardware][11]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][4])
|
||||
|
||||
### Example code
|
||||
|
||||
|
||||
```
|
||||
from gpiozero import MotionSensor, LED
|
||||
from time import sleep, time
|
||||
from sys import exit
|
||||
import serial
|
||||
import threading
|
||||
|
||||
# Raspberry Pi GPIO pin config
|
||||
sensor = MotionSensor(14)
|
||||
green = LED(21)
|
||||
red = LED(20)
|
||||
|
||||
# Modem configuration
|
||||
device = '/dev/ttyUSB2'
|
||||
message = '<message>'
|
||||
phone_number = '<phone_number>'
|
||||
sms_timeout = 120 # min seconds between SMS messages
|
||||
|
||||
def setup():
|
||||
port.close()
|
||||
|
||||
try:
|
||||
port.open()
|
||||
except serial.SerialException as e:
|
||||
print('Error opening device: ' + str(e))
|
||||
return False
|
||||
|
||||
# Turn off echo mode
|
||||
port.write(b'ATE0 \r')
|
||||
if not check_response('OK', 10):
|
||||
print('Failed on ATE0')
|
||||
return False
|
||||
|
||||
# Enter SMS text mode
|
||||
port.write(b'AT+CMGF=1 \r')
|
||||
if not check_response('OK', 6):
|
||||
print('Failed on CMGF')
|
||||
return False
|
||||
|
||||
# Switch character set to 'international reference alphabet'
|
||||
# Note: this still doesn't support all characters
|
||||
port.write(b'AT+CSCS="IRA" \r')
|
||||
if not check_response('OK', 6):
|
||||
print('Failed on CSCS')
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def check_response(string, amount):
|
||||
result = ''
|
||||
|
||||
try:
|
||||
result = port.read(amount).decode()
|
||||
except:
|
||||
return False
|
||||
|
||||
if not string in result:
|
||||
try:
|
||||
# Write 'ESC' to exit SMS input mode, just in case
|
||||
port.write(b'\x1B \r')
|
||||
except:
|
||||
return False
|
||||
|
||||
return string in result
|
||||
|
||||
def send_sms():
|
||||
global currently_sending, last_msg_time
|
||||
currently_sending = True
|
||||
|
||||
try:
|
||||
port.write('AT+CMGS="{}" \r'.format(phone_number).encode())
|
||||
if not check_response('>', 6):
|
||||
print('Failed on CMGS')
|
||||
currently_sending = False
|
||||
return
|
||||
|
||||
# Write the message terminated by 'Ctrl+Z' or '1A' in ASCII
|
||||
port.write('{}\x1A \r'.format(message).encode())
|
||||
|
||||
while True:
|
||||
result = port.readline().decode()
|
||||
|
||||
if 'OK' in result:
|
||||
print('> SMS sent successfully')
|
||||
last_msg_time = time()
|
||||
currently_sending = False
|
||||
return
|
||||
|
||||
if 'ERROR' in result:
|
||||
print('> Failed to send SMS [{}]'.format(result.rstrip()))
|
||||
currently_sending = False
|
||||
return
|
||||
except:
|
||||
# Initiate setup if the got while the program was running
|
||||
setup()
|
||||
currently_sending = False
|
||||
|
||||
def on_motion():
|
||||
print('Motion detected!')
|
||||
green.off()
|
||||
red.on()
|
||||
|
||||
if time() - last_msg_time > sms_timeout and not currently_sending:
|
||||
print('> Sending SMS...')
|
||||
threading.Thread(target=send_sms).start()
|
||||
|
||||
def no_motion():
|
||||
green.on()
|
||||
red.off()
|
||||
|
||||
print('* Setting up...')
|
||||
green.on()
|
||||
red.on()
|
||||
|
||||
port = serial.Serial()
|
||||
port.port = device
|
||||
port.baudrate = 115200
|
||||
port.timeout = 2
|
||||
|
||||
last_msg_time = 0
|
||||
currently_sending = False
|
||||
|
||||
if not setup():
|
||||
print('* Retrying...')
|
||||
if not setup():
|
||||
print('* Try restarting the modem')
|
||||
exit(1)
|
||||
|
||||
print('* Do not move, setting up the PIR sensor...')
|
||||
sensor.wait_for_no_motion()
|
||||
|
||||
print('* Device ready! ', end='', flush=True)
|
||||
green.on()
|
||||
red.off()
|
||||
|
||||
sensor.when_motion = on_motion
|
||||
sensor.when_no_motion = no_motion
|
||||
input('Press Enter or Ctrl+C to exit\n\n')
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/motion-detection-raspberry-pi
|
||||
|
||||
作者:[Lukas Janėnas][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/lukasjan
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/house_home_colors_live_building.jpg?itok=HLpsIfIL (Houses in a row)
|
||||
[2]: https://teltonika-networks.com/product/trm240/
|
||||
[3]: https://opensource.com/sites/default/files/uploads/pir-sensor.jpg (PIR sensor)
|
||||
[4]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[5]: https://opensource.com/sites/default/files/uploads/modem.jpg (LTE modem)
|
||||
[6]: https://wiki.teltonika-networks.com/view/TRM240_SIM_Card
|
||||
[7]: https://opensource.com/sites/default/files/uploads/deviceoutput.png (USB ports output)
|
||||
[8]: https://gpiozero.readthedocs.io/en/stable/recipes.html#pin-numbering
|
||||
[9]: https://opensource.com/sites/default/files/uploads/wiring.png (Raspberry Pi wiring diagram)
|
||||
[10]: tmp.4ePb9Wjuou#code
|
||||
[11]: https://opensource.com/sites/default/files/uploads/motionssensorsetup.jpg (Motion sensor hardware)
|
||||
@@ -0,0 +1,181 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Communication by example: Which methods do high-performing open source communities use?)
|
||||
[#]: via: (https://www.linux.com/news/communication-by-example-which-methods-do-high-performing-open-source-communities-use/)
|
||||
[#]: author: (Linux.com Editorial Staff https://www.linux.com/author/linuxdotcom/)
|
||||
|
||||
Communication by example: Which methods do high-performing open source communities use?
|
||||
======
|
||||
|
||||
#### ![][1]
|
||||
|
||||
#### _“Good words are worth much, and cost little.”_ _George Herbert_
|
||||
|
||||
Although effective communication is an essential life skill, it is the most critical element in any business [2]. Lack of accurate communication is the common cause of any organization’s issues, causing conflicts, reducing client relationships, team effectiveness, and profitability [2]. According to the Project Management Institute (PMI), ineffective communication is the main contributor to project failure one-third of the time. It has a negative impact on project success more than half of the time [1].
|
||||
|
||||
In open source projects where there is a diverse and world spread community, effective communication is the key to projects’ success. Using the right technology is crucial for that. So, which tools do open source communities use for communication?
|
||||
|
||||
### Open Source community communication by example
|
||||
|
||||
#### Ubuntu
|
||||
|
||||
The Ubuntu community uses [**mailing lists**][2] for _development_ and _team coordination._ The mailing lists are split into announcements and news, support, development, testing and quality assurance, and general (such as translation, marketing, and documentation) [3]. Despite the mailing lists, [**IRC (Internet Relay Chat) channels**][3] are used for informal daily chats and short-term coordination tasks [3]. If someone wants to know what is going on on Ubuntu, but doesn’t want to subscribe to the high traffic mailing list, the [**web forum**][4] can be used to get support and discuss the future of Ubuntu. Finally, [Ask Ubuntu][5] can be used to ask technical questions.
|
||||
|
||||
#### Linux Kernel
|
||||
|
||||
**Mailing lists** are the main communication channels in the Linux Kernel. For newcomers that would like to learn more about the Linux kernel development, there is the [**kernelnewbies**][6] resource and #kernelnewbies IRC channel on OFTC. This online resource provides information on basic kernel development questions. Additionally, the **kernelnewbies ** **IRC channel** is a vehicle for contributors to ask questions in real-time and get help from experts in the kernel community. The [Linux Kernel Mailing List (LKML)][7] is where most development discussions and announcements are made. Kernel developers send patches to the mailing lists as outlined in the [Submitting patches: the essential guide to getting your code into the kernel][8]. The archives from each mailing list can be found at <https://lore.kernel.org/lists.html>.
|
||||
|
||||
Shuah Khan, a Linux Fellow, mentioned in an interview [4] that before contributing to the Linux Kernel, it’s important to subscribe to the kernel-related mailing lists _“to understand the dynamics.”_ Khan said, _“The process works like this: you walk into a room. People are gathering in small groups and are talking to each other. You have to break into one of these conversations. That is the process of watching the mailing lists, watching the interaction, and learning from that before you start sending out a patch.”_
|
||||
|
||||
#### OpenStack
|
||||
|
||||
OpenStack has many communication channels such as [IRC channels][9] for both public meetings and projects as well as [mailing lists][10]. The mailing lists are used to asynchronously communicate and share information, team communication, and cross-project communication. Additionally, mailing lists in OpenStack are used to communicate with non-developer community members of OpenStack [5].
|
||||
|
||||
#### GNOME
|
||||
|
||||
[IRC channels][11] are one of the most important communication methods in Gnome. They are a google place to know what the community is talking about and also ask for help. There are many channels on [Discourse][12], including discussions about Gnome’s sub-projects, community-related topics, internationalization, etc. Similar to other communities, [mailing lists][13] can be used for discussing specific topics. Finally, [PlanetGnome][14] and [GnomeNews][15] can be used to follow the latest news of the project.
|
||||
|
||||
So, where does communication occur in open source projects?
|
||||
|
||||
As observed in our previous discussion, _mailing lists_ seem to be the _most_ used communication method. Previous work has also found that _“mailing lists are the bread and butter of project communications”_ [11] and that _“the developer mailing list is the primary communication channel for an OSS project”_ [12]_._ However, as we have previously mentioned, mailing lists are not the _only_ communication channel used in OSS. Other channels (such as IRC channels and forums) also play an important role.
|
||||
|
||||
Guzzy et. al [10] mention that when more than one communication repository exists, the policy of most OSS is to transfer all official decisions and useful discussions to the mailing lists, so that they can later be _retrieved._ Thus, traceability and transparency of information is an important matter here.
|
||||
|
||||
The benefit of using mailing lists is that it is an asynchronous form of communication, and it is an easy resource to share information with the entire community. Additionally, mailing lists allow people that are in different timezones to engage, as well as people that have different levels of English proficiency, may better manage it in text messages [5].
|
||||
|
||||
However, mailing lists might also have their disadvantages. Previous work [10] found that developers have problems maintaining awareness of each other’s work when discussing on the mailing lists. Additionally, recovering traceability links among different communication repositories might help researchers and community members to have a more complete picture of the development process.
|
||||
|
||||
#### What are the common DOs and DON’Ts when using OSS mailing lists?
|
||||
|
||||
Given that mailing lists are one of the common ways to communicate in open source projects, it is worth knowing how to communicate in mailing lists. Although each project has its own set of rules, certain conventions should be followed.
|
||||
|
||||
##### **DOs**
|
||||
|
||||
**Subject**
|
||||
|
||||
* * * _**Prefix the subject**_ with topic tags in square brackets. This makes email threads easier for readers to categorize and decide what they should read quickly. For example, OpenStack has documentation [13] establishing how to prefix the subject, i.e., community members should use **[docs]** to address any kind of documentation discussions that are cross-projects and so on.
|
||||
|
||||
|
||||
* * * Sometimes it’s appropriate to _**change the subject**_ rather than start a new thread.
|
||||
* **Exceptions:** Linux Kernel mailing lists use “bottom post” protocol (writing the message below the original text) rather than “top post” (writing the message above the original text of an email, which is what most mail clients are set to do by default.)
|
||||
|
||||
|
||||
|
||||
**Formating**
|
||||
|
||||
* * * **Plain text:** Send your email as plain text only! Please, don’t send HTML emails.
|
||||
* **Line wrapping:** Lines should be wrapped at 72 characters or fewer.
|
||||
|
||||
|
||||
|
||||
**Replies**
|
||||
|
||||
* * * Always use [**inline replies**][16], i.e., break the original message by replying to each specific part of the message.
|
||||
* When replying to long discussions, [**trim**][17] your message and leave only the relevant parts to the reply.
|
||||
|
||||
|
||||
|
||||
##### **DON’Ts**
|
||||
|
||||
* * * _**Avoid cross-posting**_, i.e., posting the same message to many mailing lists at the same time.
|
||||
* **Exceptions:** The Linux Kernel maintains mailing lists for each subsystem, and patches are often sent to multiple mailing lists for review and discussion. However, avoid “top posting” on a Linux Kernel mailing list.
|
||||
|
||||
|
||||
* * * Avoid sending the _**wrong topic**_ to the _**wrong mailing list**_. Make sure that your topic is the topic of the mailing list.
|
||||
|
||||
|
||||
|
||||
#### Setting up your email client
|
||||
|
||||
The Linux Kernel has great [documentation][18] on setting different email clients according to the rules mentioned above.
|
||||
|
||||
#### How to minimize the harm caused by conflicts?
|
||||
|
||||
Even if the code of conduct is applied, conflicts might exist. Many actions can be taken in case of dispute, and here are some examples:
|
||||
|
||||
##### Gather information about the situation
|
||||
|
||||
If someone has violated the code of conduct, you should carefully analyze the situation according to the experience working with that person [6]. It is essential to read the past comments and interactions with that person to have an unbiased perspective about what happened. Stephanie Zvan [7] has mentioned that the best way to avoid a conflict is not to get pulled into an argument. It is important to focus on what you need to do instead of getting sidetracked into dealing with others’ behaviors.
|
||||
|
||||
##### Take appropriate actions
|
||||
|
||||
Two ways to respond to the code of conduct violation is that the moderator of the community (i) in a thoughtful way explain in public how the person’s behavior affected the community, or (ii) privately reach out to the person and explain how that behavior was negative [6].
|
||||
|
||||
#### _“A code of conduct that isn’t (or can’t be) enforced is worse than no code of conduct at all: it sends the message that the values in the code of conduct aren’t actually important or respected in your community.”_ [_Ada Initiative_][19]
|
||||
|
||||
#### General tips
|
||||
|
||||
* Open source projects are, in large part, successful due to the collaborative nature of projects. Thus, **start conversations that lead to collaboration.** That means, give feedback, support each other’s communication, and share your ideas.
|
||||
* There is no additional cost to being transparent and authentic with your community. In that way, it is easy to keep your team informed, empowered, and focused on one specific goal or task.
|
||||
|
||||
|
||||
|
||||
***About the author: ***
|
||||
|
||||
_Isabella Ferreira is an Advocate at TARS Foundation,_ a cloud-native open-source microservice foundation under the Linux Foundation*.*
|
||||
|
||||
**References:**
|
||||
|
||||
[1]<https://www.pmi.org/-/media/pmi/documents/public/pdf/learning/thought-leadership/pulse/the-essential-role-of-communications.pdf>
|
||||
|
||||
[2]<https://www.orangescrum.org/articles/communication-challenges-in-project-management-how-to-overcome.html>
|
||||
|
||||
[3] <https://wiki.ubuntu.com/ContributeToUbuntu#Community_Communication>
|
||||
|
||||
[4] <https://thenewstack.io/how-to-begin-your-journey-as-a-contributor-to-the-linux-kernel/>
|
||||
|
||||
[5] <https://docs.openstack.org/project-team-guide/open-community.html>
|
||||
|
||||
[6] <https://opensource.guide/code-of-conduct/#:~:text=A%20code%20of%20conduct%20is,just%20your%20participants%2C%20but%20yourself.>
|
||||
|
||||
[7]
|
||||
|
||||
<https://the-orbit.net/almostdiamonds/2014/04/10/so-youve-got-yourself-a-policy-now-what/>
|
||||
|
||||
[9] <https://www.forbes.com/sites/forbescommunicationscouncil/2019/11/22/open-source-software-a-model-for-transparent-organizational-communication/#1b834e0d32c4>
|
||||
|
||||
[10] Guzzi, Anja, et al. “Communication in open source software development mailing lists.” 2013 10th Working Conference on Mining Software Repositories (MSR). IEEE, 2013.
|
||||
|
||||
[11] Fogel, Karl. _Producing open source software: How to run a successful free software project_. ” O’Reilly Media, Inc.”, 2005.
|
||||
|
||||
[12] Gutwin, Carl, Reagan Penner, and Kevin Schneider. “Group awareness in distributed software development.” _Proceedings of the 2004 ACM conference on Computer supported cooperative work_. 2004.
|
||||
|
||||
[13] <https://docs.openstack.org/project-team-guide/open-community.html#mailing-lists>
|
||||
|
||||
_This Linux Foundation Platinum Sponsor content was contributed by Tencent._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/news/communication-by-example-which-methods-do-high-performing-open-source-communities-use/
|
||||
|
||||
作者:[Linux.com Editorial Staff][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.linux.com/author/linuxdotcom/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.linux.com/wp-content/uploads/2019/08/email2git-linux-kernel.jpg
|
||||
[2]: https://lists.ubuntu.com/
|
||||
[3]: https://help.ubuntu.com/community/InternetRelayChat
|
||||
[4]: https://ubuntuforums.org/index.php
|
||||
[5]: https://askubuntu.com/
|
||||
[6]: https://kernelnewbies.org
|
||||
[7]: https://lore.kernel.org/lkml/
|
||||
[8]: https://www.kernel.org/doc/html/latest/process/submitting-patches.html
|
||||
[9]: https://docs.openstack.org/project-team-guide/glossary.html#term-IRC
|
||||
[10]: http://lists.openstack.org/cgi-bin/mailman/listinfo
|
||||
[11]: https://wiki.gnome.org/Community/GettingInTouch/IRC
|
||||
[12]: https://discourse.gnome.org/
|
||||
[13]: https://mail.gnome.org/mailman/listinfo/
|
||||
[14]: https://planet.gnome.org/
|
||||
[15]: https://www.gnome.org/news/
|
||||
[16]: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
|
||||
[17]: https://en.wikipedia.org/wiki/Posting_style#Trimming_and_reformatting
|
||||
[18]: https://www.kernel.org/doc/html/v4.10/process/email-clients.html
|
||||
[19]: https://adainitiative.org/2014/02/18/howto-design-a-code-of-conduct-for-your-community/
|
||||
@@ -0,0 +1,638 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Create a machine learning model with Bash)
|
||||
[#]: via: (https://opensource.com/article/20/11/machine-learning-bash)
|
||||
[#]: author: (Girish Managoli https://opensource.com/users/gammay)
|
||||
|
||||
Create a machine learning model with Bash
|
||||
======
|
||||
Bash, Tcsh, or Zsh can help you get ready for machine learning.
|
||||
![bash logo on green background][1]
|
||||
|
||||
[Machine learning][2] is a powerful computing capability for predicting or forecasting things that conventional algorithms find challenging. The machine learning journey begins with collecting and preparing data—a _lot_ of it—then it builds mathematical models based on that data. While multiple tools can be used for these tasks, I like to use the [shell][3].
|
||||
|
||||
A shell is an interface for performing operations using a defined language. This language can be invoked interactively or scripted. The concept of the shell was introduced in [Unix][4] operating systems in the 1970s. Some of the most popular shells include [Bash][5], [tcsh][6], and [Zsh][7]. They are available for all operating systems, including Linux, macOS, and Windows, which gives them high portability. For this exercise, I'll use Bash.
|
||||
|
||||
This article is an introduction to using a shell for data collection and data preparation. Whether you are a data scientist looking for efficient tools or a shell expert looking at using your skills for machine learning, I hope you will find valuable information here.
|
||||
|
||||
The example problem in this article is creating a machine learning model to forecast temperatures for US states. It uses shell commands and scripts to do the following data collection and data preparation steps:
|
||||
|
||||
1. Download data
|
||||
2. Extract the necessary fields
|
||||
3. Aggregate data
|
||||
4. Make time series
|
||||
5. Create the train, test, and validate data sets
|
||||
|
||||
|
||||
|
||||
You may be asking why you should do this with shell, when you can do all of it in a machine learning programming language such as [Python][8]. This is a good question. If data processing is performed with an easy, friendly, rich technology like a shell, a data scientist focuses only on machine learning modeling and not the details of a language.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
First, you need to have a shell interpreter installed. If you use Linux or macOS, it will already be installed, and you may already be familiar with it. If you use Windows, try [MinGW][9] or [Cygwin][10].
|
||||
|
||||
For more information, see:
|
||||
|
||||
* [Bash tutorials][11] here on opensource.com
|
||||
* The official [shell scripting tutorial][12] by Steve Parker, the creator of Bourne shell
|
||||
* The [Bash Guide for Beginners][13] by the Linux Documentation Project
|
||||
* If you need help with a specific command, type `<commandname> --help` in the shell for help; for example: `ls --help`.
|
||||
|
||||
|
||||
|
||||
## Get started
|
||||
|
||||
Now that your shell is set up, you can start preparing data for the machine learning temperature-prediction problem.
|
||||
|
||||
### 1\. Download data
|
||||
|
||||
The data for this tutorial comes from the US National Oceanic and Atmospheric Administration (NOAA). You will train your model using the last 10 complete years of data. The data source is at <https://www1.ncdc.noaa.gov/pub/data/ghcn/daily/by_year/>, and the data is in .csv format and gzipped.
|
||||
|
||||
Download and unzip the data using a [shell script][14]. Use your favorite text editor to create a file named `download.sh` and paste in the code below. The comments in the code explain what the commands do:
|
||||
|
||||
|
||||
```
|
||||
#!/bin/sh
|
||||
# This is called hashbang. It identifies the executor used to run this file.
|
||||
# In this case, the script is executed by shell itself.
|
||||
# If not specified, a program to execute the script must be specified.
|
||||
# With hashbang: ./download.sh; Without hashbang: sh ./download.sh;
|
||||
|
||||
FROM_YEAR=2010
|
||||
TO_YEAR=2019
|
||||
|
||||
year=$FROM_YEAR
|
||||
# For all years one by one starting from FROM_YEAR=2010 upto TO_YEAR=2019
|
||||
while [ $year -le $TO_YEAR ]
|
||||
do
|
||||
# show the year being downloaded now
|
||||
echo $year
|
||||
# Download
|
||||
wget <https://www1.ncdc.noaa.gov/pub/data/ghcn/daily/by\_year/${year}.csv.gz>
|
||||
# Unzip
|
||||
gzip -d ${year}.csv.gz
|
||||
# Move to next year by incrementing
|
||||
year=$(($year+1))
|
||||
done
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
* If you are behind a proxy server, consult Mark Grennan's [how-to][15], and use: [code] export http_proxy=<http://username:password@proxyhost:port/>
|
||||
export https_proxy=<https://username:password@proxyhost:port/>
|
||||
```
|
||||
* Make sure all standard commands are already in your PATH (such as `/bin` or `/usr/bin`). If not, [set your PATH][16].
|
||||
* [Wget][17] is a utility for connecting to web servers from the command line. If Wget is not installed on your system, [download it][18].
|
||||
* Make sure you have [gzip][19], a utility used for compression and decompression.
|
||||
|
||||
|
||||
|
||||
Run this script to download, extract, and make 10 years' worth of data available as CSVs:
|
||||
```
|
||||
|
||||
|
||||
$ ./download.sh
|
||||
2010
|
||||
\--2020-10-30 19:10:47-- <https://www1.ncdc.noaa.gov/pub/data/ghcn/daily/by\_year/2010.csv.gz>
|
||||
Resolving www1.ncdc.noaa.gov (www1.ncdc.noaa.gov)... 205.167.25.171, 205.167.25.172, 205.167.25.178, ...
|
||||
Connecting to www1.ncdc.noaa.gov (www1.ncdc.noaa.gov)|205.167.25.171|:443... connected.
|
||||
HTTP request sent, awaiting response... 200 OK
|
||||
Length: 170466817 (163M) [application/gzip]
|
||||
Saving to: '2010.csv.gz'
|
||||
|
||||
0K .......... .......... .......... .......... .......... 0% 69.4K 39m57s
|
||||
50K .......... .......... .......... .......... .......... 0% 202K 26m49s
|
||||
100K .......... .......... .......... .......... .......... 0% 1.08M 18m42s
|
||||
|
||||
...
|
||||
|
||||
```
|
||||
The [ls][20] command lists the contents of a folder. Use `ls 20*.csv` to list all your files with names beginning with 20 and ending with .csv.
|
||||
```
|
||||
|
||||
|
||||
$ ls 20*.csv
|
||||
2010.csv 2011.csv 2012.csv 2013.csv 2014.csv 2015.csv 2016.csv 2017.csv 2018.csv 2019.csv
|
||||
|
||||
```
|
||||
### 2\. Extract average temperatures
|
||||
|
||||
Extract the TAVG (average temperature) data from the CSVs for US regions:
|
||||
|
||||
**extract_tavg_us.sh**
|
||||
```
|
||||
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
# For each file with name that starts with "20" and ens with ".csv"
|
||||
for csv_file in `ls 20*.csv`
|
||||
do
|
||||
# Message that says file name $csv_file is extracted to file TAVG_US_$csv_file
|
||||
# Example: 2010.csv extracted to TAVG_US_2010.csv
|
||||
echo "$csv_file -> TAVG_US_$csv_file"
|
||||
# grep "TAVG" $csv_file: Extract lines in file with text "TAVG"
|
||||
# |: pipe
|
||||
# grep "^US": From those extract lines that begin with text "US"
|
||||
# > TAVG_US_$csv_file: Save xtracted lines to file TAVG_US_$csv_file
|
||||
grep "TAVG" $csv_file | grep "^US" > TAVG_US_$csv_file
|
||||
done
|
||||
|
||||
```
|
||||
This script:
|
||||
```
|
||||
|
||||
|
||||
$ ./extract_tavg_us.sh
|
||||
2010.csv -> TAVG_US_2010.csv
|
||||
...
|
||||
2019.csv -> TAVG_US_2019.csv
|
||||
|
||||
```
|
||||
creates these files:
|
||||
```
|
||||
|
||||
|
||||
$ ls TAVG_US*.csv
|
||||
TAVG_US_2010.csv TAVG_US_2011.csv TAVG_US_2012.csv TAVG_US_2013.csv
|
||||
TAVG_US_2014.csv TAVG_US_2015.csv TAVG_US_2016.csv TAVG_US_2017.csv
|
||||
TAVG_US_2018.csv TAVG_US_2019.csv
|
||||
|
||||
```
|
||||
Here are the first few lines for `TAVG_US_2010.csv`:
|
||||
```
|
||||
|
||||
|
||||
$ head TAVG_US_2010.csv
|
||||
USR0000AALC,20100101,TAVG,-220,,,U,
|
||||
USR0000AALP,20100101,TAVG,-9,,,U,
|
||||
USR0000ABAN,20100101,TAVG,12,,,U,
|
||||
USR0000ABCA,20100101,TAVG,16,,,U,
|
||||
USR0000ABCK,20100101,TAVG,-309,,,U,
|
||||
USR0000ABER,20100101,TAVG,-81,,,U,
|
||||
USR0000ABEV,20100101,TAVG,-360,,,U,
|
||||
USR0000ABEN,20100101,TAVG,-224,,,U,
|
||||
USR0000ABNS,20100101,TAVG,89,,,U,
|
||||
USR0000ABLA,20100101,TAVG,59,,,U,
|
||||
|
||||
```
|
||||
The [head][21] command is a utility for displaying the first several lines (by default, 10 lines) of a file.
|
||||
|
||||
The data has more information than you need. Limit the number of columns by eliminating column 3 (since all the data is average temperature) and column 5 onward. In other words, keep columns 1 (climate station), 2 (date), and 4 (temperature recorded).
|
||||
|
||||
**key_columns.sh**
|
||||
```
|
||||
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
# For each file with name that starts with "TAVG_US_" and ens with ".csv"
|
||||
for csv_file in `ls TAVG_US_*.csv`
|
||||
do
|
||||
echo "Exractiing columns $csv_file"
|
||||
# cat $csv_file: 'cat' is to con'cat'enate files - here used to show one year csv file
|
||||
# |: pipe
|
||||
# cut -d',' -f1,2,4: Cut columns 1,2,4 with , delimitor
|
||||
# > $csv_file.cut: Save to temporary file
|
||||
| > $csv_file.cut:
|
||||
cat $csv_file | cut -d',' -f1,2,4 > $csv_file.cut
|
||||
# mv $csv_file.cut $csv_file: Rename temporary file to original file
|
||||
mv $csv_file.cut $csv_file
|
||||
# File is processed and saved back into the same
|
||||
# There are other ways to do this
|
||||
# Using intermediate file is the most reliable method.
|
||||
done
|
||||
|
||||
```
|
||||
Run the script:
|
||||
```
|
||||
|
||||
|
||||
$ ./key_columns.sh
|
||||
Extracting columns TAVG_US_2010.csv
|
||||
...
|
||||
Extracting columns TAVG_US_2019.csv
|
||||
|
||||
```
|
||||
The first few lines of `TAVG_US_2010.csv` with the unneeded data removed are:
|
||||
```
|
||||
|
||||
|
||||
$ head TAVG_US_2010.csv
|
||||
USR0000AALC,20100101,-220
|
||||
USR0000AALP,20100101,-9
|
||||
USR0000ABAN,20100101,12
|
||||
USR0000ABCA,20100101,16
|
||||
USR0000ABCK,20100101,-309
|
||||
USR0000ABER,20100101,-81
|
||||
USR0000ABEV,20100101,-360
|
||||
USR0000ABEN,20100101,-224
|
||||
USR0000ABNS,20100101,89
|
||||
USR0000ABLA,20100101,59
|
||||
|
||||
```
|
||||
Dates are in string form (YMD). To train your model correctly, your algorithms need to recognize date fields in the comma-separated Y,M,D form (For example, `20100101` becomes `2010,01,01`). You can convert them with the [sed][22] utility.
|
||||
|
||||
**date_format.sh**
|
||||
```
|
||||
|
||||
|
||||
for csv_file in `ls TAVG_*.csv`
|
||||
do
|
||||
echo Date formatting $csv_file
|
||||
# This inserts , after year
|
||||
sed -i 's/,..../&,/' $csv_file
|
||||
# This inserts , after month
|
||||
sed -i 's/,....,../&,/' $csv_file
|
||||
done
|
||||
|
||||
```
|
||||
Run the script:
|
||||
```
|
||||
|
||||
|
||||
$ ./date_format.sh
|
||||
Date formatting TAVG_US_2010.csv
|
||||
...
|
||||
Date formatting TAVG_US_2019.csv
|
||||
|
||||
```
|
||||
The first few lines of `TAVG_US_2010.csv` with the comma-separated date format are:
|
||||
```
|
||||
|
||||
|
||||
$ head TAVG_US_2010.csv
|
||||
USR0000AALC,2010,01,01,-220
|
||||
USR0000AALP,2010,01,01,-9
|
||||
USR0000ABAN,2010,01,01,12
|
||||
USR0000ABCA,2010,01,01,16
|
||||
USR0000ABCK,2010,01,01,-309
|
||||
USR0000ABER,2010,01,01,-81
|
||||
USR0000ABEV,2010,01,01,-360
|
||||
USR0000ABEN,2010,01,01,-224
|
||||
USR0000ABNS,2010,01,01,89
|
||||
USR0000ABLA,2010,01,01,59
|
||||
|
||||
```
|
||||
### 3\. Aggregate states' average temperature data
|
||||
|
||||
The weather data comes from climate stations located in US cities, but you want to forecast whole states' temperatures. To convert the climate-station data to state data, first, map climate stations to their states.
|
||||
|
||||
Download the list of climate stations using wget:
|
||||
```
|
||||
`$ wget ftp://ftp.ncdc.noaa.gov/pub/data/ghcn/daily/ghcnd-stations.txt`
|
||||
```
|
||||
Extract the US stations with the [grep][23] utility to find US listings. The following command searches for lines that begin with the text `"US`." The `>` is a [redirection][24] that writes output to a file—in this case, to a file named `us_stations.txt`:
|
||||
```
|
||||
`$ grep "^US" ghcnd-stations.txt > us_stations.txt`
|
||||
```
|
||||
This file was created for pretty print, so the column separators are inconsistent:
|
||||
```
|
||||
|
||||
|
||||
$ head us_stations.txt
|
||||
US009052008 43.7333 -96.6333 482.0 SD SIOUX FALLS (ENVIRON. CANADA)
|
||||
US10RMHS145 40.5268 -105.1113 1569.1 CO RMHS 1.6 SSW
|
||||
US10adam001 40.5680 -98.5069 598.0 NE JUNIATA 1.5 S
|
||||
...
|
||||
|
||||
```
|
||||
Make them consistent by using [cat][25] to print the file, using [tr][26] to squeeze repeats and output to a temp file, and renaming the temp file back to the original—all in one line:
|
||||
```
|
||||
`$ cat us_stations.txt | tr -s ' ' > us_stations.txt.tmp; cp us_stations.txt.tmp us_stations.txt;`
|
||||
```
|
||||
The first lines of the command's output:
|
||||
```
|
||||
|
||||
|
||||
$ head us_stations.txt
|
||||
US009052008 43.7333 -96.6333 482.0 SD SIOUX FALLS (ENVIRON. CANADA)
|
||||
US10RMHS145 40.5268 -105.1113 1569.1 CO RMHS 1.6 SSW
|
||||
US10adam001 40.5680 -98.5069 598.0 NE JUNIATA 1.5 S
|
||||
...
|
||||
|
||||
```
|
||||
This contains a lot of info—GPS coordinates and such—but you only need the station code and state. Use [cut][27]:
|
||||
```
|
||||
`$ cut -d' ' -f1,5 us_stations.txt > us_stations.txt.tmp; mv us_stations.txt.tmp us_stations.txt;`
|
||||
```
|
||||
The first lines of the command's output:
|
||||
```
|
||||
|
||||
|
||||
$ head us_stations.txt
|
||||
US009052008 SD
|
||||
US10RMHS145 CO
|
||||
US10adam001 NE
|
||||
US10adam002 NE
|
||||
...
|
||||
|
||||
```
|
||||
Make this a CSV and change the spaces to comma separators using sed:
|
||||
```
|
||||
`$ sed -i s/' '/,/g us_stations.txt`
|
||||
```
|
||||
The first lines of the command's output:
|
||||
```
|
||||
|
||||
|
||||
$ head us_stations.txt
|
||||
US009052008,SD
|
||||
US10RMHS145,CO
|
||||
US10adam001,NE
|
||||
US10adam002,NE
|
||||
...
|
||||
|
||||
```
|
||||
Although you used several commands for these tasks, it is possible to perform all the steps in one run. Try it yourself.
|
||||
|
||||
Now, replace the station codes with their state locations by using [AWK][28], which is functionally high performant for large data processing.
|
||||
|
||||
**station_to_state_data.sh**
|
||||
```
|
||||
|
||||
|
||||
PATTERN_FILE=us_stations.txt
|
||||
|
||||
for DATA_FILE in `ls TAVG_US_*.csv`
|
||||
do
|
||||
echo ${DATA_FILE}
|
||||
|
||||
awk -F, \
|
||||
'FNR==NR { x[$1]=$2; next; } { $1=x[$1]; print $0 }' \
|
||||
OFS=, \
|
||||
${PATTERN_FILE} ${DATA_FILE} > ${DATA_FILE}.tmp
|
||||
|
||||
mv ${DATA_FILE}.tmp ${DATA_FILE}
|
||||
done
|
||||
|
||||
```
|
||||
Here is what these parameters mean:
|
||||
|
||||
`-F,` | Field separator is `,`
|
||||
---|---
|
||||
`FNR` | Line number in each file
|
||||
`NR` | Line number in both files together
|
||||
`FNR==NR` | Is TRUE only in the first file `${PATTERN_FILE}`
|
||||
`{ x[$1]=$2; next; }` | If `FNR==NR` is TRUE (for all lines in `$PATTERN_FILE` only)
|
||||
`- x` | Variable to store `station=state` map
|
||||
`- x[$1]=$2` | Adds data of `station=state` to map
|
||||
`- $1` | First column in first file (station codes)
|
||||
`- $2` | Second column in first file (state codes)
|
||||
`- x` | Map of all stations e.g., `x[US009052008]=SD`, `x[US10RMHS145]=CO`, ..., `x[USW00096409]=AK`
|
||||
`- next` | Go to next line matching `FNR==NR` (essentially, this creates a map of all stations-states from the `${PATTERN_FILE}`
|
||||
`{ $1=x[$1]; print $0 }` | If `FNR==NR` is FALSE (for all lines `in $DATA_FILE` only)
|
||||
`- $1=x[$1]` | Replace first field with `x[$1]`; essentially, replace station code with state code
|
||||
`- print $0` | Print all columns (including replaced `$1`)
|
||||
`OFS=,` | Output fields separator is `,`
|
||||
|
||||
The CSV with station codes:
|
||||
```
|
||||
|
||||
|
||||
$ head TAVG_US_2010.csv
|
||||
USR0000AALC,2010,01,01,-220
|
||||
USR0000AALP,2010,01,01,-9
|
||||
USR0000ABAN,2010,01,01,12
|
||||
USR0000ABCA,2010,01,01,16
|
||||
USR0000ABCK,2010,01,01,-309
|
||||
USR0000ABER,2010,01,01,-81
|
||||
USR0000ABEV,2010,01,01,-360
|
||||
USR0000ABEN,2010,01,01,-224
|
||||
USR0000ABNS,2010,01,01,89
|
||||
USR0000ABLA,2010,01,01,59
|
||||
|
||||
```
|
||||
Run the command:
|
||||
```
|
||||
|
||||
|
||||
$ ./station_to_state_data.sh
|
||||
TAVG_US_2010.csv
|
||||
...
|
||||
TAVG_US_2019.csv
|
||||
|
||||
```
|
||||
Stations are now mapped to states:
|
||||
```
|
||||
|
||||
|
||||
$ head TAVG_US_2010.csv
|
||||
AK,2010,01,01,-220
|
||||
AZ,2010,01,01,-9
|
||||
AL,2010,01,01,12
|
||||
AK,2010,01,01,16
|
||||
AK,2010,01,01,-309
|
||||
AK,2010,01,01,-81
|
||||
AK,2010,01,01,-360
|
||||
AK,2010,01,01,-224
|
||||
AZ,2010,01,01,59
|
||||
AK,2010,01,01,-68
|
||||
|
||||
```
|
||||
Every state has several temperature readings for each day, so you need to calculate the average of each state's readings for a day. Use AWK for text processing, [sort][29] to ensure the final results are in a logical order, and [rm][30] to delete the temporary file after processing.
|
||||
|
||||
**station_to_state_data.sh**
|
||||
```
|
||||
|
||||
|
||||
PATTERN_FILE=us_stations.txt
|
||||
|
||||
for DATA_FILE in `ls TAVG_US_*.csv`
|
||||
do
|
||||
echo ${DATA_FILE}
|
||||
|
||||
awk -F, \
|
||||
'FNR==NR { x[$1]=$2; next; } { $1=x[$1]; print $0 }' \
|
||||
OFS=, \
|
||||
${PATTERN_FILE} ${DATA_FILE} > ${DATA_FILE}.tmp
|
||||
|
||||
mv ${DATA_FILE}.tmp ${DATA_FILE}
|
||||
done
|
||||
|
||||
```
|
||||
Here is what the AWK parameters mean:
|
||||
|
||||
`FILE=$DATA_FILE` | CSV file processed as `FILE`
|
||||
---|---
|
||||
`-F,` | Field separator is `,`
|
||||
`state_day_sum[$1 "," $2 "," $3 "," $4] = $5 state_day_sum[$1 "," $2 "," $3 "," $4] + $5` | Sum of temperature (`$5`) for the state `($1`) on year (`$2`), month (`$3`), day (`$4`)
|
||||
`state_day_num[$1 "," $2 "," $3 "," $4] = $5 state_day_num[$1 "," $2 "," $3 "," $4] + 1` | Number of temperature readings for the state (`$1`) on year (`$2`), month (`$3`), day (`$4`)
|
||||
`END` | In the end, after collecting sum and number of readings for all states, years, months, days, calculate averages
|
||||
`for (state_day_key in state_day_sum)` | For each state-year-month-day
|
||||
`print state_day_key "," state_day_sum[state_day_key]/state_day_num[state_day_key]` | Print state,year,month,day,average
|
||||
`OFS=,` | Output fields separator is `,`
|
||||
`$DATA_FILE` | Input file (all files with name starting with `TAVG_US_` and ending with `.csv`, one by one)
|
||||
`> STATE_DAY_${DATA_FILE}.tmp` | Save result to a temporary file
|
||||
|
||||
Run the script:
|
||||
```
|
||||
|
||||
|
||||
$ ./TAVG_avg.sh
|
||||
TAVG_US_2010.csv
|
||||
TAVG_US_2011.csv
|
||||
TAVG_US_2012.csv
|
||||
TAVG_US_2013.csv
|
||||
TAVG_US_2014.csv
|
||||
TAVG_US_2015.csv
|
||||
TAVG_US_2016.csv
|
||||
TAVG_US_2017.csv
|
||||
TAVG_US_2018.csv
|
||||
TAVG_US_2019.csv
|
||||
|
||||
```
|
||||
These files are created:
|
||||
```
|
||||
|
||||
|
||||
$ ls STATE_DAY_TAVG_US_20*.csv
|
||||
STATE_DAY_TAVG_US_2010.csv STATE_DAY_TAVG_US_2015.csv
|
||||
STATE_DAY_TAVG_US_2011.csv STATE_DAY_TAVG_US_2016.csv
|
||||
STATE_DAY_TAVG_US_2012.csv STATE_DAY_TAVG_US_2017.csv
|
||||
STATE_DAY_TAVG_US_2013.csv STATE_DAY_TAVG_US_2018.csv
|
||||
STATE_DAY_TAVG_US_2014.csv STATE_DAY_TAVG_US_2019.csv
|
||||
|
||||
```
|
||||
See one year of data for all states ([less][31] is a utility to see output a page at a time):
|
||||
```
|
||||
|
||||
|
||||
$ less STATE_DAY_TAVG_US_2010.csv
|
||||
AK,2010,01,01,-181.934
|
||||
...
|
||||
AK,2010,01,31,-101.068
|
||||
AK,2010,02,01,-107.11
|
||||
...
|
||||
AK,2010,02,28,-138.834
|
||||
...
|
||||
WY,2010,01,01,-43.5625
|
||||
...
|
||||
WY,2010,12,31,-215.583
|
||||
|
||||
```
|
||||
Merge all the data files into one:
|
||||
```
|
||||
`$ cat STATE_DAY_TAVG_US_20*.csv > TAVG_US_2010-2019.csv`
|
||||
```
|
||||
You now have one file, with all states, for all years:
|
||||
```
|
||||
|
||||
|
||||
$ cat TAVG_US_2010-2019.csv
|
||||
AK,2010,01,01,-181.934
|
||||
...
|
||||
WY,2018,12,31,-167.421
|
||||
AK,2019,01,01,-32.3386
|
||||
...
|
||||
WY,2019,12,30,-131.028
|
||||
WY,2019,12,31,-79.8704
|
||||
|
||||
```
|
||||
## 4\. Make time-series data
|
||||
|
||||
A problem like this is fittingly addressed with a time-series model such as long short-term memory ([LSTM][32]), which is a recurring neural network ([RNN][33]). This input data is organized into time slices; consider 20 days to be one slice.
|
||||
|
||||
This is a one-time slice (as in `STATE_DAY_TAVG_US_2010.csv`):
|
||||
```
|
||||
|
||||
|
||||
X (input – 20 weeks):
|
||||
AK,2010,01,01,-181.934
|
||||
AK,2010,01,02,-199.531
|
||||
...
|
||||
AK,2010,01,20,-157.273
|
||||
|
||||
y (21st week, prediction for these 20 weeks):
|
||||
AK,2010,01,21,-165.31
|
||||
|
||||
```
|
||||
This time slice is represented as (temperature values where the first 20 weeks are X, and 21 is y):
|
||||
```
|
||||
|
||||
|
||||
AK, -181.934,-199.531, ... ,
|
||||
-157.273,-165.3
|
||||
|
||||
```
|
||||
The slices are time-contiguous. For example, the end of 2010 continues into 2011:
|
||||
```
|
||||
|
||||
|
||||
AK,2010,12,22,-209.92
|
||||
...
|
||||
AK,2010,12,31,-79.8523
|
||||
AK,2011,01,01,-59.5658
|
||||
...
|
||||
AK,2011,01,10,-100.623
|
||||
|
||||
```
|
||||
Which results in the prediction:
|
||||
```
|
||||
`AK,2011,01,11,-106.851`
|
||||
```
|
||||
This time slice is taken as:
|
||||
```
|
||||
`AK, -209.92, ... ,-79.8523,-59.5658, ... ,-100.623,-106.851`
|
||||
```
|
||||
and so on, for all states, years, months, and dates. For more explanation, see this tutorial on [time-series forecasting][34].
|
||||
|
||||
Write a script to create time slices:
|
||||
|
||||
**timeslices.sh**
|
||||
```
|
||||
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
TIME_SLICE_PERIOD=20
|
||||
|
||||
file=TAVG_US_2010-2019.csv
|
||||
|
||||
# For each state in file
|
||||
for state in `cut -d',' -f1 $file | sort | uniq`
|
||||
do
|
||||
# Get all temperature values for the state
|
||||
state_tavgs=`grep $state $file | cut -d',' -f5`
|
||||
# How many time slices will this result in?
|
||||
# mber of temperatures recorded minus size of one timeslice
|
||||
num_slices=`echo $state_tavgs | wc -w`
|
||||
num_slices=$((${num_slices} - ${TIME_SLICE_PERIOD}))
|
||||
# Initialize
|
||||
slice_start=1; num_slice=0;
|
||||
# For each timeslice
|
||||
while [ $num_slice -lt $num_slices ]
|
||||
do
|
||||
# One timeslice is from slice_start to slice_end
|
||||
slice_end=$(($slice_start + $TIME_SLICE_PERIOD - 1))
|
||||
# X (1-20)
|
||||
sliceX="$slice_start-$slice_end"
|
||||
# y (21)
|
||||
slicey=$(($slice_end + 1))
|
||||
# Print state and timeslice temperature values (column 1-20 and 21)
|
||||
echo $state `echo $state_tavgs | cut -d' ' -f$sliceX,$slicey`
|
||||
# Increment
|
||||
slice_start=$(($slice_start + 1)); num_slice=$(($num_slice + 1));
|
||||
done
|
||||
done
|
||||
|
||||
```
|
||||
Run the script. It uses spaces as column separators; make them commas with sed:
|
||||
```
|
||||
`$ ./timeslices.sh > TIMESLICE_TAVG_US_2010-2019.csv; sed -i s/' '/,/g TIME_VARIANT_TAVG_US_2010-2019.csv`
|
||||
```
|
||||
Here are the first few lines and the last few lines of the output .csv:
|
||||
```
|
||||
|
||||
|
||||
$ head -3 TIME_VARIANT_TAVG_US_2009-2019.csv
|
||||
AK,-271.271,-290.057,-300.324,-277.603,-270.36,-293.152,-292.829,-270.413,-256.674,-241.546,-217.757,-158.379,-102.585,-24.9517,-1.7973,15.9597,-5.78231,-33.932,-44.7655,-92.5694,-123.338
|
||||
AK,-290.057,-300.324,-277.603,-270.36,-293.152,-292.829,-270.413,-256.674,-241.546,-217.757,-158.379,-102.585,-24.9517,-1.7973,15.9597,-5.78231,-33.932,-44.7655,-92.5694,-123.338,-130.829
|
||||
AK,-300.324,-277.603,-270.36,-293.152,-292.829,-270.413,-256.674,-241.546,-217.757,-158.379,-102.585,-24.9517,-1.7973,15.9597,-5.78231,-33.932,-44.7655,-92.5694,-123.338,-130.829,-123.979
|
||||
|
||||
$ tail -3 TIME_VARIANT_TAVG_US_2009-2019.csv
|
||||
WY,-76.9167,-66.2315,-45.1944,-27.75,-55.3426,-81.5556,-124.769,-137.556,-90.213,-54.1389,-55.9907,-30.9167,-9.59813,7.86916,-1.09259,-13.9722,-47.5648,-83.5234,-98.2963,-124.694,-142.898
|
||||
WY,-66.2315,-45.1944,-27.75,-55.3426,-81.5556,-124.769,-137.556,-90.213,-54.1389,-55.9907,-30.91
|
||||
@@ -0,0 +1,108 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Customize Task Switching Experience on GNOME Desktop With These Nifty Tools)
|
||||
[#]: via: (https://itsfoss.com/customize-gnome-task-switcher/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
Customize Task Switching Experience on GNOME Desktop With These Nifty Tools
|
||||
======
|
||||
|
||||
Unless you’re new to Linux, you know that there are several [popular desktop environment][1] choices for users. And if you’re that newbie, I recommend you to learn [what a desktop environment is][2] along with this tutorial.
|
||||
|
||||
Here, I shall be focusing on tweaking the task switching experience on GNOME. I know that the majority of users just tend to use it as is and stock settings are good enough for the most part.
|
||||
|
||||
I mean there is nothing wrong with the application switcher that [you use with Alt+Tab keyboard shortcut in Ubuntu][3].
|
||||
|
||||
![][4]
|
||||
|
||||
However, if you are a tinkerer who wants to [customize the look and feel of your GNOME desktop][5], including the task switcher and animation effects when launching or minimizing an app — you might want to continue reading this article.
|
||||
|
||||
### Change GNOME Task Switcher to Windows 7 Style Effect
|
||||
|
||||
![][6]
|
||||
|
||||
Switching between running applications using the key bind **Alt+Tab** is fast but it may not be the most intuitive experience for some. You just get to cycle through a bunch of icons depending on the number of active applications.
|
||||
|
||||
What if you want to change how the task switcher looks?
|
||||
|
||||
Well, you can easily give it a look of Windows 7 Aero Flip 3D effect. And, here’s how it will look:
|
||||
|
||||
![][7]
|
||||
|
||||
It definitely looks interesting to have a different task switcher. Why? Just for fun or to share your desktop’s screenshot on Linux communities.
|
||||
|
||||
Now, to get this on your GNOME desktop, here’s what you have to do:
|
||||
|
||||
Step 1: Enable GNOME extensions if you haven’t already. You can follow our guide to [learn how to use GNOME shell extensions][8].
|
||||
|
||||
Step 2: Once you are done with the setup, you can proceed downloading and installing the [Coverflow GNOME extension][9] from GNOME extensions website.
|
||||
|
||||
In case you haven’t installed the browser extension, you can just click on the link “**Click here to install browser extension**” from the notice as shown in the screenshot below.
|
||||
|
||||
![][10]
|
||||
|
||||
Step 3: Next, you just have to refresh the web page and enable the extension as shown in the screenshot below.
|
||||
|
||||
![][11]
|
||||
|
||||
You also get some customization options if you click on the “gear” icon right to the toggle button.
|
||||
|
||||
![][12]
|
||||
|
||||
Of course, depending on how fast you want it to be or how good you want it to look, you will have to adjust the animation speed accordingly.
|
||||
|
||||
Next, why not some kind of cool effect when you interact with applications (minimize/close)? I have just the solution for you.
|
||||
|
||||
### Add Genie Animation Effect While Minimizing & Re-opening Applications
|
||||
|
||||
There’s an interesting effect (sort of like genie popping out of a lamp) that you can add to see when you minimize or re-open an app.
|
||||
|
||||
This also comes as a GNOME extension, so you do not need to do anything else to get started.
|
||||
|
||||
You just have to head to the extensions page, which is [Compiz alike Magic Lamp effect][13] and then enable the extension to see it in action.
|
||||
|
||||
![][14]
|
||||
|
||||
Here’s how it looks in action:
|
||||
|
||||
![][15]
|
||||
|
||||
It would look even cooler if you switch the Ubuntu dock to the bottom.
|
||||
|
||||
Exciting GNOME extensions, right? You can play around to tweak your GNOME experience using the [GNOME tweaks app][16] and [install some beautiful icon themes][17] or explore different options.
|
||||
|
||||
How do you prefer to customize your GNOME experience? Is there any other cool GNOME extension or an app that you tend to utilize? Feel free to share your thoughts in the comments below.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/customize-gnome-task-switcher/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/best-linux-desktop-environments/
|
||||
[2]: https://itsfoss.com/what-is-desktop-environment/
|
||||
[3]: https://itsfoss.com/ubuntu-shortcuts/
|
||||
[4]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2017/10/gnome-app-switcher.jpeg?resize=800%2C255&ssl=1
|
||||
[5]: https://itsfoss.com/gnome-tricks-ubuntu/
|
||||
[6]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/ubuntu-coverflow-screenshot.jpg?resize=800%2C387&ssl=1
|
||||
[7]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/coverflow-task-switcher.jpg?resize=800%2C392&ssl=1
|
||||
[8]: https://itsfoss.com/gnome-shell-extensions/
|
||||
[9]: https://extensions.gnome.org/extension/97/coverflow-alt-tab/
|
||||
[10]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/gnome-shell-extension-browser.jpg?resize=800%2C401&ssl=1
|
||||
[11]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/coverflow-enable.jpg?resize=800%2C303&ssl=1
|
||||
[12]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/coverflow-settings.png?resize=800%2C481&ssl=1
|
||||
[13]: https://extensions.gnome.org/extension/3740/compiz-alike-magic-lamp-effect/
|
||||
[14]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/magic-lamp-extension.jpg?resize=800%2C355&ssl=1
|
||||
[15]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/magic-lamp-effect-800x380.gif?resize=800%2C380&ssl=1
|
||||
[16]: https://itsfoss.com/gnome-tweak-tool/
|
||||
[17]: https://itsfoss.com/best-icon-themes-ubuntu-16-04/
|
||||
@@ -0,0 +1,102 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Keep track of multiple Git remote repositories)
|
||||
[#]: via: (https://opensource.com/article/20/11/multiple-git-repositories)
|
||||
[#]: author: (Peter Portante https://opensource.com/users/portante)
|
||||
|
||||
Keep track of multiple Git remote repositories
|
||||
======
|
||||
Having consistent naming standards is key to keeping local and upstream
|
||||
Git repos straight.
|
||||
![Digital hand surrounding by objects, bike, light bulb, graphs][1]
|
||||
|
||||
Working with remote repositories gets confusing when the names of the remote repositories in your local Git repo are inconsistent.
|
||||
|
||||
One approach to solving this issue is to standardize the use and meaning of two words: `origin`, referring to your personal `example.com/<USER>/*` repos, and `upstream`, referring to the `example.com` repo from which you forked the `origin` repo. In other words, `upstream` refers to the upstream repo where work is publicly submitted, while `origin` refers to your local fork of the upstream repo from which you generate pull requests (PRs), for example.
|
||||
|
||||
Using the [pbench][2] repo as an example, here is a step-by-step approach to set up a new local clone with `origin` and `upstream` defined consistently.
|
||||
|
||||
1. On most Git hosting services, you must fork a project when you want to work on it. When you run your own Git server, that's not necessary, but for a codebase that's open to the public, it's an easy way to transfer diffs among contributors.
|
||||
|
||||
Create a fork of a Git repository. For this example, assume your fork is located at `example.com/<USER>/pbench`.
|
||||
|
||||
2. Next, you must obtain a Uniform Resource Identifier ([URI][3]) for cloning over SSH. On most Git hosting services, such as GitLab or GitHub, it's in a button or panel labeled **Clone** or **Clone over SSH**. Copy the clone URI to your clipboard.
|
||||
|
||||
3. On your development system, clone the repo using the text you copied:
|
||||
|
||||
|
||||
```
|
||||
`$ git clone git@example.com:<USER>/pbench.git`
|
||||
```
|
||||
|
||||
This clones the Git repository with the default name `origin` for your forked copy of the pbench repo.
|
||||
|
||||
4. Change directory to the repo you just cloned:
|
||||
|
||||
|
||||
```
|
||||
`$ cd ~/pbench`
|
||||
```
|
||||
|
||||
5. Next, obtain the SSH URI of the source repo (the one you originally forked). This is probably done the same way as above: Find the **Clone** button or panel and copy the clone address. In software development, this is typically referred to as "upstream" because (in theory) this is where most commits happen, and you intend to let those commits flow downstream into your copy of the repository.
|
||||
|
||||
6. Add the URI to your local copy of the repository. Yes, there will be _two different_ remotes assigned to your local copy of the repository:
|
||||
|
||||
|
||||
```
|
||||
`$ git remote add upstream \ git@example.com:bigproject/pbench.git`
|
||||
```
|
||||
|
||||
7. You now have two named remote repos: `origin` and `upstream`. You can see your remote repos with the remote subcommand:
|
||||
|
||||
|
||||
```
|
||||
`$ git remote -v`
|
||||
```
|
||||
|
||||
Right now, your local `master` branch is tracking the `origin` master, which is not necessarily what you want. You probably want to track the `upstream` version of this branch because upstream is where most development takes place. The idea is that you are adding your changes on top of whatever you get from upstream.
|
||||
|
||||
8. Change your local master branch to track `upstream/master`:
|
||||
|
||||
|
||||
```
|
||||
$ git fetch upstream
|
||||
$ git branch --set-upstream-to=upstream/master master
|
||||
```
|
||||
|
||||
You can do this for any branch you want, not just `master`. For instance, some projects use a `dev` branch for all unstable changes, reserving `master` for code approved for release.
|
||||
|
||||
9. Once you've set your tracking branches, be sure to `rebase` your master to bring it up to date to any new changes made to the upstream repo:
|
||||
|
||||
|
||||
```
|
||||
$ git remote update
|
||||
$ git checkout master
|
||||
$ git rebase
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
This is a great way to keep your Git repositories synchronized between forks. If you want to automate this, read Seth Kenlon's article on [cohosting Git repositories with Ansible][4] to learn how.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/multiple-git-repositories
|
||||
|
||||
作者:[Peter Portante][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/portante
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003588_01_rd3os.combacktoschoolseriesk12_rh_021x_0.png?itok=fvorN0e- (Digital hand surrounding by objects, bike, light bulb, graphs)
|
||||
[2]: https://github.com/distributed-system-analysis/pbench
|
||||
[3]: https://en.wikipedia.org/wiki/Uniform_Resource_Identifier
|
||||
[4]: https://opensource.com/article/19/11/how-host-github-gitlab-ansible
|
||||
122
sources/tech/20201126 5 open source alternatives to GitHub.md
Normal file
122
sources/tech/20201126 5 open source alternatives to GitHub.md
Normal file
@@ -0,0 +1,122 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (5 open source alternatives to GitHub)
|
||||
[#]: via: (https://opensource.com/article/20/11/open-source-alternatives-github)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
5 open source alternatives to GitHub
|
||||
======
|
||||
Stay resilient by keeping your open source code in an open source
|
||||
repository.
|
||||
![Woman programming][1]
|
||||
|
||||
Git is a popular version-control system, primarily used for code but popular in [other disciplines][2], too. It can run locally on your computer for personal use, it can run on a server for collaboration, and it can also run as a hosted service for widespread public participation. There are many hosted services out there, and one of the most popular brands is [GitHub][3].
|
||||
|
||||
GitHub is not open source. Pragmatically, this doesn't make much of a difference to most users. The vast majority of code put onto GitHub is, presumably, encouraged to be shared by everyone, so GitHub's primary function is a sort of public backup service. Should GitHub fold or drastically change its terms of service, recovering data would be relatively simple because it's expected that you have a local copy of the code you keep on GitHub. However, some organizations have come to rely on the non-Git parts of GitHub's service offerings, making migration away from GitHub difficult. That's an awkward place to be, so for many people and organizations, insurance against vendor lock-in is a worthwhile investment.
|
||||
|
||||
If that's the position you're in, check out these five GitHub alternatives, all of which are open source.
|
||||
|
||||
### 1\. GitLab
|
||||
|
||||
![GitLab][4]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][5])
|
||||
|
||||
GitLab is more than just a GitHub alternative; it's more like a complete DevOps platform. GitLab is nearly all the infrastructure a software development house requires, as it provides code and project management tools, issue reporting, continuous delivery, and monitoring. You can use GitLab on [GitLab.com][6], or you can download the codebase and run it locally with or without paid support. GitLab has a web interface, but all Git-specific commands work as expected.
|
||||
|
||||
GitLab is committed to open source, both in its code and the organization behind it, and to Git itself. The organization publishes much of its business documentation, including [how employees are onboarded][7], their [marketing policies][8], and much more. As a site, GitLab is ardent in promoting Git. When you use a site-specific feature (such as a merge request), GitLab's interface explains how to resolve the request in pure Git, should you prefer to work in the terminal.
|
||||
|
||||
### 2\. Gitolite
|
||||
|
||||
[Gitolite][9] is quite probably the minimal amount of code required to provide a server administrator a frontend for Git repository management. Unlike GitHub, it has no web interface, no desktop client, and adds nothing to Git from the user perspective. In fact, your users don't really use Gitolite directly. They just use Git, as usual, whether they're used to Git in a terminal or Git in a frontend client like [Git Cola][10].
|
||||
|
||||
From the server administrator's perspective, though, Gitolite solves all the permission and access problems you'd have to manage manually if you ran a plain Git server. With Gitolite, you create only one user (for instance, a user called `git`) on your server. You allow your users to use this single login identity to access your Git server, but when they log in, they must deal with your Git server through Gitolite. It's Gitolite that verifies users' access permissions, manages their SSH keys, verifies their privilege level when accessing specific repositories, and more. Instead of creating and managing countless Unix user accounts, all the administrator has to do is list users (identified by their SSH public keys) to the repositories they are allowed to access. Gitolite takes care of everything else.
|
||||
|
||||
Gitolite is nearly invisible to users, and it makes Git management nearly invisible to the server admin. As long as you don't require a web interface, Gitolite is a net win for everyone involved.
|
||||
|
||||
### 3\. Gitea and Gogs
|
||||
|
||||
![Gitea][11]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][5])
|
||||
|
||||
The [Gogs project][12] is an MIT-Licensed Git server framework and web user interface. In 2016, some Gogs users felt development was hindered because only its initial developer had write access to its development repository, so they forked the code to [Gitea][13]. Today, both projects co-exist independently of one another, and from a user's perspective, they are basically the same experience. Ironically, both projects are hosted on GitHub.
|
||||
|
||||
With Gitea and Gogs, you download the source code and run it as a service on your server. This provides a website for users, where they can create an account, log in, create their own repositories, upload code, navigate through code, file issues and bug reports, request code merges, manage SSH keys, and so on. The interface is similar in look and feel to GitLab, GitHub, or Bitbucket, so if users have any experience with an online-code management system, they're already essentially familiar with Gitea and Gogs.
|
||||
|
||||
Gitea or Gogs can be installed as a package on any Linux server, including a Raspberry Pi, as a container, on BSD, macOS, or Windows, or compiled from source code. They're both cross-platform, so they can be run on anything that runs Go. Read Ricardo Gerardi's article about [setting up a Gogs container using Podman][14] for more information.
|
||||
|
||||
### 4\. Independent communities
|
||||
|
||||
![Notabug][15]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][5])
|
||||
|
||||
If you're not up for self-hosting, you can cheat a little by using a self-hosted option on somebody else's server. There are many independent sites out there, such as [Codeberg][16], Nixnet, Tinfoil-hat, and [Notabug.org][17]. Some run Gitea and others run Gogs, but the result is the same: free code hosting to help you keep your work safe and public. These solutions may not be as complex as something like GitLab or GitHub, they may not offer on-demand Jenkins pipelines and continuous integration/continuous development (CI/CD) solutions, but they're great mirrors for your work.
|
||||
|
||||
There are purpose-specific providers, too: a [Gitea instance for FSFE supporters][18], a Gitlab instance for [Freedesktop projects][19], and another for [GNOME projects][20].
|
||||
|
||||
Because these independent servers are smaller communities, you might also find that the "social" aspect of social coding is more significant. I've made several online friends through an independent Git provider, while GitHub has proven to be, at least socially, underwhelming.
|
||||
|
||||
The message is clear: there's no requirement or advantage for there to be a centralized, dominant, non-free Git software hosting service.
|
||||
|
||||
### 5\. Git
|
||||
|
||||
It might surprise you to know that Git is surprisingly self-reliant as a server. While it lacks user management and permission settings, Git integrates with SSH and ships with a special `git-shell` application designed specifically to serve as a limited environment for using Git commands. By setting users' default shell to `git-shell`, you can limit what actions are available to them when they interact with your server.
|
||||
|
||||
What Git alone does not offer is repository permission tools to help you manage what each user has access to. For this, you'll have to fall back on the operating system's user and access control list (ACL) controls, which can become tedious should you have more than just a handful of users. For small projects or projects just starting, running Git on a Linux server is an easy and immediate solution to the need for a collaborative space. For more information, read my article on [building a Git server][21].
|
||||
|
||||
### Bonus: Fossil
|
||||
|
||||
![Fossil UI][22]
|
||||
|
||||
(Klaatu, [CC BY-SA 4.0][5])
|
||||
|
||||
Fossil isn't by any means Git, and in a sense, that's its appeal as an alternative to GitHub. In fact, Fossil is an alternative to the entire Git system. It's a complete version-control system, like Git, and it also has bug tracking, wiki, forum, and documentation features _built into every repository you create_. It also has a web interface included and is entirely self-contained. If it all sounds too good to be true, you can see it in action at [fossil-scm.org][23], because Fossil's homepage runs on Fossil!
|
||||
|
||||
Read Klaatu's article on [getting started with Fossil][24] for more information.
|
||||
|
||||
### Open source means choice
|
||||
|
||||
The best thing about Git (and Fossil) is that they're open source technologies. You can choose whatever solution works best for you. In fact, because Git is also distributed, you can even choose _multiple_ solutions. There's nothing stopping you from hosting your code on several services and writing to all of them with each push. Take a look at your options, decide what works best for you, and get to work!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/open-source-alternatives-github
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/programming-code-keyboard-laptop-music-headphones.png?itok=EQZ2WKzy (Woman programming)
|
||||
[2]: https://opensource.com/article/19/4/write-git
|
||||
[3]: https://github.com/
|
||||
[4]: https://opensource.com/sites/default/files/uploads/gitlab.jpg (GitLab)
|
||||
[5]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[6]: https://gitlab.com
|
||||
[7]: https://about.gitlab.com/handbook/people-group/general-onboarding/onboarding-processes
|
||||
[8]: https://about.gitlab.com/handbook
|
||||
[9]: https://gitolite.com/gitolite/index.html
|
||||
[10]: https://opensource.com/article/20/3/git-cola
|
||||
[11]: https://opensource.com/sites/default/files/uploads/gitea.jpg (Gitea)
|
||||
[12]: https://gogs.io
|
||||
[13]: https://gitea.io
|
||||
[14]: https://www.redhat.com/sysadmin/git-gogs-podman
|
||||
[15]: https://opensource.com/sites/default/files/uploads/notabug.jpg (Notabug)
|
||||
[16]: https://join.codeberg.org/
|
||||
[17]: https://notabug.org
|
||||
[18]: https://git.fsfe.org/
|
||||
[19]: https://gitlab.freedesktop.org
|
||||
[20]: https://gitlab.gnome.org
|
||||
[21]: https://opensource.com/life/16/8/how-construct-your-own-git-server-part-6
|
||||
[22]: https://opensource.com/sites/default/files/uploads/fossil-ui.jpg (Fossil UI)
|
||||
[23]: https://www.fossil-scm.org
|
||||
[24]: https://opensource.com/article/20/11/fossil
|
||||
223
sources/tech/20201127 Getting started with Fedora CoreOS.md
Normal file
223
sources/tech/20201127 Getting started with Fedora CoreOS.md
Normal file
@@ -0,0 +1,223 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Getting started with Fedora CoreOS)
|
||||
[#]: via: (https://fedoramagazine.org/getting-started-with-fedora-coreos/)
|
||||
[#]: author: (Clément Verna https://fedoramagazine.org/author/cverna/)
|
||||
|
||||
Getting started with Fedora CoreOS
|
||||
======
|
||||
|
||||
![Getting started with Fedora CoreOS][1]
|
||||
|
||||
Photo by [Paweł Czerwiński][2] on [Unsplash][3]
|
||||
|
||||
This has been called the age of DevOps, and operating systems seem to be getting a little bit less attention than tools are. However, this doesn’t mean that there has been no innovation in operating systems. [Edit: The diversity of offerings from the plethora of distributions based on the Linux kernel is a fine example of this.] [Fedora CoreOS][4] has a specific philosophy of what an operating system should be in this age of DevOps.
|
||||
|
||||
### Fedora CoreOS’ philosophy
|
||||
|
||||
Fedora CoreOS (FCOS) came from the merging of CoreOS Container Linux and Fedora Atomic Host. It is a minimal and monolithic OS focused on running containerized applications. Security being a first class citizen, FCOS provides automatic updates and comes with SELinux hardening.
|
||||
|
||||
For automatic updates to work well they need to be very robust. The goal being that servers running FCOS won’t break after an update. This is achieved by using different release streams (stable, testing and next). Each stream is released every 2 weeks and content is promoted from one stream to the other (next -> testing -> stable). That way updates landing in the stable stream have had the opportunity to be tested over a long period of time.
|
||||
|
||||
### Getting Started
|
||||
|
||||
For this example let’s use the stable stream and a QEMU base image that we can run as a virtual machine. You can use [coreos-installer][5] to download that image.
|
||||
|
||||
From your (Workstation) terminal, run the following commands after updating the link to the image. [Edit: On Silverblue the container based coreos tools are the simplest method to try. Instructions can be found at <https://docs.fedoraproject.org/en-US/fedora-coreos/tutorial-setup/> , in particular “Setup with Podman or Docker”.]
|
||||
|
||||
```
|
||||
$ sudo dnf install coreos-installer
|
||||
$ coreos-installer download --image-url https://builds.coreos.fedoraproject.org/prod/streams/stable/builds/32.20200907.3.0/x86_64/fedora-coreos-32.20200907.3.0-qemu.x86_64.qcow2.xz
|
||||
$ xz -d fedora-coreos-32.20200907.3.0-qemu.x86_64.qcow2.xz
|
||||
$ ls
|
||||
fedora-coreos-32.20200907.3.0-qemu.x86_64.qcow2
|
||||
```
|
||||
|
||||
#### Create a configuration
|
||||
|
||||
To customize a FCOS system, you need to provide a configuration file that will be used by [Ignition][6] to provision the system. You may use this file to configure things like creating a user, adding a trusted SSH key, enabling systemd services, and more.
|
||||
|
||||
The following configuration creates a _‘core’_ user and adds an SSH key to the authorized_keys file. It is also creating a systemd service that uses [podman][7] to run a simple hello world container.
|
||||
|
||||
```
|
||||
version: "1.0.0"
|
||||
variant: fcos
|
||||
passwd:
|
||||
users:
|
||||
- name: core
|
||||
ssh_authorized_keys:
|
||||
- ssh-ed25519 my_public_ssh_key_hash fcos_key
|
||||
systemd:
|
||||
units:
|
||||
-
|
||||
contents: |
|
||||
[Unit]
|
||||
Description=Run a hello world web service
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
[Service]
|
||||
ExecStart=/bin/podman run --pull=always --name=hello --net=host -p 8080:8080 quay.io/cverna/hello
|
||||
ExecStop=/bin/podman rm -f hello
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
enabled: true
|
||||
name: hello.service
|
||||
```
|
||||
|
||||
After adding your SSH key in the configuration save it as _config.yaml_. Next use the Fedora CoreOS Config Transpiler (fcct) tool to convert this YAML configuration into a valid Ignition configuration (JSON format).
|
||||
|
||||
Install _fcct_ directly from Fedora’s repositories or get the binary from [GitHub][8].
|
||||
|
||||
```
|
||||
$ sudo dnf install fcct
|
||||
$ fcct -output config.ign config.yaml
|
||||
```
|
||||
|
||||
#### Install and run Fedora CoreOS
|
||||
|
||||
To run the image, you can use the libvirt stack. To install it on a Fedora system using the dnf package manager
|
||||
|
||||
```
|
||||
$ sudo dnf install @virtualization
|
||||
```
|
||||
|
||||
Now let’s create and run a Fedora CoreOS virtual machine
|
||||
|
||||
```
|
||||
$ chcon --verbose unconfined_u:object_r:svirt_home_t:s0 config.ign
|
||||
$ virt-install --name=fcos \
|
||||
--vcpus=2 \
|
||||
--ram=2048 \
|
||||
--import \
|
||||
--network=bridge=virbr0 \
|
||||
--graphics=none \
|
||||
--qemu-commandline="-fw_cfg name=opt/com.coreos/config,file=${PWD}/config.ign" \
|
||||
--disk=size=20,backing_store=${PWD}/fedora-coreos-32.20200907.3.0-qemu.x86_64.qcow2
|
||||
```
|
||||
|
||||
Once the installation is successful, some information is displayed and a login prompt is provided.
|
||||
|
||||
```
|
||||
Fedora CoreOS 32.20200907.3.0
|
||||
Kernel 5.8.10-200.fc32.x86_64 on an x86_64 (ttyS0)
|
||||
SSH host key: SHA256:BJYN7AQZrwKZ7ZF8fWSI9YRhI++KMyeJeDVOE6rQ27U (ED25519)
|
||||
SSH host key: SHA256:W3wfZp7EGkLuM3z4cy1ZJSMFLntYyW1kqAqKkxyuZrE (ECDSA)
|
||||
SSH host key: SHA256:gb7/4Qo5aYhEjgoDZbrm8t1D0msgGYsQ0xhW5BAuZz0 (RSA)
|
||||
ens2: 192.168.122.237 fe80::5054:ff:fef7:1a73
|
||||
Ignition: user provided config was applied
|
||||
Ignition: wrote ssh authorized keys file for user: core
|
||||
```
|
||||
|
||||
The Ignition configuration file did not provide any password for the _core_ user, therefore it is not possible to login directly via the console. (Though, it is possible to configure a password for users via Ignition configuration.)
|
||||
|
||||
Use Ctrl + ] key combination to exit the virtual machine’s console. Then check if the hello.service is running.
|
||||
|
||||
```
|
||||
$ curl http://192.168.122.237:8080
|
||||
Hello from Fedora CoreOS!
|
||||
```
|
||||
|
||||
Using the preconfigured SSH key, you can also access the VM and inspect the services running on it.
|
||||
|
||||
```
|
||||
$ ssh core@192.168.122.237
|
||||
$ systemctl status hello
|
||||
● hello.service - Run a hello world web service
|
||||
Loaded: loaded (/etc/systemd/system/hello.service; enabled; vendor preset: enabled)
|
||||
Active: active (running) since Wed 2020-10-28 10:10:26 UTC; 42s ago
|
||||
```
|
||||
|
||||
#### zincati, rpm-ostree and automatic updates
|
||||
|
||||
The zincati service drives rpm-ostreed with automatic updates.
|
||||
Check which version of Fedora CoreOS is currently running on the VM, and check if Zincati has found an update.
|
||||
|
||||
```
|
||||
$ ssh core@192.168.122.237
|
||||
$ rpm-ostree status
|
||||
State: idle
|
||||
Deployments:
|
||||
● ostree://fedora:fedora/x86_64/coreos/stable
|
||||
Version: 32.20200907.3.0 (2020-09-23T08:16:31Z)
|
||||
Commit: b53de8b03134c5e6b683b5ea471888e9e1b193781794f01b9ed5865b57f35d57
|
||||
GPGSignature: Valid signature by 97A1AE57C3A2372CCA3A4ABA6C13026D12C944D0
|
||||
$ systemctl status zincati
|
||||
● zincati.service - Zincati Update Agent
|
||||
Loaded: loaded (/usr/lib/systemd/system/zincati.service; enabled; vendor preset: enabled)
|
||||
Active: active (running) since Wed 2020-10-28 13:36:23 UTC; 7s ago
|
||||
…
|
||||
Oct 28 13:36:24 cosa-devsh zincati[1013]: [INFO ] initialization complete, auto-updates logic enabled
|
||||
Oct 28 13:36:25 cosa-devsh zincati[1013]: [INFO ] target release '32.20201004.3.0' selected, proceeding to stage it
|
||||
|
||||
... zincati reboot ...
|
||||
```
|
||||
|
||||
After the restart, let’s remote login once more to check the new version of Fedora CoreOS.
|
||||
|
||||
```
|
||||
$ ssh core@192.168.122.237
|
||||
$ rpm-ostree status
|
||||
State: idle
|
||||
Deployments:
|
||||
● ostree://fedora:fedora/x86_64/coreos/stable
|
||||
Version: 32.20201004.3.0 (2020-10-19T17:12:33Z)
|
||||
Commit: 64bb377ae7e6949c26cfe819f3f0bd517596d461e437f2f6e9f1f3c24376fd30
|
||||
GPGSignature: Valid signature by 97A1AE57C3A2372CCA3A4ABA6C13026D12C944D0
|
||||
ostree://fedora:fedora/x86_64/coreos/stable
|
||||
Version: 32.20200907.3.0 (2020-09-23T08:16:31Z)
|
||||
Commit: b53de8b03134c5e6b683b5ea471888e9e1b193781794f01b9ed5865b57f35d57
|
||||
GPGSignature: Valid signature by 97A1AE57C3A2372CCA3A4ABA6C13026D12C944D0
|
||||
```
|
||||
|
||||
_rpm-ostree status_ now shows 2 versions of Fedora CoreOS, the one that came in the QEMU image, and the latest one received from the update. By having these 2 versions available, it is possible to rollback to the previous version using the _rpm-ostree rollback_ command.
|
||||
|
||||
Finally, you can make sure that the hello service is still running and serving content.
|
||||
|
||||
```
|
||||
$ curl http://192.168.122.237:8080
|
||||
Hello from Fedora CoreOS!
|
||||
```
|
||||
|
||||
More information: [Fedora CoreOS updates][9]
|
||||
|
||||
#### Deleting the Virtual Machine
|
||||
|
||||
To clean up afterwards, the following commands will delete the VM and associated storage.
|
||||
|
||||
```
|
||||
$ virsh destroy fcos
|
||||
$ virsh undefine --remove-all-storage fcos
|
||||
```
|
||||
|
||||
### Conclusion
|
||||
|
||||
Fedora CoreOS provides a solid and secure operating system tailored to run applications in containers. It excels in a DevOps environment which encourages the hosts to be provisioned using declarative configuration files. Automatic updates and the ability to rollback to a previous version of the OS, bring a peace of mind during the operation of a service.
|
||||
|
||||
Learn more about Fedora CoreOS by following the tutorials available in the project’s [documentation][10].
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/getting-started-with-fedora-coreos/
|
||||
|
||||
作者:[Clément Verna][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/cverna/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2020/11/fcos-gettingstarted-1-816x345.jpg
|
||||
[2]: https://unsplash.com/@pawel_czerwinski?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[3]: https://unsplash.com/s/photos/core?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[4]: https://getfedora.org/coreos/
|
||||
[5]: https://github.com/coreos/coreos-installer/releases
|
||||
[6]: https://github.com/coreos/ignition
|
||||
[7]: https://podman.io/
|
||||
[8]: https://github.com/coreos/fcct/releases
|
||||
[9]: https://docs.fedoraproject.org/en-US/fedora-coreos/auto-updates/
|
||||
[10]: https://docs.fedoraproject.org/en-US/fedora-coreos/tutorials/
|
||||
@@ -0,0 +1,146 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to choose a wireless protocol for home automation)
|
||||
[#]: via: (https://opensource.com/article/20/11/wireless-protocol-home-automation)
|
||||
[#]: author: (Steve Ovens https://opensource.com/users/stratusss)
|
||||
|
||||
How to choose a wireless protocol for home automation
|
||||
======
|
||||
Which of the three dominant wireless protocols used in home
|
||||
automation—WiFi, Z-Wave, and Zigbee—is right for you? Consider the
|
||||
options in part three of this series.
|
||||
![Digital images of a computer desktop][1]
|
||||
|
||||
In the second article in this series, I talked about [local control vs. cloud connectivity][2] and some things to consider for your home automation setup.
|
||||
|
||||
In this third article, I will discuss the underlying technology for connecting devices to [Home Assistant][3], including the dominant protocols that smart devices use to communicate and some things to think about before purchasing smart devices.
|
||||
|
||||
### Connecting devices to Home Assistant
|
||||
|
||||
Many different devices work with Home Assistant. Some connect through a cloud service, and others work by communicating with a central unit, such as a [SmartThings Hub][4], that Home Assistant communicates with. And still others have a facility to communicate over your local network.
|
||||
|
||||
For a device to be truly useful, one of its key features must be wireless connectivity. There are currently three dominant wireless protocols that smart devices use: WiFi, Z-Wave, and Zigbee. I'll do a quick breakdown of each including their pros and cons.
|
||||
|
||||
**A note about wireless spectra:** Spectra are measured in hertz (Hz). A gigahertz (GHz) is 1 billion Hz. In general, the larger the number of Hz, the more data can be transmitted and the faster the connection. However, higher frequencies are more susceptible to interference and do not travel very well through solid objects. Lower frequencies can travel further and pass through solid objects more readily, but the trade-off is they cannot send much data.
|
||||
|
||||
### WiFi
|
||||
|
||||
[WiFi][5] is the most widely known of the three standards. These devices are the easiest to get up and running if you are starting from scratch. This is because almost everyone interested in home automation already has a WiFi router or an access point. In fact, in most countries in the western world, WiFi is considered almost on the same level as running water; if you go to a hotel, you expect a clean, temperature-controlled room with a WiFi password provided at check-in.
|
||||
|
||||
Therefore, Internet of Things (IoT) devices that use the WiFi protocol require no additional hardware to get started. Plug in the new device, launch a vendor-provided application or a web browser, enter your credentials, and you're done.
|
||||
|
||||
It's important to note that almost all moderate- to low-priced IoT devices use the 2.4GHz wireless spectrum. Why does this matter? Well, 2.4GHz has been around so long that virtually all devices—from cordless phones to smart bulbs—use this spectrum. In most countries, there are generally only about a dozen channels that off-the-shelf devices can broadcast and receive on. Like overloading a cell tower when too many users attempt to make phone calls during an emergency, channels can become overcrowded and susceptible to outside interference.
|
||||
|
||||
While well-behaving smart devices use little-to-no bandwidth, if they struggle to send/receive messages due to overcrowding on the spectrum, your automation will have mixed results. A WiFi access point can only communicate with one client at a time. That means the more devices you have on WiFi, the greater the chance that someone on the network will have to wait their turn to communicate.
|
||||
|
||||
**Pros:**
|
||||
|
||||
* Ubiquitous
|
||||
* Tend to be inexpensive
|
||||
* Easy to set up
|
||||
* Easy to extend the range
|
||||
* Uses existing network
|
||||
* Requires no hub
|
||||
|
||||
|
||||
|
||||
**Cons:**
|
||||
|
||||
* Can suffer from interference from neighboring devices or adjacent networks
|
||||
* Uses the most populated 2.4GHz spectrum
|
||||
* Your router limits the number of devices
|
||||
* Uses more power, which means less or no battery-powered devices
|
||||
* Has the potential to impact latency-sensitive activities like gaming over WiFi
|
||||
* Most off-the-shelf products require an internet connection
|
||||
|
||||
|
||||
|
||||
### Z-Wave
|
||||
|
||||
[Z-Wave][6] is a closed wireless protocol controlled and maintained by a company named Zensys. Because it is controlled by a single entity, all devices are guaranteed to work together. There is one standard and one implementation. This means that you never have to worry about which device you buy from which manufacturer; they will always work.
|
||||
|
||||
Z-Wave operates in the 0.9GHz spectrum, which means it has the largest range of the popular protocols. A central hub is required to coordinate all the devices on a Z-Wave ecosystem. Z-Wave operates on a [mesh network][7] topology, which means that every device acts as a potential repeater for other devices. In theory, this allows a much greater coverage area. Z-Wave limits the number of "hops" to 4. That means that, in order for a signal to get from a device to a hub, it can only travel through four devices. This could be a positive or a negative, depending on your perspective.
|
||||
|
||||
On the one hand, it reduces the ecosystem's maximum latency by preventing packets from traveling through a significant number of devices before reaching the destination. The more devices a signal must go through, the longer it can take for devices to become responsive.
|
||||
|
||||
On the other hand, it means that you need to be more strategic about providing a good path from your network's extremities back to the hub. Remember, the lower frequency that enables greater distance also limits the speed and amount of data that can be transferred. This is currently not an issue, but no one knows what size messages future smart devices will want to send.
|
||||
|
||||
**Pros:**
|
||||
|
||||
* Z-Wave compatibility guaranteed
|
||||
* Form mesh network
|
||||
* Low powered and can be battery powered
|
||||
* Mesh networks become more reliable with more devices
|
||||
* Uses 0.9GHz and can transmit up to 100 meters
|
||||
* Least likely of the three to have signal interference from solid objects or external sources
|
||||
|
||||
|
||||
|
||||
**Cons:**
|
||||
|
||||
* Closed protocol
|
||||
* Costs the most
|
||||
* Maximum of four hops in the mesh
|
||||
* Can support up to 230 devices per network
|
||||
* Uses 0.9GHz, which is the slowest of all protocols
|
||||
|
||||
|
||||
|
||||
### Zigbee
|
||||
|
||||
Unlike Z-Wave, [Zigbee][8] is an open standard. This can be a pro or a con, depending on your perspective. Because it is an open standard, manufacturers are free to alter the implementation to suit their products. To borrow an analogy from one of my favorite YouTube channels, [The Hook Up][9], Zigbee is like going through a restaurant drive-through. Having the same standard means you will always be able to speak to the restaurant and they will be able to hear you. However, if you speak a different language than the drive-through employee, you won't be able to understand each other. Both of you can speak and hear each other, but the meaning will be lost.
|
||||
|
||||
Similarly, the Zigbee standard allows all devices on a Zigbee network to "hear" each other, but different implementations mean they may not "understand" each other. Fortunately, more often than not, your Zigbee devices should be able to interoperate. However, there is a non-trivial chance that your devices will not be able to understand each other. When this happens, you may end up with multiple networks that could interfere with each other.
|
||||
|
||||
Like Z-Wave, Zigbee employs a mesh network topology but has no limit to the number of "hops" devices can use to communicate with the hub. This, combined with some tweaks to the standard, means that Zigbee theoretically can support more than 65,000 devices on a single network.
|
||||
|
||||
**Pros:**
|
||||
|
||||
* Open standard
|
||||
* Form mesh network
|
||||
* Low-powered and can be battery powered
|
||||
* Can support over 65,000 devices
|
||||
* Can communicate faster than Z-Wave
|
||||
|
||||
|
||||
|
||||
**Cons:**
|
||||
|
||||
* No guaranteed compatibility
|
||||
* Can form separate mesh networks that interfere with each other
|
||||
* Uses the oversaturated 2.4GHz spectrum
|
||||
* Transmits only 10 to 30 meters
|
||||
|
||||
|
||||
|
||||
### Pick your protocol
|
||||
|
||||
Perhaps you already have some smart devices. Or maybe you are just starting to investigate your options. There is a lot to consider when you're buying devices. Rather than focusing on the lights, sensors, smart plugs, thermometers, and the like, it's perhaps more important to know which protocol (WiFi, Z-Wave, or Zigbee) you want to use.
|
||||
|
||||
Whew! I am finally done laying home automation groundwork. In the next article, I will show you how to start the initial installation and configuration of a Home Assistant virtual machine.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/wireless-protocol-home-automation
|
||||
|
||||
作者:[Steve Ovens][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/stratusss
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/computer_browser_web_desktop.png?itok=Bw8ykZMA (Digital images of a computer desktop)
|
||||
[2]: https://opensource.com/article/20/11/cloud-vs-local-home-automation
|
||||
[3]: https://opensource.com/article/20/11/home-assistant
|
||||
[4]: https://www.smartthings.com/
|
||||
[5]: https://en.wikipedia.org/wiki/Wi-Fi
|
||||
[6]: https://www.z-wave.com/
|
||||
[7]: https://en.wikipedia.org/wiki/Mesh_networking
|
||||
[8]: https://zigbeealliance.org/
|
||||
[9]: https://www.youtube.com/channel/UC2gyzKcHbYfqoXA5xbyGXtQ
|
||||
@@ -0,0 +1,80 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to Go Full Dark Mode With LibreOffice)
|
||||
[#]: via: (https://itsfoss.com/libreoffice-dark-mode/)
|
||||
[#]: author: (Dimitrios Savvopoulos https://itsfoss.com/author/dimitrios/)
|
||||
|
||||
How to Go Full Dark Mode With LibreOffice
|
||||
======
|
||||
|
||||
[LibreOffice][1] is a free and open-source cross-platform office productivity software. If you’re not making the most of it, the [LibreOffice Tips][2] article is a must-read.
|
||||
|
||||
Dark theme is getting popular even among non-programmers. It is less stressing on the eyes specially for extended use of the screen. Some people believe that it makes the texts looks crisp and clear and that helps improve their productivity.
|
||||
|
||||
Some Linux distributions like [Ubuntu come with dark mode][3] these days giving your systems a darker tint. When you turn on the dark mode, some applications will automatically switch to dark mode.
|
||||
|
||||
LibreOffice also does that except the main area where you write:
|
||||
|
||||
![LibreOffice semi dark mode matching with the system theme][4]
|
||||
|
||||
You can change that. If you want to go complete dark mode with LibreOffice, you just have to change a few settings. Let me show you how to do that.
|
||||
|
||||
### How to enable complete dark mode in LibreOffice
|
||||
|
||||
As I mentioned earlier, you need to enable a system-wide dark mode first. This will ensure that the window color (or the title bar) blends well with the in-app dark color.
|
||||
|
||||
Next, open _**any**_ LibreOffice tool from the suite such as **Writer**. Then from the menu, click **Tools -> Options** **->** **Application Colors** and select **Document background & Application** background as **Black** or **Automatic** (whichever works for you).
|
||||
|
||||
![][5]
|
||||
|
||||
In case the icons are not in dark colour, you can change them from menu (as shown in the image below), **Tools -> Options** **->** **View** and my personal choice on MX Linux, is the [Yaru][6] icon style from Ubuntu (if you have a dark version of the icon pack, select that).
|
||||
|
||||
![][7]
|
||||
|
||||
Of course, you can also try some other [icon themes][8] available for Linux distros.
|
||||
|
||||
The end result should look like this:
|
||||
|
||||
![][9]
|
||||
|
||||
#### Additional tip for LibreOffice flatpak package
|
||||
|
||||
If you’re using the [Flatpak package][10] of LibreOffice suite, the header area (or the menu area) of LibreOffice may look white. In that case, you can try navigating to **Tools-> Options-> Personalization** and then select the “**Grey theme**” as shown in the screenshot below.
|
||||
|
||||
![][11]
|
||||
|
||||
It isn’t completely black but it should make things look better. Hope that helps you switch to a dark theme LibreOffice experience!
|
||||
|
||||
#### Conclusion
|
||||
|
||||
Dark themes have slowly started to dominate our desktops, giving a modern taste and reducing the eye strain, especially in low light conditions.
|
||||
|
||||
LibreOffice gives you the freedom to switch your working environment to a fully dark theme or to keep light themed elements. In fact, you get a decent amount of customization options to tweak what you prefer. Have you switched to a dark theme on LibreOffice? Which color combination is your preferred? Let us know in the comments below!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/libreoffice-dark-mode/
|
||||
|
||||
作者:[Dimitrios Savvopoulos][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/dimitrios/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.libreoffice.org
|
||||
[2]: https://itsfoss.com/libreoffice-tips/
|
||||
[3]: https://itsfoss.com/dark-mode-ubuntu/
|
||||
[4]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/libreOffice-dark-mode.png?resize=799%2C450&ssl=1
|
||||
[5]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/11/1-libreoffice-application-colours.png?resize=800%2C551&ssl=1
|
||||
[6]: https://extensions.libreoffice.org/en/extensions/show/yaru-icon-theme
|
||||
[7]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/11/2-libreoffice-iconstyle-1.png?resize=800%2C531&ssl=1
|
||||
[8]: https://itsfoss.com/best-icon-themes-ubuntu-16-04/
|
||||
[9]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/3-libreoffice-dark.png?resize=800%2C612&ssl=1
|
||||
[10]: https://itsfoss.com/what-is-flatpak/
|
||||
[11]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/11/libre-office-personalization.png?resize=800%2C636&ssl=1
|
||||
@@ -0,0 +1,75 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (scanimage: scan from the command line!)
|
||||
[#]: via: (https://jvns.ca/blog/2020/07/11/scanimage--scan-from-the-command-line/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
scanimage:从命令行扫描!
|
||||
======
|
||||
|
||||
这又是一篇关于我很喜欢的一个命令行工具的文章。
|
||||
|
||||
昨晚,出于官僚原因,我需要扫描一些文档。我以前从来没有在 Linux 上使用过扫描仪,我担心会花上好几个小时才弄明白。我从使用 `gscan2pdf` 开始,但在用户界面上遇到了麻烦。我想同时扫描两面(我知道我们的扫描仪支持),但无法使它工作。
|
||||
|
||||
### 遇到 scanimage!
|
||||
|
||||
`scanimage` 是一个命令行工具,在 `sane-utils` Debian 软件包中。我想所有的 Linux 扫描工具都使用 `sane` (”scanner access now easy“) 库,所以我猜测它和其他扫描软件有类似的能力。在这里,我不需要 OCR,所以我们不打算谈论 OCR。
|
||||
|
||||
### 用 `scanimage -L` 得到你的扫描仪的名字
|
||||
|
||||
`scanimage -L` 列出了你所有的扫描设备。
|
||||
|
||||
一开始我不能让它工作,我有点沮丧,但事实证明,我把扫描仪连接到了我的电脑上,但没有插上电源。
|
||||
|
||||
插上后,它马上就能工作了。显然我们的扫描仪叫 `fujitsu:ScanSnap S1500:2314`。万岁!
|
||||
|
||||
### 用 `--help` 列出你的扫描仪选项
|
||||
|
||||
显然每个扫描仪有不同的选项(有道理!),所以我运行这个命令来获取我的扫描仪的选项:
|
||||
|
||||
```
|
||||
scanimage --help -d 'fujitsu:ScanSnap S1500:2314'
|
||||
```
|
||||
|
||||
我发现我的扫描仪支持 `--source` 选项(我可以用它来启用双面扫描)和 `--resolution` 选项(我把它改为 150,以减少文件大小,使扫描更快)。
|
||||
|
||||
### scanimage 不支持输出 PDF 文件(但你可以写一个小脚本)
|
||||
|
||||
唯一的缺点是:我想要一个 PDF 格式的扫描文件,而 scanimage 似乎不支持 PDF 输出。
|
||||
|
||||
所以我写了这个 5 行的 shell 脚本在一个临时文件夹中扫描一堆 PNG 文件,并将结果保存到 PDF 中。
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
DIR=`mktemp -d`
|
||||
CUR=$PWD
|
||||
cd $DIR
|
||||
scanimage -b --format png -d 'fujitsu:ScanSnap S1500:2314' --source 'ADF Front' --resolution 150
|
||||
convert *.png $CUR/$1
|
||||
```
|
||||
|
||||
我像这样运行脚本:`scan-single-sided output-file-to-save.pdf`
|
||||
|
||||
你可能需要为你的扫描仪设置不同的 `-d` 和 `-source`。
|
||||
|
||||
### 这真是太简单了!
|
||||
|
||||
我一直以为在 Linux 上使用打印机/扫描仪是一个噩梦,我真的很惊讶 `scanimage` 可以工作。我可以直接运行我的脚本 `scan-single-sided receipts.pdf`,它将扫描文档并将其保存到 `receipts.pdf`!
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2020/07/11/scanimage--scan-from-the-command-line/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
@@ -1,198 +0,0 @@
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "xiao-song-123"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
[#]: subject: "5 steps to learn any programming language"
|
||||
[#]: via: "https://opensource.com/article/20/10/learn-any-programming-language"
|
||||
[#]: author: "Seth Kenlon https://opensource.com/users/seth"
|
||||
|
||||
学习任何编程语言的 5 个步骤
|
||||
======
|
||||
只需一点编程经验,您就可以在几天内(有时更少)学习一种新语言。
|
||||
![Learning to program][1]
|
||||
|
||||
有些人喜欢学习新的编程语言,也有一些人连学习一种都是可望不可即的事情。在本文中,我将向您展示如何像程序员一样思考,以便您可以自信地学习所需的任何编程语言。
|
||||
|
||||
事实上,一旦您学会了如何编程,您使用的语言就不再是一个障碍,而更像是一种形式。这只是教育家们倡导 [让孩子尽早学习编程][2] 的众多原因之一。不管他们的入门语言有多简单,这种编程的逻辑和儿童(或成人学习者)以后可能遇到的其他东西的逻辑有着相同之处。
|
||||
|
||||
只需有一点编程经验(您可以从 Opensource.com 上的任何一篇介绍性文章中获得),您就可以在几天内(有时更短)学习任何编程语言。这并不是魔法,现在您也必须要为此付出一些努力。诚然,学习一种语言每个的可用库,或者学习打包代码以及进行交付的细微差别,需要的时间远远不止几天。但是,就入门来说,比您想像中的要容易许多,剩下的则要通过不断练习来完成。
|
||||
|
||||
当有经验的程序员静下心来学习一门新的编程语言时,他们会寻找五样东西。只要您知道了这五件事,您就可以开始编码了。
|
||||
|
||||
### 1\. 语法
|
||||
|
||||
![Syntax][3]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][4])
|
||||
|
||||
语言的语法描述了代码的结构。这包括如何逐行编写代码,以及用于构造代码语句的实际单词。
|
||||
|
||||
例如,[Python][5] 因使用缩进来指示一个代码块在哪里结束以及另一代码块在哪里开始而闻名:
|
||||
|
||||
|
||||
```
|
||||
while j < rows:
|
||||
while k < columns:
|
||||
tile = Tile(k * w)
|
||||
board.add(tile)
|
||||
k += 1
|
||||
j += 1
|
||||
k = 0
|
||||
```
|
||||
|
||||
[Lua][6] 只是使用关键字 `end`:
|
||||
|
||||
|
||||
```
|
||||
for i,obj in ipairs(hit) do
|
||||
if obj.moving == 1 then
|
||||
obj.x,obj.y = v.mouse.getPosition()
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
[Java][7], [C][8], C++, 和类似的编程语言使用花括号:
|
||||
|
||||
|
||||
```
|
||||
while (std::getline(e,r)) {
|
||||
wc++;
|
||||
}
|
||||
```
|
||||
|
||||
编程语言的语法还包括包括库、设置变量和终止行等内容。通过练习,您将学会在阅读示例代码时下意识地识别语法需求(和惯例)。
|
||||
|
||||
#### 实践
|
||||
|
||||
当学习一门新的编程语言时,要努力理解它的语法。您不需要去记住它,只需要知道如果忘记了以后去哪里看。使用好的 [IDE][9] 也很有帮助,因为很多 IDE 在出现语法错误时会提醒您。
|
||||
|
||||
### 2\. 内置函数和条件
|
||||
|
||||
![built-in words][10]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][4])
|
||||
|
||||
就像自然语言一样,编程语言可以识别的合法单词是有限的。这个词汇表可以使用其他库进行扩展,但是核心语言知道一组特定的关键字。大多数语言并没有您想的那么多关键字。即使在像 C 语言这样非常低级的语言中,也只有 32 个关键字,比如 `for`, `do`, `while`, `int`, `float`, `char`, `break` 等等。
|
||||
|
||||
了解了这些关键字,您就可以编写基本的表达式,也就是构建程序的代码块。许多内置的关键字能帮助您构建条件语句,这些条件语句影响整个程序的流程。例如,如果您想编写一个允许单击和拖动图标的程序,那么您的代码就必须检测用户的鼠标指针何时位于图标上。只有当鼠标光标位于图标外部边缘相同的坐标时,才执行导致使鼠标抓取图标的代码。这是一个经典的 if / then 语句,不同的语言可以用不同的方式表达。
|
||||
|
||||
Python 使用 `if`, `elif `和 `else` 的组合来实现条件语句,但是并不显式的关闭语句:
|
||||
|
||||
|
||||
```
|
||||
if var == 1:
|
||||
# action
|
||||
elif var == 2:
|
||||
# some action
|
||||
else:
|
||||
# some other action
|
||||
```
|
||||
|
||||
[Bash][11] 使用 `if`, `elif`, `else`, 并且使用 `fi` 来结束语句:
|
||||
|
||||
|
||||
```
|
||||
if [ "$var" = "foo" ]; then
|
||||
# action
|
||||
elif [ "$var" = "bar" ]; then
|
||||
# some action
|
||||
else
|
||||
# some other action
|
||||
fi
|
||||
```
|
||||
|
||||
然而 C 和 Java, 使用 `if`, `else` 和 `else if`, 用花括号把它们括起来:
|
||||
|
||||
|
||||
```
|
||||
if (boolean) {
|
||||
// action
|
||||
} else if (boolean) {
|
||||
// some action
|
||||
} else {
|
||||
// some other action
|
||||
}
|
||||
```
|
||||
|
||||
各种编程语言虽然在关键字的选择和语法上有细微的变化,但基本是相同的。学习如何在编程语言中定义条件语句,包括 `if/then`, `do...while` 和 `case` 语句。
|
||||
|
||||
#### 实践
|
||||
|
||||
要去熟悉编程语言能够理解的关键字集。在实践中,您的代码将不仅仅包含一种语言的关键字。可以肯定的是,有许多库中包含一些简单的函数,它们可以帮助您完成诸如将输出打印到屏幕或显示窗口之类的操作。然而,驱动这些库的逻辑始于编程语言的内置关键字。
|
||||
|
||||
### 3\. 数据类型
|
||||
|
||||
![Data types][12]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][4])
|
||||
|
||||
代码是用来处理数据的,因此您必须学习编程语言如何识别不同类型的数据。所有编程语言都能理解整数,大多数的语言能理解小数和单个字符 (a, b, c 等等)。它们通常被表示为 `int` , `float`,`double` 和 `char`, 当然,语言的内置词汇表会告诉您如何引用这些实体。
|
||||
|
||||
有时候,在编程语言中内置了一些额外的数据类型,也有时是通过引用库来启用复杂的数据类型。例如,Python 可以识别关键字为 `str` 的字符串,但是 C 语言的代码中必须包含 `string.h` 头文件才能实现字符串特性。
|
||||
|
||||
#### 实践
|
||||
|
||||
库可以为您的代码解锁所有类型的数据,但是学习编程语言中包含的基本数据类型是一个明智的起点。
|
||||
|
||||
### 4\. 运算符和解析器
|
||||
|
||||
![Operators][13]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][4])
|
||||
|
||||
一旦您理解了编程语言可处理的数据类型,就可以学习如何分析这些数据了。幸运的是,数学这门学科是相当稳定的,所以算数运算符在许多语言中通常是相同的(或至少非常相似)。例如,两个整数相加通常用 `+` 符号完成,而测试一个整数是否大于另一个整数通常用 `>` 符号完成。测试是否相等通常使用 `==` 来完成(是的,是两个等号,因为通常一个等号用来赋值)。
|
||||
|
||||
当然也有一些例外,比如像 Lisp 和 Bash 语言算数运算符就不是如此,但与其他语言一样,这只是一个音译的问题。一旦您了解了表达方式有何不同,很快就可以适应它。快速回顾一门编程语言的算数运算符通常足以让您了解算数操作是如何完成的。
|
||||
|
||||
您还需要知道如何比较和操作非数值数据,比如字符和字符串。这些通常是通过编程语言的核心库来进行的的。例如,Python 提供了 `split()` 方法,而 C 语言需要引入头文件 `string.h` 来提供 `strtok()` 函数。
|
||||
|
||||
#### 实践
|
||||
|
||||
了解用于处理基本数据类型的基本函数和关键字,并寻找可帮助您完成复杂操作的核心库。
|
||||
|
||||
### 5\. 函数
|
||||
|
||||
![Class][14]
|
||||
|
||||
(Seth Kenlon, [CC BY-SA 4.0][4])
|
||||
|
||||
代码不只是计算机的待办清单。通常情况下,在编写代码时您往往希望向计算机提供一组理论条件和一组操作指令,当满足每个条件时计算机就会采取这些操作。尽管使用条件语句以及数学和逻辑运算符进行流控制可以做很多事情,但是引入了函数和类之后,代码会变得更加高效,因为它们使您可以定义子程序。 例如,如果应用程序需要非常频繁地确认一个对话框,那么将其作为类的实例编写一次要比每次需要它时重新编写实现起来要容易得多。
|
||||
|
||||
您需要学习如何在编程语言中定义类和函数。更准确地说,您首先需要了解编程语言中是否支持类和函数。大多数现代语言都支持函数,但是类是面向对象的编程语言中所特有的。
|
||||
|
||||
#### 实践
|
||||
|
||||
学习语言中可用的结构,这些结构可以帮助您高效地编写和使用代码。
|
||||
|
||||
### 您可以学到任何东西
|
||||
|
||||
学习编程语言,就其本身而言,是一种编码过程中的子程序。一旦理解了代码如何工作,您所使用的语言就只是一种传递逻辑的媒介。学习一门新语言的过程几乎都是一样的:通过简单的练习来学习语法,通过学习词汇来积累进行复杂动作的能力,然后练习、练习、再练习。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/10/learn-any-programming-language
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[xiao-song-123](https://github.com/xiao-song-123)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/learn-programming-code-keyboard.png?itok=xaLyptT4 "Learning to program"
|
||||
[2]: https://opensource.com/article/20/9/scratch
|
||||
[3]: https://opensource.com/sites/default/files/uploads/syntax_0.png "Syntax"
|
||||
[4]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[5]: https://opensource.com/downloads/cheat-sheet-python-37-beginners
|
||||
[6]: https://opensource.com/article/20/2/lua-cheat-sheet
|
||||
[7]: https://opensource.com/downloads/java-cheat-sheet
|
||||
[8]: https://opensource.com/downloads/c-programming-cheat-sheet
|
||||
[9]: https://opensource.com/resources/what-ide
|
||||
[10]: https://opensource.com/sites/default/files/uploads/builtin.png "built-in words"
|
||||
[11]: https://opensource.com/downloads/bash-cheat-sheet
|
||||
[12]: https://opensource.com/sites/default/files/uploads/type.png "Data types"
|
||||
[13]: https://opensource.com/sites/default/files/uploads/operator.png "Operators"
|
||||
[14]: https://opensource.com/sites/default/files/uploads/class.png "Class"
|
||||
@@ -0,0 +1,93 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to rebase to Fedora 33 on Silverblue)
|
||||
[#]: via: (https://fedoramagazine.org/how-to-rebase-to-fedora-33-on-silverblue/)
|
||||
[#]: author: (Michal Konečný https://fedoramagazine.org/author/zlopez/)
|
||||
|
||||
如何在 Silverblue 上变基到 Fedora 33?
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
Silverblue 是[一个建立在 Fedora 上的桌面操作系统][2]。它非常适合日常使用、开发和基于容器的工作流程。它提供了[众多的优势][3],例如在出现任何问题时能够回滚。如果你想在你的 Silverblue 系统上更新到 Fedora 33,这篇文章会告诉你如何做。它不仅告诉你该怎么做,还告诉你如果发生了不可预见的事情时该如何回退。
|
||||
|
||||
在实际做变基到 Fedora 33 之前,你应该应用任何挂起的更新。在终端中输入以下内容:
|
||||
|
||||
```
|
||||
$ rpm-ostree update
|
||||
```
|
||||
|
||||
或通过 GNOME 软件中心安装更新并重启。
|
||||
|
||||
### 使用 GNOME 软件中心变基
|
||||
|
||||
GNOME 软件中心会在更新界面显示有新版本的 Fedora 可用。
|
||||
|
||||
![Fedora 33 is available][4]
|
||||
|
||||
首先你需要做的是下载新镜像,点击 _Download_ 按钮。这将需要一些时间,完成后你会看到更新已经准备好安装了。
|
||||
|
||||
![Fedora 33 is ready for installation][5]
|
||||
|
||||
点击 _Install_ 按钮。这一步只需要几分钟,然后会提示你重启电脑。
|
||||
|
||||
![Restart is needed to rebase to Fedora 33 Silverblue][6]
|
||||
|
||||
点击 _Restart_ 按钮就可以了。重启后,你将进入新的 Fedora 33 版本。很简单,不是吗?
|
||||
|
||||
### 使用终端变基
|
||||
|
||||
如果你喜欢在终端上做所有的事情,那么接下来的指南就适合你。
|
||||
|
||||
使用终端变基到 Fedora 33 很简单。首先,检查 33 版本分支是否可用:
|
||||
|
||||
```
|
||||
$ ostree remote refs fedora
|
||||
```
|
||||
|
||||
你应该在输出中看到以下内容:
|
||||
|
||||
```
|
||||
fedora:fedora/33/x86_64/silverblue
|
||||
```
|
||||
|
||||
接下来,将你的系统变基到 Fedora 33 分支。
|
||||
|
||||
```
|
||||
$ rpm-ostree rebase fedora:fedora/33/x86_64/silverblue
|
||||
```
|
||||
|
||||
最后要做的是重启你的电脑并启动到 Fedora 33。
|
||||
|
||||
### 如何回滚
|
||||
|
||||
如果有什么不好的事情发生。例如,如果你无法启动到 Fedora 33,那很容易回滚回去。在启动时选择 GRUB 菜单中的前一个条目,你的系统就会以切换到 Fedora 33 之前的状态启动。要使这一改变永久化,请使用以下命令:
|
||||
|
||||
```
|
||||
$ rpm-ostree rollback
|
||||
```
|
||||
|
||||
就是这样了。现在你知道如何将 Silverblue 变基为 Fedora 33 并回滚了。那为什么不在今天就做呢?
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/how-to-rebase-to-fedora-33-on-silverblue/
|
||||
|
||||
作者:[Michal Konečný][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/zlopez/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2020/02/fedora-silverblue-logo.png
|
||||
[2]: https://docs.fedoraproject.org/en-US/fedora-silverblue/
|
||||
[3]: https://fedoramagazine.org/give-fedora-silverblue-a-test-drive/
|
||||
[4]: https://fedoramagazine.org/wp-content/uploads/2020/10/Screenshot-from-2020-10-29-12-53-37-1024x725.png
|
||||
[5]: https://fedoramagazine.org/wp-content/uploads/2020/10/Screenshot-from-2020-10-29-13-00-15-1024x722.png
|
||||
[6]: https://fedoramagazine.org/wp-content/uploads/2020/10/Screenshot-from-2020-10-29-13-01-32-1024x727.png
|
||||
@@ -0,0 +1,95 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Day 1: a confusing Rails error message)
|
||||
[#]: via: (https://jvns.ca/blog/2020/11/09/day-1--a-little-rails-/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
Rails 之旅第 1 天:一个令人困惑的 Rails 错误信息
|
||||
======
|
||||
|
||||
今天,我开始了一个 Recurse Center 的批次学习!我认识了一些人,并开始了一个小小的有趣的 Rails 项目。我想我今天不会谈太多关于这个项目的实际内容,但这里有一些关于 Rails 一天的快速笔记。
|
||||
|
||||
### 一些关于开始的笔记
|
||||
|
||||
在建立 Rails 项目的过程中,我学到的主要是:
|
||||
|
||||
1. 它默认使用 sqlite,你必须告诉它使用 Postgres。
|
||||
2. Rails 默认包含了大量的东西,你可以禁用。
|
||||
|
||||
我安装并 `rm -rf` Rails 大概 7 次后才满意,最后用了这个咒语:
|
||||
|
||||
```
|
||||
rails new . -d postgresql --skip-sprockets --skip-javascript
|
||||
```
|
||||
|
||||
主要是因为我想用 Postgres 而不是 sqlite,而且跳过 sprockets 和 javascript 似乎能让安装 Rails 的速度更快,而且我想如果我决定要它们的话,我可以在以后再安装。
|
||||
|
||||
### 官方的 Rails 指南真的很不错
|
||||
|
||||
我在创建我的 Rails 入门应用时主要参考了 2 个资源:
|
||||
|
||||
* DHH 在 2005 年的 Rails 原版演讲 <https://www.youtube.com/watch?v=Gzj723LkRJY>(这次我没有看,但上次我花了一天时间学习 Rails 时看了,我发现它很有启发和帮助)。
|
||||
* 官方的 Rails 入门指南,似乎非常简短明了 <https://guides.rubyonrails.org/v5.0/getting_started.html>。
|
||||
|
||||
### 一个神秘的错误信息:`undefined method 'user'`
|
||||
|
||||
我喜欢 bug,所以今天我遇到了一个奇怪的 Rails 错误! 我有一些看起来像这样的代码:
|
||||
|
||||
```
|
||||
@user = User.new(user_params)
|
||||
@user.save
|
||||
```
|
||||
|
||||
很简单吧?但当这段代码运行时,我得到了这个令人费解的错误信息:
|
||||
|
||||
```
|
||||
undefined method `user' for #<User:0x00007fb6f4012ab8> Did you mean? super
|
||||
```
|
||||
|
||||
我对这里发生的事情感到**超级**困惑,因为我没有调用一个叫做 `user` 的方法。我调用的是 `.save`。什么嘛?!我对此感到困惑和沮丧,大概呆了 20 分钟,最后我看了看我的 `User` 模型,发现了这段代码:
|
||||
|
||||
```
|
||||
class User < ApplicationRecord
|
||||
has_secure_password
|
||||
|
||||
validates :user, presence: true, uniqueness: true
|
||||
end
|
||||
```
|
||||
|
||||
`validates :user...` *应该*是一些 Rails 魔法,验证每个 `User` 都有一个 `username`,而且用户名必须是唯一的。但我犯了一个错,我写的是 `user` 而不是 `username`。我把这个问题解决了,然后一切都正常了!万岁。
|
||||
|
||||
我仍然不明白我应该如何调试这个问题:堆栈跟踪告诉我问题出在 `@user.save` 行,根本没有提到 `validates :user` 的事情。我觉得一定有办法调试这个问题,但我不知道是什么办法。
|
||||
|
||||
我学 Rails 的目的就是想看看 Rails 的魔力在实践中是如何发挥的,所以这是个很有意思的 bug,早早的就掉坑里了。
|
||||
|
||||
### 一个简单的用户管理系统
|
||||
|
||||
我决定在我的玩具应用中加入用户。我在网上搜索了一下,发现有一个非常流行的叫做 [devise][1] 的工具可以处理用户。我发现它的 `README` 有点让人不知所措,而且我知道想要在我的玩具应用中建立一个非常简陋的用户管理系统,所以我遵循了这个名为《[Rails 5.2 中从零开始进行用户验证][2]》的指南,到目前为止,这个指南似乎还不错。Rails 似乎已经有了一大堆管理用户的内置东西,我真的很惊讶于这本指南的短小和我需要写的代码之少。
|
||||
|
||||
我在实现用户功能的时候了解到,Rails 有一个内置的神奇的会话管理系统(参见 [Rails 会话如何工作][3]。默认情况下,所有的会话数据似乎都存储在用户电脑上的 cookie 中,不过我想如果 cookie 太大了,你也可以把会话数据存储在数据库中。
|
||||
|
||||
已经有了会话管理系统,有了 cookie 和用户,却不太清楚到底发生了什么,这肯定是有点奇怪的,但也是挺好玩的!我们会看看情况如何。我们将拭目以待。
|
||||
|
||||
### 明天:更多的 Rails!
|
||||
|
||||
也许明天我可以在实现我的有趣的 rails 应用的想法上取得一些进展!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2020/11/09/day-1--a-little-rails-/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://github.com/heartcombo/devise
|
||||
[2]: https://medium.com/@wintermeyer/authentication-from-scratch-with-rails-5-2-92d8676f6836
|
||||
[3]: https://www.justinweiss.com/articles/how-rails-sessions-work/
|
||||
@@ -0,0 +1,246 @@
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "lxbwolf"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
[#]: subject: "Get started with Fossil, an alternative to Git"
|
||||
[#]: via: "https://opensource.com/article/20/11/fossil"
|
||||
[#]: author: "Klaatu https://opensource.com/users/klaatu"
|
||||
|
||||
开始学习 Fossil,Git 的一个替代品
|
||||
======
|
||||
Fossil 是一个集版本控制系统、bug 追踪、维基、论坛以及文档解决方案于一体的系统。
|
||||
![Dinosaurs on land at sunset][1]
|
||||
|
||||
每个开发者都知道,追踪代码的修改是至关重要的。有时候你会处于好奇或者教育的目的需要展示你的项目开始和进化的历史。有时候你想让其他的开发者参与到你的项目中,因此你需要一种值得信赖的能合并不同代码分支的方法。更极端一点,有时候你为了解决一个问题而修改的代码导致已有的功能不能正常使用。
|
||||
|
||||
[Fossil][2] 源码管理系统是由著名的 [SQLite][3] 数据库的作者开发的一个集版本控制系统、bug 追踪、维基、论坛以及文档解决方案于一体的系统。
|
||||
|
||||
### 安装 Fossil
|
||||
|
||||
Fossil 是一个独立的 C 程序,因此你可以从它的网站上[下载][4]后放在环境变量 [PATH][5] 中的任意位置。例如,假定 `/usr/local/bin` 已经在你的环境变量中(默认情况下是在的)
|
||||
|
||||
|
||||
```
|
||||
$ wget <https://fossil-scm.org/home/uv/fossil-linux-x64-X.Y.tar.gz>
|
||||
$ sudo tar xvf fossil-linux-x64-X.Y.tar.gz \
|
||||
\--directory /usr/local/bin
|
||||
```
|
||||
|
||||
你也可以通过包管理器从软件仓库中找到 Fossil,或者直接从源码编译。
|
||||
|
||||
### 创建一个 Fossil 仓库
|
||||
|
||||
如果你已经有一个代码项目,想用 Fossil 来追踪,那么第一步就是创建一个 Fossil 仓库:
|
||||
|
||||
|
||||
```
|
||||
$ fossil init myproject.fossil
|
||||
project-id: 010836ac6112fefb0b015702152d447c8c1d8604
|
||||
server-id: 54d837e9dc938ba1caa56d31b99c35a4c9627f44
|
||||
admin-user: klaatu (initial password is "14b605")
|
||||
```
|
||||
|
||||
创建 Fossil 仓库的过程中会返回三行信息:一个唯一的项目 ID、一个唯一的服务 ID 以及管理员 ID 和密码。项目 ID 和服务 ID 是版本数字。管理员资质表明你对这个仓库的所有权,当你把这个 Fossil 仓库作为服务器让其他用户来访问时可以使用管理员权限。
|
||||
|
||||
### Fossil 仓库工作流
|
||||
|
||||
在你使用 Fossil 仓库之前,你需要先为它的数据创建一个工作路径。你可以把这个过程类比为使用 Python 时创建一个虚拟环境或者解压一个只会用来备份的 ZIP 文件。
|
||||
|
||||
创建一个工作目录并进入:
|
||||
|
||||
|
||||
```
|
||||
$ mkdir myprojectdir
|
||||
$ cd myprojectdir
|
||||
```
|
||||
|
||||
把你的 Fossil 打开到刚刚创建的目录:
|
||||
|
||||
|
||||
```
|
||||
$ fossil open ../myproject
|
||||
project-name: <unnamed>
|
||||
repository: /home/klaatu/myprojectdir/../myproject
|
||||
local-root: /home/klaatu/myprojectdir/
|
||||
config-db: /home/klaatu/.fossil
|
||||
project-code: 010836ac6112fefb0b015702152d447c8c1d8604
|
||||
checkout: 9e6cd96dd675544c58a246520ad58cdd460d1559 2020-11-09 04:09:35 UTC
|
||||
tags: trunk
|
||||
comment: initial empty check-in (user: klaatu)
|
||||
check-ins: 1
|
||||
```
|
||||
|
||||
你可能注意到了,Fossil 在你的家目录下创建了一个名为 `.fossil` 的隐藏文件,用来追踪你的全局 Fossil 配置。这个配置不是只适用于你的一个项目的;这个文件只会在你第一次使用 Fossil 时生成。
|
||||
|
||||
#### 添加文件
|
||||
|
||||
使用 `add` 和 `commit` 子命令来向你的仓库添加文件。例如,创建一个简单的 README 文件,把它添加到仓库:
|
||||
|
||||
|
||||
```
|
||||
$ echo "My first Fossil project" > README
|
||||
$ fossil add README
|
||||
ADDED README
|
||||
$ fossil commit -m 'My first commit'
|
||||
New_Version: 2472a43acd11c93d08314e852dedfc6a476403695e44f47061607e4e90ad01aa
|
||||
```
|
||||
|
||||
#### 使用分支
|
||||
|
||||
Fossil 仓库开始时默认使用的主分支名为 `trunk`。当你想修改代码而又不影响主干代码时,你可以从 trunk 分支切走。创建新分支需要使用 `branch` 子命令,这个命令需要两个参数:一个新分支的名字,一个新分支的基分支名字。在本例中,只有一个分支 `trunk`,因此尝试创建一个名为 `dev` 的新分支:
|
||||
|
||||
|
||||
```
|
||||
$ fossil branch --help
|
||||
Usage: fossil branch new BRANCH-NAME BASIS ?OPTIONS?
|
||||
$ fossil branch new dev trunk
|
||||
New branch: cb90e9c6f23a9c98e0c3656d7e18d320fa52e666700b12b5ebbc4674a0703695
|
||||
```
|
||||
|
||||
你已经创建了一个新分支,但是你当前所在的分支仍然是 `trunk`:
|
||||
|
||||
|
||||
```
|
||||
$ fossil branch current
|
||||
trunk
|
||||
```
|
||||
|
||||
使用 `checkout` 命令切换到你的新分支 `dev`:
|
||||
|
||||
|
||||
```
|
||||
$ fossil checkout dev
|
||||
dev
|
||||
```
|
||||
|
||||
#### 合并修改
|
||||
|
||||
假设你在 `dev` 分支中添加了一个新文件,完成了测试,现在想把它合并到 `trunk`。这个过程叫做*合并*。
|
||||
|
||||
首先,切回目标分支(本例中目标分支为 `trunk`):
|
||||
|
||||
|
||||
```
|
||||
$ fossil checkout trunk
|
||||
trunk
|
||||
$ ls
|
||||
README
|
||||
```
|
||||
|
||||
这个分支中没有你的新文件(或者你对其他文件的修改),而那些内容是合并的过程需要的信息:
|
||||
|
||||
|
||||
```
|
||||
$ fossil merge dev
|
||||
"fossil undo" is available to undo changes to the working checkout.
|
||||
$ ls
|
||||
myfile.lua README
|
||||
```
|
||||
|
||||
### 查看 Fossil 时间线
|
||||
|
||||
使用 `timeline` 选项来查看仓库的历史。这个命令列出了你的仓库的所有活动的详细信息,包括用来表示每次修改的哈希值、每次提交时填写的信息以及提交者:
|
||||
|
||||
|
||||
```
|
||||
$ fossil timeline
|
||||
=== 2020-11-09 ===
|
||||
06:24:16 [5ef06e668b] added exciting new file (user: klaatu tags: dev)
|
||||
06:11:19 [cb90e9c6f2] Create new branch named "dev" (user: klaatu tags: dev)
|
||||
06:08:09 [a2bb73e4a3] *CURRENT* some additions were made (user: klaatu tags: trunk)
|
||||
06:00:47 [2472a43acd] This is my first commit. (user: klaatu tags: trunk)
|
||||
04:09:35 [9e6cd96dd6] initial empty check-in (user: klaatu tags: trunk)
|
||||
+++ no more data (5) +++
|
||||
```
|
||||
|
||||
![Fossil UI][6]
|
||||
|
||||
(Klaatu, [CC BY-SA 4.0][7])
|
||||
|
||||
### 公开你的 Fossil 仓库
|
||||
|
||||
因为 Fossil 有个内置的 web 界面,所以 Fossil 不像 GitLab 和 Gitea 那样需要主机服务。Fossil 就是它自己的主机服务,只要你把它放在一台机器上就行了。在你公开你的 Fossil 仓库之前,你还需要通过 web 用户界面(UI)来配置一些信息:
|
||||
|
||||
使用 `ui` 子命令启动一个本地的实例:
|
||||
|
||||
|
||||
```
|
||||
$ pwd
|
||||
/home/klaatu/myprojectdir/
|
||||
$ fossil ui
|
||||
```
|
||||
|
||||
`用户`和`设置`是安全相关的,`配置`是项目属性相关的(包括一个合适的标题)。web 界面不仅仅是一个方便的功能。 它是能在生产环境中使用并作为 Fossil 项目的宿主来使用的。它还有一些其他的高级选项,比如用户管理(或者叫自我管理)、在同一个服务器上与其他的 Fossil 仓库进行单点登录(SSO)。
|
||||
|
||||
当配置完成后,关掉 web 界面并按下 **Ctrl+C** 来停止 UI 引擎。像提交代码一样提交你的 web 修改。
|
||||
|
||||
|
||||
```
|
||||
$ fossil commit -m 'web ui updates'
|
||||
New_Version: 11fe7f2855a3246c303df00ec725d0fca526fa0b83fa67c95db92283e8273c60
|
||||
```
|
||||
|
||||
现在你可以配置你的 Fossil 服务器了。
|
||||
|
||||
1. 把你的 Fossil 仓库(本例中是 `myproject.fossil`)复制到服务器,你只需要这一个文件。
|
||||
2. 如果你的服务器没有安装 Fossil,就在你的服务器上安装 Fossil。在服务器上安装的过程跟在本地一样。
|
||||
3. 在你的 `cgi-bin` 目录下(或它对应的目录,这取决于你的 HTTP 守护进程)创建一个名为 `repo_myproject.cgi` 的文件:
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
#!/usr/local/bin/fossil
|
||||
repository: /home/klaatu/public_html/myproject.fossil
|
||||
```
|
||||
|
||||
添加可执行权限:
|
||||
|
||||
|
||||
```
|
||||
`$ chmod +x repo_myproject.cgi`
|
||||
```
|
||||
|
||||
你需要做的都已经做完了。现在可以通过互联网访问你的项目了。
|
||||
|
||||
你可以通过 CGI 脚本来访问 web UI,例如 `https://example.com/cgi-bin/repo_myproject.cgi`。
|
||||
|
||||
你也可以通过命令行来进行交互:
|
||||
|
||||
|
||||
```
|
||||
`$ fossil clone https://klaatu@example.com/cgi-bin/repo_myproject.cgi`
|
||||
```
|
||||
|
||||
在本地的克隆仓库中工作时,你需要使用 `push` 子命令把本地的修改推送到远程的仓库,使用 `pull` 子命令把远程的修改拉取到本地仓库:
|
||||
|
||||
|
||||
```
|
||||
`$ fossil push https://klaatu@example.com/cgi-bin/repo_myproject.cgi`
|
||||
```
|
||||
|
||||
### 使用Fossil 作为独立的主机
|
||||
|
||||
Fossil 大大提高了你的效率(也提高了你的合作者的效率),让你不再依赖主机副刷。本文只是简单的介绍了基本概念。你的代码项目还会用到很多有用的 Fossil 功能。尝试一下 Fossil。它不仅会改变你对版本控制的理解;它会让你不再考虑其他的版本控制系统。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/11/fossil
|
||||
|
||||
作者:[Klaatu][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[lxbwolf](https://github.com/lxbwolf)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/klaatu
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/osdc_dinosaur_sunset.png?itok=lbzpbW5p "Dinosaurs on land at sunset"
|
||||
[2]: https://fossil-scm.org/home/doc/trunk/www/index.wiki
|
||||
[3]: https://www.sqlite.org/index.html
|
||||
[4]: https://fossil-scm.org/home/uv/download.html
|
||||
[5]: https://opensource.com/article/17/6/set-path-linux
|
||||
[6]: https://opensource.com/sites/default/files/uploads/fossil-ui.jpg "Fossil UI"
|
||||
[7]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
Reference in New Issue
Block a user