mirror of
https://github.com/LCTT/TranslateProject.git
synced 2026-08-23 04:03:29 +08:00
@@ -1,20 +1,22 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (lkxed)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (turbokernel)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-14747-1.html)
|
||||
[#]: subject: (Docker Compose: a nice way to set up a dev environment)
|
||||
[#]: via: (https://jvns.ca/blog/2021/01/04/docker-compose-is-nice/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
Docker Compose:搭建开发环境的好办法
|
||||
Docker Compose:搭建开发环境的好方式
|
||||
======
|
||||
|
||||

|
||||
|
||||
大家好!我又写了一篇关于 [我最喜欢的电脑工具][1] 的文章。这一篇讲的是 Docker Compose!
|
||||
|
||||
这篇文章主要就是讲一讲我对 Docker Compose 有多么满意啦(不讨论它的缺点)!咳咳,因为它总能够完成它该做的,并且似乎总能奏效,更棒的是,它使用起来还非常简单。另外,在本文中,我只讨论我是怎么用 Docker Compose 来搭建开发环境的,而不涉及它在生产中的使用。
|
||||
本文主要就是讲一讲我对 Docker Compose 有多么满意啦(不讨论它的缺点)!咳咳,因为它总能够完成它该做的,并且似乎总能有效,更棒的是,它的使用还非常简单。另外,在本文中,我只讨论我是如何用 Docker Compose 来搭建开发环境的,而不涉及它在生产中的使用。
|
||||
|
||||
最近,我考虑了很多关于这种搭建个人开发环境的方式,原因是,我现在把所有的计算工作都搬到了一个私有云上,大概 20 美元/月的样子。这样一来,我就不用在工作的时候花时间去思考应该如何管理几千台 AWS 服务器了。
|
||||
最近,我考虑了很多关于这种个人开发环境的搭建方式,原因是,我现在把所有的计算工作都搬到了一个私有云上,大概 20 美元/月的样子。这样一来,我就不用在工作的时候花时间去思考应该如何管理几千台 AWS 服务器了。
|
||||
|
||||
在此之前,我曾花了两天的时间,尝试使用其他的工具来尝试搭建一个开发环境,搭到后面,我实在是心累了。相比起来,Docker Compose 就简单易用多了,我非常满意。于是,我和妹妹分享了我的 `docker-compose` 使用经历,她略显惊讶:“是吧!你也觉得 Docker Compose 真棒对吧!” 嗯,我觉得我应该写一篇博文把过程记录下来,于是就有了你们看到的这篇文章。
|
||||
|
||||
@@ -24,10 +26,10 @@ Docker Compose:搭建开发环境的好办法
|
||||
|
||||
* 一个 Nginx 服务器
|
||||
* 一个 Rails 服务
|
||||
* 一个 Go 服务 (使用了 [gotty][2] 来代理一些 SSH 连接)
|
||||
* 一个 Go 服务(使用了 [gotty][2] 来代理一些 SSH 连接)
|
||||
* 一个 Postgres 数据库
|
||||
|
||||
在本地搭建 Rails 服务非常简单,用不着容器(我只需要安装 Postgres 和 Ruby 就行了,小菜一碟)。但是,我还想要把匹配 `/proxy/*` 的请求的发送到 Go 服务,其他所有请求都发送到 Rails 服务,所以我还要用到 Nginx。问题来了,在笔记本电脑上安装 Nginx 对我来说太麻烦了。
|
||||
在本地搭建 Rails 服务非常简单,用不着容器(我只需要安装 Postgres 和 Ruby 就行了,小菜一碟)。但是,我还想要把匹配 `/proxy/*` 的请求的发送到 Go 服务,其他所有请求都发送到 Rails 服务,所以需要借助 Nginx。问题来了,在笔记本电脑上安装 Nginx 对我来说太麻烦了。
|
||||
|
||||
是时候使用 `docker-compose` 了!
|
||||
|
||||
@@ -35,7 +37,7 @@ Docker Compose:搭建开发环境的好办法
|
||||
|
||||
基本上,Docker Compose 的作用就是允许你运行一组可以互相通信 Docker 容器。
|
||||
|
||||
你可以在一个叫做 `docker-compose.yml` 的文件中,配置你所有的容器。下面,我将贴上我为这个服务编写的 `docker-compose.yml` 文件(的全部内容),因为我觉得它真的很简洁、直接!
|
||||
你可以在一个叫做 `docker-compose.yml` 的文件中,配置你所有的容器。我在下方将贴上我为这个服务编写的 `docker-compose.yml` 文件(完整内容),因为我觉得它真的很简洁、直接!
|
||||
|
||||
```
|
||||
version: "3.3"
|
||||
@@ -63,7 +65,7 @@ services:
|
||||
- "8777:80" # this exposes port 8777 on my laptop
|
||||
```
|
||||
|
||||
这个配置包含了两种容器。对于前面两个容器,我不加修改地使用了既有的镜像(`image: postgres` 和 `image: ubuntu`)。对于后面两个,我不得不构建一个自定义容器镜像,其中, `build: docker/rails` 的作用就是告诉 Docker Compose,它应该使用 `docker/rails/Dockerfile` 来构建一个自定义容器。
|
||||
这个配置包含了两种容器。对于前面两个容器,我直接使用了现有的镜像(`image: postgres` 和 `image: ubuntu`)。对于后面两个容器,我不得不构建一个自定义容器镜像,其中, `build: docker/rails` 的作用就是告诉 Docker Compose,它应该使用 `docker/rails/Dockerfile` 来构建一个自定义容器。
|
||||
|
||||
我需要允许我的 Rails 服务访问一些 API 密钥和其他东西,因此,我使用了 `source secrets.sh`,它的作用就是在环境变量中预设一组密钥。
|
||||
|
||||
@@ -71,11 +73,11 @@ services:
|
||||
|
||||
我一直都是先运行 `docker-compose build` 来构建容器,然后再运行 `docker-compose up` 把所有服务启动起来。
|
||||
|
||||
你可以在 yaml 文件中设置 `depends_on`,这样你可以获得更多容器启动时的控制。不过,对于我的这些服务而言,启动顺序并不重要,所以我没有设置它。
|
||||
你可以在 yaml 文件中设置 `depends_on`,从而进行更多启动容器的控制。不过,对于我的这些服务而言,启动顺序并不重要,所以我没有设置它。
|
||||
|
||||
### 使用网络通信也非常简单
|
||||
### 网络互通也非常简单
|
||||
|
||||
有件很重要的事:容器之间得能够互相连接才行。Docker Compose 让这件事变得超级简单!假设我有一个 Rails 服务正在名为 `rails_server` 的容器中运行,端口是 3000,那么我就可以通过 `http://rails_server:3000` 来访问该服务。就是这么简单!
|
||||
容器之间的互通也是一件很重要的事情。Docker Compose 让这件事变得超级简单!假设我有一个 Rails 服务正在名为 `rails_server` 的容器中运行,端口是 3000,那么我就可以通过 `http://rails_server:3000` 来访问该服务。就是这么简单!
|
||||
|
||||
以下代码片段截取自我的 Nginx 配置文件,它是根据我的使用需求配置的(我删除了许多 `proxy_set_headers` 行,让它看起来更清楚):
|
||||
|
||||
@@ -88,7 +90,7 @@ location @app {
|
||||
}
|
||||
```
|
||||
|
||||
或者,你也看下面这个代码片段,它截取自我的 Rails 项目的数据库配置,我在其中使用了数据库容器的名称(`db`):
|
||||
或者,你可以参考如下代码片段,它截取自我的 Rails 项目的数据库配置,我在其中使用了数据库容器的名称(`db`):
|
||||
|
||||
```
|
||||
development:
|
||||
@@ -118,13 +120,13 @@ $ dig +short @127.0.0.11 go_server
|
||||
|
||||
以下所有命令都是在容器外执行的,因为我没有在容器里安装很多网络工具。
|
||||
|
||||
**第一步:**:使用 `ps aux | grep puma`,找到我的 Rails 服务的进程 ID。
|
||||
**第一步:**:使用 `ps aux | grep puma`,获取 Rails 服务的进程 ID。
|
||||
|
||||
找到了,它是 `1837916`!感觉不错哦~
|
||||
找到了,它是 `1837916`!简单~
|
||||
|
||||
**第二步:**:找到和 `1837916` 运行在同一个网络命名空间的 UDP 服务。
|
||||
|
||||
我使用了 `nsenter` 来在 `puma` 进程的网络命令空间内运行 `netstat`(理论上,我猜想你也可以使用 `netstat -tupn` 来只显示 UDP 服务,但此时,我的手指头只会打出 `netstat -tulpn`)。
|
||||
我使用了 `nsenter` 来在 `puma` 进程的网络命令空间内运行 `netstat`(理论上,我猜想你也可以使用 `netstat -tupn` 来只显示 UDP 服务,但此时,我的手指头只习惯于打出 `netstat -tulpn`)。
|
||||
|
||||
```
|
||||
$ sudo nsenter -n -t 1837916 netstat -tulpn
|
||||
@@ -152,7 +154,7 @@ $ sudo nsenter -n -t 1837916 dig +short @127.0.0.11 59426 rails_server
|
||||
|
||||
对于类似“这个服务似乎正运行在 X 端口上,但我却在 Y 端口上访问到了它,这是什么回事呢?”的问题,我的第一念头都是“一定是 iptables 在作怪”。
|
||||
|
||||
于是,我运行了容器的网络命令空间内运行了 `iptables-save`,果不其然,真相大白:
|
||||
于是,我在运行了容器的网络命令空间内执行 `iptables-save`,果不其然,真相大白:
|
||||
|
||||
```
|
||||
$ sudo nsenter -n -t 1837916 iptables-save
|
||||
@@ -165,13 +167,13 @@ COMMIT
|
||||
|
||||
### 数据库文件储存在一个临时目录中
|
||||
|
||||
这样做有一个好处:我可以直接挂载 Postgres 容器的数据目录 `./tmp/db`,而不需要在我的笔记本电脑上管理 Postgres 环境。
|
||||
这样做有一个好处:我可以直接挂载 Postgres 容器的数据目录 `./tmp/db`,而无需在我的笔记本电脑上管理 Postgres 环境。
|
||||
|
||||
我很喜欢这种方式,因为我真的不想在笔记本电脑上,亲自管理一个 Postgres 环境(我也真的不知道该如何配置 Postgres)。还有就是,出于习惯,我更喜欢让开发环境的数据库和代码放在同一个目录下。
|
||||
我很喜欢这种方式,因为我真的不想在笔记本电脑上独自管理一个 Postgres 环境(我也真的不知道该如何配置 Postgres)。另外,出于习惯,我更喜欢让开发环境的数据库和代码放在同一个目录下。
|
||||
|
||||
### 仅需一行命令,我就可以访问 Rails 控制台
|
||||
|
||||
管理 Ruby 的版本总是有点棘手,并且,即使我暂时搞定了它,我也总是有点担心自己会把 Ruby 环境搞坏,然后就要修它修个十年(夸张)。
|
||||
管理 Ruby 的版本总是有点棘手,并且,即使我暂时搞定了它,我也总是有点担心自己会把 Ruby 环境搞坏,然后就要修它个十年(夸张)。
|
||||
|
||||
(使用 Docker Compose)搭建好这个开发环境后,如果我需要访问 Rails <ruby>控制台<rt>console</rt></ruby>(一个交互式环境,加载了所有我的 Rails 代码),我只需要运行一行代码即可:
|
||||
|
||||
@@ -188,31 +190,31 @@ irb(main):001:0>
|
||||
|
||||
我碰到了一个问题:Rails 控制台的历史记录丢失了,因为我一直在不断地重启它。
|
||||
|
||||
不过,我也找到了一个相当简单的解决方案(嘿嘿):我往容器中添加了一个 `/root/.irbrc` 文件,它能够把 IRB 历史记录文件的保存位置,修改到一个不受容器重启影响的地方。只需要一行代码就够啦:
|
||||
不过,我也找到了一个相当简单的解决方案(嘿嘿):我往容器中添加了一个 `/root/.irbrc` 文件,它能够把 IRB 历史记录文件的保存位置指向一个不受容器重启影响的地方。只需要一行代码就够啦:
|
||||
|
||||
```
|
||||
IRB.conf[:HISTORY_FILE] = "/app/tmp/irb_history"
|
||||
```
|
||||
|
||||
### 我还是不知道它在生产环境的表现会怎么样
|
||||
### 我还是不知道它在生产环境的表现如何
|
||||
|
||||
到目前为止,这个项目的生产环境搭建进度,还停留在“我制作了一个 digitalocean droplet(LCCT 译注:一种 Linux 虚拟机服务),并手工编辑了很多文件”的阶段。
|
||||
到目前为止,这个项目的生产环境搭建进度,还停留在“我制作了一个 DigitalOcean droplet(LCCT 译注:一种 Linux 虚拟机服务),并手工编辑了很多文件”的阶段。
|
||||
|
||||
嗯……我相信我以后会在生产环境中使用 docker-compose 来运行一下它的。我猜它能够会正常工作,因为这个服务很可能最多只有两个用户在使用,并且,如果我愿意,我可以容忍它在部署过程中有 60 秒的不可用时间。不过话又说回来,出错的往往是我想不到的地方。
|
||||
嗯……我相信以后会在生产环境中使用 docker-compose 来运行一下它的。我猜它能够正常工作,因为这个服务很可能最多只有两个用户在使用,并且,如果我愿意,我可以容忍它在部署过程中有 60 秒的不可用时间。不过话又说回来,出错的往往是我想不到的地方。
|
||||
|
||||
推特网友提供了一些在生产中使用 docker-compose 的注意事项:
|
||||
|
||||
* `docker-compose up` 只会重启那些需要重启的容器,这会让重启速度更快。
|
||||
* 有一个 Bash 小脚本 [wait-for-it][3],你可以用它来让一个容器保持等待,直到另一个容器的服务可用。
|
||||
* 你可以准备两份 `docker-compose.yaml` 文件:用于开发环境的 `docker-compose.yaml` 和 用于生产环境的 `docker-compose-prod.yaml`。我想我会在分别为 Nginx 指定不同的端口:开发时使用 `8999`,生产中使用 `80`。
|
||||
* 有一个 Bash 小脚本 [wait-for-it][3],你可以用它来保持等待一个容器,直到另一个容器的服务可用。
|
||||
* 你可以准备两份 `docker-compose.yaml` 文件:用于开发环境的 `docker-compose.yaml` 和用于生产环境的 `docker-compose-prod.yaml`。我想我会在分别为 Nginx 指定不同的端口:开发时使用 `8999`,生产中使用 `80`。
|
||||
* 人们似乎一致认为,如果你的项目是一台计算机上运行的小网站,那么 docker-compose 在生产中不会有问题。
|
||||
* 有个人建议说,如果愿意在生产环境搭建复杂那么一丢丢,Docker Swarm 就或许会是更好的选择,不过我还没试过(当然,如果要这么说的话,干嘛不用 Kubernetes 呢?Docker Compose 的意义就是它超级简单,而 Kubernetes 肯定不简单 :))。
|
||||
* 有个人建议说,如果愿意在生产环境搭建复杂那么一丢丢,Docker Swarm 就或许会是更好的选择,不过我还没试过(当然,如果要这么说的话,干嘛不用 Kubernetes 呢?Docker Compose 的意义就是它超级简单,而 Kubernetes 肯定不简单 : ))。
|
||||
|
||||
Docker 似乎还有一个特性,它能够 [把你用 docker-compose 搭建的环境,自动推送到弹性容器服务(ESC)上][4],听上去好酷的样子,但是我还没有试过。
|
||||
|
||||
### docker-compose 会有不适用的场景吗
|
||||
|
||||
我听说 docker-compose 在以下场景的表现差强人意:
|
||||
我听说 docker-compose 在以下场景的表现较差:
|
||||
|
||||
* 当你有很多微服务的时候(还是自己搭建比较好)
|
||||
* 当你尝试从一个很大的数据库中导入数据时(就像把几百 G 的数据存到每个人的笔记本电脑里一样)
|
||||
@@ -231,7 +233,7 @@ via: https://jvns.ca/blog/2021/01/04/docker-compose-is-nice/
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[lkxed](https://github.com/lkxed)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[turbokernel](https://github.com/turbokernel)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
97
published/20210207 3 ways to play video games on Linux.md
Normal file
97
published/20210207 3 ways to play video games on Linux.md
Normal file
@@ -0,0 +1,97 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (godgithubf)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-14756-1.html)
|
||||
[#]: subject: (3 ways to play video games on Linux)
|
||||
[#]: via: (https://opensource.com/article/21/2/linux-gaming)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
在 Linux 上玩电子游戏的三种方式
|
||||
======
|
||||
|
||||
> 如果你准备放下爆米花,想从各个角度体验游戏的话,那么就在 Linux 下打开游戏吧!
|
||||
|
||||

|
||||
|
||||
如今,人们有更多喜欢 Linux 的理由。在这个系列里,我将分享 21 个使用 Linux 的理由。今天,我将从游戏开始。
|
||||
|
||||
我过去认为“游戏玩家”是一种非常特殊的生物,要由科学家们在数年的研究和测试之后严谨地认定才行。我从来没有把自己归类为游戏玩家,因为我所玩过的游戏要么是桌面游戏(棋盘类游戏和纸笔角色扮演游戏),要么是 NetHack、俄罗斯方块。现在,在移动设备、游戏机、电脑和电视机上都有游戏,我觉得现在的承认有各种形式的游戏玩家们了。如果你想自称为游戏玩家,你就可以是,不需任何资格认定。你不用必须在心里熟记那些“上上下下左右左右BA”的科乐美秘籍(你甚至可以不知道这是什么);你也不用必须买过和玩过 3A 级游戏。如果你时不时地玩游戏,你就完全可以自称为玩家。如果你想成为一名玩家,那么现在使用 Linux 正当其时。
|
||||
|
||||
### 欢迎来到游戏世界
|
||||
|
||||
剥除光鲜的广告,在其下面,你肯定会发现一个欣欣向荣的游戏世界。在人们相信不是电子表格也不是练习打字一类的软件能挣钱以前,新兴的游戏市场已经开始发展起来了。<ruby>独立游戏<rt>indie game</rt></ruby>已经在流行文化上以各种方式打上了自己的烙印(或许你不相信,《我的世界》尽管不是开源的,但一开始就是一款独立游戏),这也证实了,在玩家眼里,可玩性高于产品价值。
|
||||
|
||||
独立开发者和开源开发者之间有很多交集。没有什么比带着你的 Linux 笔记本电脑,浏览 itch.io 或你的发行版的软件库,寻找鲜为人知但珍贵的开源游戏宝藏更有意义了。
|
||||
|
||||
有各种各样的开源游戏,包括大量的第一视角射击游戏、Nodulus 之类的益智游戏、运输大亨之类的策略经营游戏、Jethook 之类的竞速游戏、Sauerbraten 之类的竞速逃生游戏,以及很多未提到的(多亏了像 Open Jam 这样伟大的活动,每年都有新增的游戏)。
|
||||
|
||||
![Jethook game screenshot][10]
|
||||
|
||||
总的来说,探索开源游戏的世界的体验,和购买大型游戏工作室的产品带来的即时满足感有很大的不同。大型游戏工作室生产的游戏提供大量的视听刺激、知名演员、和长达 60 小时以上的游戏时长。而独立和开源游戏不能与之相提并论。但是话又说回来,大型游戏工作室无法提供的是,当你发现一款别人未曾听说过的游戏时的产生的发现感和与个人相关的感受。当你意识到别人都非常想知道你刚玩过的哪个出色游戏时,大型工作室也并不能提供这种紧迫感。(LCTT 校注:此处大概的意思是指大型工作室的作品已被人熟知,没有什么挖掘的新鲜感)
|
||||
|
||||
花点时间找出你最喜欢的游戏,然后浏览下你的发行商的软件仓库、Flathub、开源的游戏仓库,看看你能发现什么,如果发现你很喜欢的游戏,就帮忙推广一下吧。
|
||||
|
||||
#### Proton 和 WINE
|
||||
|
||||
Linux 上的游戏并没有止步于开源,但是从开源开始的。数年前 Valve 软件公司通过发行 Linux 版的 Steam 客户端把 Linux 重新带入游戏市场时,人们希望这可以推动游戏工作室能编写原生的 Linux 游戏。一些工作室这样做了,但 Valve 公司并没有成功的把 Linux 推为主要的平台,即使是 Valve 品牌的游戏电脑。并且大多数游戏工作室又转回仅在 Windows 平台上开发游戏的旧方式。
|
||||
|
||||
有趣的是,最终的结果是产生了更多的开源代码。Valve 公司为 Linux 兼容创建了 Proton 工程,一个可以转换 Windows 游戏到 Linux 的兼容层。在 Proton 的内核层面,它使用了WINE(Wine Is Not an Emulator) —— 以开源的方式极好地重新实现了主要的 Windows 库。
|
||||
|
||||
游戏市场的成果,如今已经变成了开源世界的宝藏。今天,来自大型工作室的大多数游戏都可以在 Linux 上像原生游戏一样运行。
|
||||
|
||||
当然,如果你是必须要在发行日就玩上最新版游戏的这类玩家,你可能会遇到一些令人不愉快的“惊喜”。尽管那不是惊喜,很少有大型游戏在发行时毫无漏洞,一周后才补上补丁。这些游戏在 Proton 和 WINE 上运行时遇到这些错误可能更糟糕,因此 Linux 玩家通过避免尽早上车而避免这些问题。这种妥协可能是值得的。我玩过一些游戏,它们在 Proton 平台运行完美,后来从愤怒的论坛帖子中发现,它在最新版的 Windows 上运行显然充满了致命的错误。总之,似乎来自大型工作室的游戏并不完美,但你可能在 Linux 上遇到相似但不同的问题,正如你在 Windows 上遇到的。
|
||||
|
||||
#### Flatpak
|
||||
|
||||
Linux 近来历史上最令人激动的发展就是 Flatpak 了,它是本地容器和打包的结合,它和游戏无关(或者它和游戏息息相关),它使得 Linux 应用基本上能被分发到任意的 Linux 发行版上。这也适用于游戏,因为在游戏中使用了相当多的前沿技术,而对发行版维护者来说,要跟上任何特定游戏所需的所有最新版本可能是相当苛刻的。
|
||||
|
||||
Flapak 通过为应用程序库抽象出一种通用的 Flatpak 特定的层,而将其从发行版中抽象出来。Flatpak 软件包的发行者知道,如果一个库不在 Flatpak SDK 中,那么它必须要包含在 Flatpak 软件包中,简单而直接。
|
||||
|
||||
多亏了 Flatpak,Steam 客户端可以运行在像 Fedora 这样的常用发行版上,也可以运行在 RHEL、Slackware 等从传统角度看并不面向游戏市场的操作系统上。
|
||||
|
||||
#### Lutris
|
||||
|
||||
如果你并不急于在 Steam 上注册账号,那么可以用我比较偏爱的游戏客户端 Lutris 。表面上看,Lutris 是一个简单的游戏启动器,当你想玩游戏但还没决定玩什么的时候,你可以到这这里找找。有了 Lutris,你可以将系统上的所有游戏添加到你的游戏库,然后从 Lutris 界面启动并立即玩起来。更好的是,Lutris 贡献者(像我一样)会定期发布安装脚本,使你可以轻松安装自己的游戏。这并不是必须的,但它可以是一个很好的捷径,可以绕过一些繁琐的配置。
|
||||
|
||||
Lutris 也可以借助运行器或子系统,来运行那些不能从应用菜单直接启动的游戏。比如你想玩开源的《<ruby>魔兽塔防<rt>Warcraft Tower Defense</rt></ruby>》这样的游戏机游戏,你必须运行模拟器。如果你已经安装过模拟器的话,Lutris 可以帮你处理这一切。除此以外,如果你有一个 GOG.com 游戏账号,Lutris 可以访问它,并可以把游戏导入你的游戏库中。
|
||||
|
||||
没有比这更容易的管理你的游戏的方式了。
|
||||
|
||||
### 去玩游戏吧
|
||||
|
||||
Linux 游戏是一种充实且给人力量的体验。我过去避免玩电脑游戏,因为我不觉得我有太多的选择。似乎昂贵的游戏总是在不断发布,并且不可避免的获得好或者不好的极端体验,然后很快又转向下一个。另一方面,开源游戏把我引入了游戏的圈子。我见到过其他玩家和开发者。我见到过艺术家和音乐家、粉丝以及推广者。我玩过各种各样的我从来不知道的游戏。其中一些甚至不够我玩一下午,而其他的却让我长久的着迷于游戏、修改、关卡设计和乐趣。
|
||||
|
||||
如果你准备好放下爆米花,从各个角度体验下游戏的话,那就在 Linux 上开始游戏吧。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/2/linux-gaming
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[godgithubf](https://github.com/godgithubf)
|
||||
校对:[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/alternatives/minecraft
|
||||
[3]: https://itch.io/jam/open-jam-2020
|
||||
[4]: https://opensource.com/article/20/5/open-source-fps-games
|
||||
[5]: https://hyperparticle.itch.io/nodulus
|
||||
[6]: https://www.openttd.org/
|
||||
[7]: https://rcorre.itch.io/jethook
|
||||
[8]: http://sauerbraten.org/
|
||||
[9]: https://opensource.com/article/18/9/open-jam-announcement
|
||||
[10]: https://opensource.com/sites/default/files/game_0.png
|
||||
[11]: http://flathub.org
|
||||
[12]: https://github.com/ValveSoftware/Proton
|
||||
[13]: http://winehq.org
|
||||
[14]: https://opensource.com/business/16/8/flatpak
|
||||
[15]: https://www.redhat.com/en/enterprise-linux-8
|
||||
[16]: http://lutris.net
|
||||
[17]: https://opensource.com/article/18/10/lutris-open-gaming-platform
|
||||
[18]: https://ndswtd.wordpress.com/download
|
||||
@@ -3,23 +3,22 @@
|
||||
[#]: author: "Seth Kenlon https://opensource.com/users/seth"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "lkxed"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-14751-1.html"
|
||||
|
||||
一起来学习 Lisp 编程语言吧!
|
||||
======
|
||||
许多大型代码库中都有 Lisp 代码的身影,因此,熟悉一下这门语言是一个明智之举。
|
||||
|
||||
![科技和计算领域的女性][1]
|
||||

|
||||
|
||||
图源:kris krüg
|
||||
> 许多大型代码库中都有 Lisp 代码的身影,因此,熟悉一下这门语言是一个明智之举。
|
||||
|
||||
Lisp 在 1958 年就被发明出来了,它是世界上第二老的计算机编程语言(LCTT 译注:最老的是 Fortran,诞生于 1957 年)。它有许多现代的衍生品,包括 Common Lisp、Emacs Lisp(Elisp)、Clojure、Racket、Scheme、Fennel 和 GNU Guile 等。
|
||||
早在 1958 年,Lisp 就被发明出来了,它是世界上第二古老的计算机编程语言(LCTT 译注:最古老的编程语言是 Fortran,诞生于 1957 年)。它有许多现代的衍生品,包括 Common Lisp、Emacs Lisp(Elisp)、Clojure、Racket、Scheme、Fennel 和 GNU Guile 等。
|
||||
|
||||
那些喜欢思考编程语言设计的人,往往都喜欢 Lisp,因为它的语法和数据有者相同的结构:Lisp 代码实际上是<ruby>一个列表的列表<rt>a list of lists</rt></ruby>,它的名字其实是 <ruby>“列表处理”<rt>LISt Processing</rt></ruby> 的首字母缩写。那些喜欢思考编程语言美学的人,往往都讨厌 Lisp,因为它经常使用括号来定义范围;事实上,编程界也有一个广为流传的笑话:Lisp 代表的其实是 <ruby>“大量烦人的多余括号”<rt>Lots of Irritating Superfluous Parentheses</rt></ruby>。
|
||||
那些喜欢思考编程语言的设计的人,往往都喜欢 Lisp,因为它的语法和数据有着相同的结构:Lisp 代码实际上是<ruby>一个列表的列表<rt>a list of lists</rt></ruby>,它的名字其实是 “<ruby>列表处理<rt>LISt Processing</rt></ruby>” 的简写。而那些喜欢思考编程语言的美学的人,往往都讨厌 Lisp,因为它经常使用括号来定义范围;事实上,编程界也有一个广为流传的笑话:Lisp 代表的其实是 <ruby>“大量烦人的多余括号”<rt>Lots of Irritating Superfluous Parentheses</rt></ruby>。
|
||||
|
||||
不管你是喜欢还是讨厌 Lisp 的设计哲学,你都不得不承认,它都是一门有趣的语言,过去如此,现在亦然(这得归功于现代方言 Clojure 和 Guile)。你可能会感到惊讶,但事实就是,Lisp 在任何行业的大型代码库中都占有一席之地。因此,现在开始学习 Lisp,至少熟悉一下它,不失为一个好主意。
|
||||
不管你是喜欢还是讨厌 Lisp 的设计哲学,你都不得不承认,它都是一门有趣的语言,过去如此,现在亦然(这得归功于现代方言 Clojure 和 Guile)。你可能会惊讶于在任何特定行业的大代码库中潜伏着多少 Lisp 代码,因此,现在开始学习 Lisp,至少熟悉一下它,不失为一个好主意。
|
||||
|
||||
### 安装 Lisp
|
||||
|
||||
@@ -55,7 +54,7 @@ $ brew install clisp
|
||||
|
||||
### 列表处理
|
||||
|
||||
Lisp 源代码的基本单元是 <ruby>“表达式”<rt>expression</rt></ruby>,它在形式上是一个列表。举个例子,下面就是一个列表,它由一个操作符(`+`)和两个整数(`1` 和 `2`)组成的:
|
||||
Lisp 源代码的基本单元是 “<ruby>表达式<rt>expression</rt></ruby>”,它在形式上是一个列表。举个例子,下面就是一个列表,它由一个操作符(`+`)和两个整数(`1` 和 `2`)组成:
|
||||
|
||||
```
|
||||
(+ 1 2)
|
||||
@@ -85,7 +84,7 @@ $ clisp
|
||||
|
||||
### 函数
|
||||
|
||||
在了解了 Lisp 表达式的基本结构后,你可以使用函数来做更多有用的事。譬如,`print` 函数可以接受任意数量的参数,然后把它们都显示在你的终端上,`pprint` 函数还可以实现格式化打印。还有更多不同的打印函数,不过,`pprint` 在 REPL 中的效果还挺好的:
|
||||
在了解了 Lisp 表达式的基本结构后,你可以使用函数来做更多有用的事。譬如,`print` 函数可以接受任意数量的参数,然后把它们都显示在你的终端上,`pprint` 函数还可以实现格式化打印。还有更多不同的打印函数,不过,`pprint` 在 REPL 中的效果就挺好的:
|
||||
|
||||
```
|
||||
[1]> (pprint "hello world")
|
||||
@@ -121,7 +120,7 @@ MYPRINTER
|
||||
[3]>
|
||||
```
|
||||
|
||||
你可以往表达式里嵌套表达式(就像使用某种管道一样)。举个例子,你可以先使用 `string-upcase` 函数,把某个字符串的所有字符转换成大写,然后再使用 `pprint` 函数,将它的内容格式化打印到终端上:
|
||||
你可以在表达式里嵌套表达式(就像使用某种管道一样)。举个例子,你可以先使用 `string-upcase` 函数,把某个字符串的所有字符转换成大写,然后再使用 `pprint` 函数,将它的内容格式化打印到终端上:
|
||||
|
||||
```
|
||||
[3]> (pprint (string-upcase foo))
|
||||
@@ -142,7 +141,6 @@ Lisp 是动态类型语言,这意味着,你在给变量赋值时不需要声
|
||||
|
||||
如果你想让整数被当作字符串来处理,你可以给它加上引号:
|
||||
|
||||
|
||||
```
|
||||
[4]> (setf foo "2")
|
||||
"2"
|
||||
@@ -215,7 +213,7 @@ $
|
||||
|
||||
### 编写脚本
|
||||
|
||||
Lisp 可以被编译,也可以作为解释型的脚本语言来使用。在你刚开始学习的时候,后者很可能是最容易的选项,特别是当你已经熟悉 Python 或 [Shell 脚本][9] 时。
|
||||
Lisp 可以被编译,也可以作为解释型的脚本语言来使用。在你刚开始学习的时候,后者很可能是最容易的方式,特别是当你已经熟悉 Python 或 [Shell 脚本][9] 时。
|
||||
|
||||
下面是一个用 Common Lisp 编写的简单的“掷骰子”脚本:
|
||||
|
||||
@@ -231,7 +229,7 @@ Lisp 可以被编译,也可以作为解释型的脚本语言来使用。在你
|
||||
(roller userput)
|
||||
```
|
||||
|
||||
脚本的第一行注释告诉了你的 POSIX 终端,该使用什么可执行文件来运行这个脚本。
|
||||
脚本的第一行注释(LCTT 译注:称之为“<ruby>释伴<rt>shebang</rt></ruby>”)告诉了你的 POSIX 终端,该使用什么可执行文件来运行这个脚本。
|
||||
|
||||
`roller` 函数使用 `defun` 函数创建,它在内部使用 `random` 函数来打印一个伪随机数,这个伪随机数严格小于 `num` 列表中下标为 0 的元素。在脚本中,这个 `num` 列表还没有被创建,不过没关系,因为只有当脚本被调用时,函数才会执行。
|
||||
|
||||
@@ -278,7 +276,7 @@ via: https://opensource.com/article/21/5/learn-lisp
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[lkxed](https://github.com/lkxed)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
@@ -3,20 +3,22 @@
|
||||
[#]: author: "Abhishek Prakash https://itsfoss.com/author/abhishek/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "robsean"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-14760-1.html"
|
||||
|
||||
在 Ubuntu 中使用 apt 命令来安装具体指定的软件包版本
|
||||
如何在 Ubuntu 中安装具体指定的软件包版本
|
||||
======
|
||||
|
||||
在 Ubuntu 中想安装一个软件包的一个具体指定的软件包版本?你可以通过下面的方式来轻松地完成:
|
||||

|
||||
|
||||
在 Ubuntu 中想安装一个软件包的一个特别指定的版本?你可以通过下面的方式来轻松地完成:
|
||||
|
||||
```
|
||||
sudo apt install package_name=package_version
|
||||
```
|
||||
|
||||
你如何知道某个软件包有哪些可用的版本?使用这个命令:
|
||||
你如何知道某个软件包有哪些可用的版本?可以使用这个命令:
|
||||
|
||||
```
|
||||
apt list --all-versions package_name
|
||||
@@ -28,23 +30,23 @@ apt list --all-versions package_name
|
||||
|
||||
听起来像一个简单的任务,对吧?但是事情并非看起来那么简单。这里有一些不确定是否会出现,但是可能会涉及的东西。
|
||||
|
||||
这篇教程将涵盖使用 apt 或 apt-get 命令来安装一个具体指定的程序的版本的所有的重要的方面。
|
||||
这篇教程将涵盖使用 `apt` 或 `apt-get` 命令来安装一个具体指定的程序的版本的所有的重要的方面。
|
||||
|
||||
### 关于安装一个具体指定版本的程序而所需要知道的事
|
||||
### 安装一个具体指定版本的程序需要知道的事
|
||||
|
||||
在基于 Ubuntu 和 Debian 发行版中,你需要知道一些关于 APT 和 存储库 是如何工作的知识
|
||||
在基于 Ubuntu 和 Debian 发行版中,你需要知道一些关于 APT 和存储库是如何工作的知识。
|
||||
|
||||
#### 同一个的软件包源没有较旧的版本
|
||||
#### 同一个软件包源没有较旧的版本
|
||||
|
||||
Ubuntu 在其存储库中不保留较旧版本的软件包。在特殊的情况下,你可以暂时性地看到多个版本。例如,你运行 apt 更新 (但不升级),那么会用一个可用的新的版本。在 apt 缓存中,你可以看到同一个软件包的两个版本。但是,一旦软件包被升级到了新的版本,较旧版本的软件包将从 **apt 缓存** 和 存储库 中移除。
|
||||
Ubuntu 在其存储库中不保留较旧版本的软件包。在特殊的情况下,你可以暂时性地看到多个版本。例如,你运行 APT 更新(但不升级)时,可能会有一个可用的新版本。在 APT 缓存中,你可以看到同一个软件包的两个版本。但是,一旦软件包被升级到了新的版本,较旧版本的软件包将从 **APT 缓存** 和存储库中移除。
|
||||
|
||||
#### 使用多个软件包源来使用不同的版本
|
||||
|
||||
为获取同一个的软件包的多个版本,你将必需条件多个软件包源。例如,VLC 是版本 3.x 系列。添加 [VLC 每日构建 PPA][2] 将会提供 (不稳定是) 版本 4.x 系列。
|
||||
为获取同一个的软件包的多个版本,你必须得添加多个软件包源。例如,VLC 是版本 3.x 系列。添加 [VLC 每日构建 PPA][2] 将会提供(不稳定的)版本 4.x 系列。
|
||||
|
||||
同样,**你可以下载不同版本的 DEB 文件,并安装它**。
|
||||
|
||||
#### 较高版本编号的版本通常获取优先权
|
||||
#### 较高版本编号的版本通常有优先权
|
||||
|
||||
如果你有来自多个软件包源的相同名称的软件,默认情况下,Ubuntu 将安装可用的最高版本编号的版本。
|
||||
|
||||
@@ -52,11 +54,11 @@ Ubuntu 在其存储库中不保留较旧版本的软件包。在特殊的情况
|
||||
|
||||
#### 较旧版本将升级到可用的较新版本
|
||||
|
||||
这是另外一个可能存在的问题。即使你安装较旧版本的软件包,它也会升级到较新的版本 (如果存在可用的较新的版本)。你必须 [监禁软件包来防止其升级][3] 。
|
||||
这是另外一个可能存在的问题。即使你安装较旧版本的软件包,它也会升级到较新的版本(如果存在可用的较新版本)。你必须 [保留该软件包来防止其升级][3] 。
|
||||
|
||||
#### 依赖关系也需要安装
|
||||
|
||||
如果软件包有依赖关系,你也需要安装必要的依赖关系软件包版本。
|
||||
如果软件包有依赖关系,你也需要安装必要的依赖关系软件包。
|
||||
|
||||
现在,你已经知道一些可能存在的问题,让我们看看如何解决它们。
|
||||
|
||||
@@ -69,20 +71,20 @@ Ubuntu 在其存储库中不保留较旧版本的软件包。在特殊的情况
|
||||
![install specific versions apt ubuntu][4]
|
||||
|
||||
```
|
||||
[email protected]:~$ apt list -a vlc
|
||||
~$ apt list -a vlc
|
||||
Listing... Done
|
||||
vlc/jammy 4.0.0~rc1~~git20220516+r92284+296~ubuntu22.04.1 amd64
|
||||
vlc/jammy 3.0.16-1build7 amd64
|
||||
vlc/jammy 3.0.16-1build7 i386
|
||||
```
|
||||
|
||||
因为较高版本编号版本获取优先权,使用 ‘apt install vlc’ 命令将会导致安装 VLC 的 4.0 版本。但是,因为这篇教程的缘由,我想安装较旧的版本 3.0.16 。
|
||||
因为较高版本编号版本有优先权,使用 `apt install vlc` 命令将会导致安装 VLC 的 4.0 版本。但是,因为这篇教程的缘由,我想安装较旧的版本 3.0.16 。
|
||||
|
||||
```
|
||||
sudo apt install vlc=3.0.16-1build7
|
||||
```
|
||||
|
||||
但是,这里会有这样的事。vlc 软件包有一些依赖关系,并且这些依赖关系也需要具体指定的版本。因此,在 Ubuntu 为其尝试安装最新的版本时,你将会遇到经典的 [<ruby>你已持有残缺软件包<rt>you have held broken packages</rt></ruby>][5] 错误。
|
||||
但是,这里会有这样的事。VLC 软件包有一些依赖关系,并且这些依赖关系也需要具体指定的版本。因此,在 Ubuntu 为其尝试安装最新的版本时,你将会遇到经典的 <ruby>[你已保留残缺软件包][5]<rt>you have held broken packages</rt></ruby> 错误。
|
||||
|
||||
![problem installing specific version apt ubuntu][6]
|
||||
|
||||
@@ -103,13 +105,13 @@ sudo apt install vlc=3.0.16-1build7 \
|
||||
vlc-plugin-visualization=3.0.16-1build7
|
||||
```
|
||||
|
||||
以免你瞎琢磨,每行结尾处的 \ 只是用来将多行命令来写入同一个命令的一种方式。
|
||||
说明一下,每行结尾处的 `\` 只是用来将多行命令来写入同一个命令的一种方式。
|
||||
|
||||
**它有作用吗?在很多情况下,它是有作用的。** 但是,我选择了一个复杂的 VLC 示例,它有很多依赖关系。甚至这些所涉及的依赖关系也依赖于其它的软件包。所以,它就变得令人难以处理。
|
||||
|
||||
一种可选的方法是在安装时指定软件包源。
|
||||
一种替代的方法是在安装时指定软件包源。
|
||||
|
||||
#### 可选,指定存储库软件包源
|
||||
#### 替代方式,指定存储库
|
||||
|
||||
你已经添加多个软件包源,因此,你应该对这些软件包的来源有一些了解。
|
||||
|
||||
@@ -119,7 +121,7 @@ sudo apt install vlc=3.0.16-1build7 \
|
||||
apt-cache policy | less
|
||||
```
|
||||
|
||||
聚焦于存储库名称后面的行:
|
||||
注意存储库名称后面的行:
|
||||
|
||||
```
|
||||
500 http://security.ubuntu.com/ubuntu jammy-security/multiverse i386 Packages
|
||||
@@ -127,9 +129,9 @@ apt-cache policy | less
|
||||
origin security.ubuntu.com
|
||||
```
|
||||
|
||||
你可以具体指定 o、l、a 等参数。
|
||||
你可以具体指定 `o`、`l`、`a` 等参数。
|
||||
|
||||
在我原来的示例中,我想安装来自 Ubuntu 存储库的 VLC (获取版本 3.16) ,而不是安装来 PPA 的版本 (它将向我提供版本 4)。
|
||||
在我原来的示例中,我想安装来自 Ubuntu 存储库的 VLC(获取版本 3.16),而不是安装来 PPA 的版本(它将向我提供版本 4)。
|
||||
|
||||
因此,下面的命令将安装 VLC 版本 3.16 及其所有的依赖关系:
|
||||
|
||||
@@ -143,9 +145,9 @@ sudo apt install -t "o=ubuntu" vlc
|
||||
|
||||
**还能做什么?**
|
||||
|
||||
为安装较旧的软件包版本,从你的系统中移除较新版本的软件包源 (如果可能的话)。它将有助于逃脱这些依赖关系的地狱。
|
||||
为安装较旧的软件包版本,从你的系统中移除较新版本的软件包源(如果可能的话)。它将有助于逃脱这些依赖关系地狱。
|
||||
|
||||
如果不能这么做,检查你是否可以从其它一些打包软件包的格式来获取,像 Snap、Flatpak、AppImage 等等。事实上,Snap 和 Flatpak 也允许你从可用的版本中选择和安装。因为这些应用程序是沙盒模式的,所以它很容易管理不同版本的依赖关系。
|
||||
如果不能这么做,检查你是否可以从其它一些软件包的打包格式来获取,像 Snap、Flatpak、AppImage 等等。事实上,Snap 和 Flatpak 也允许你从可用的版本中选择和安装。因为这些应用程序是沙盒模式的,所以它很容易管理不同版本的依赖关系。
|
||||
|
||||
#### 保留软件包,防止升级
|
||||
|
||||
@@ -155,17 +157,17 @@ sudo apt install -t "o=ubuntu" vlc
|
||||
sudo apt-mark hold package_name
|
||||
```
|
||||
|
||||
你可以移除保留软件包,以便它能稍后升级:
|
||||
你可以免除保留软件包,以便它能稍后升级:
|
||||
|
||||
```
|
||||
sudo apt-mark unhold package_name
|
||||
```
|
||||
|
||||
注意,软件包的依赖关系不会自动地保持。它们需要单独地提及。
|
||||
注意,软件包的依赖关系不会自动地保留。它们需要单独地指明。
|
||||
|
||||
### 结论
|
||||
|
||||
如你所见,这里有一条安装选定软件包版本的条文。只要软件包有依赖关系,那么事情就会变得复杂。接下来,你将进入依赖关系的地狱。
|
||||
如你所见,安装选定软件包版本有一定之规。只有当软件包有依赖关系时,那么事情就会变得复杂,然后,你就会进入依赖关系地狱。
|
||||
|
||||
我希望你在这篇教程中学到一些新的东西。如果你有问题或建议来改善它,请在评论区告诉我。
|
||||
|
||||
@@ -176,7 +178,7 @@ via: https://itsfoss.com/apt-install-specific-version-2/
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[robsean](https://github.com/robsean)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
@@ -3,65 +3,68 @@
|
||||
[#]: author: "Pradeep Kumar https://www.linuxtechi.com/author/pradeep/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-14750-1.html"
|
||||
|
||||
如何启动 Ubuntu 22.04 进入救援/紧急模式
|
||||
======
|
||||
极客们好,将 Ubuntu 22.04(Jammy Jellyfish)启动到救援和紧急模式有助于重置忘记的用户密码,修复文件系统错误以及在启动过程中禁用或启用 systemd 服务。
|
||||
|
||||

|
||||
|
||||
极客们好,将 Ubuntu 22.04(Jammy Jellyfish)启动到<ruby>救援<rt>Rescue</rt></ruby>和<ruby>紧急<rt>Emergency</rt></ruby>模式可以重置忘记的用户密码、修复文件系统错误,以及在启动过程中禁用或启用 systemd 服务。
|
||||
|
||||
在这篇文章中,我们将学习如何启动 Ubuntu 22.04 LTS 系统进入救援和应急模式。救援模式类似于单用户模式,所有的故障排除步骤都在这里进行。救援模式加载最小的环境并挂载根文件系统。
|
||||
|
||||
而在紧急模式下,我们得到的是单用户 shell,而不启动任何系统服务。因此,当我们无法启动系统进入救援模式时,就需要紧急模式。
|
||||
而在紧急模式下,我们得到的是单用户 Shell,而不启动任何系统服务。因此,当我们无法启动系统进入救援模式时,就需要紧急模式。
|
||||
|
||||
### 启动 Ubuntu 22.04 进入救援或单用户模式
|
||||
|
||||
前往你想启动到救援或单用户模式的目标系统。在启动时按下 “SHIFT+ESC” 键,进入 grub bootloader 页面。
|
||||
前往你想启动到救援或单用户模式的目标系统。在启动时按下 `SHIFT + ESC` 键,进入 GRUB 引导加载器页面。
|
||||
|
||||
![Default-Grub-Screen-Ubuntu-22-04][1]
|
||||
|
||||
选择第一个选项 Ubuntu,并按 “e” 键进入编辑模式。
|
||||
选择第一个选项 “Ubuntu”,并按 `e` 键进入编辑模式。
|
||||
|
||||
在以 linux 开头的一行末尾,删除字符串 “$vt_handoff” 并添加字符串 “systemd.unit=rescue.target”。
|
||||
在以 `linux` 开头的一行末尾,删除字符串 `$vt_handoff` 并添加字符串 `systemd.unit=rescue.target`。
|
||||
|
||||
![rescue-target-ubuntu-22-04][2]
|
||||
|
||||
做完修改后,按 Ctrl+x 或 F10 在救援模式下启动。
|
||||
做完修改后,按 `Ctrl + X` 或 `F10` 在救援模式下启动。
|
||||
|
||||
![Troubleshooting-Commands-in-Rescue-Mode][3]
|
||||
|
||||
进入救援模式后,运行所有的故障排除命令,并运行 “systemctl reboot” 命令来重启系统。
|
||||
进入救援模式后,运行所有的故障排除命令,并运行 `systemctl reboot` 命令来重启系统。
|
||||
|
||||
### 另一种启动系统进入救援模式的方法
|
||||
|
||||
重新启动系统并按下 “ESC+Shift” 键,进入 grub 启动界面。
|
||||
重新启动系统并按下 `ESC + Shift` 键,进入 GRUB 启动界面。
|
||||
|
||||
选择第二个选项 “Advanced Options for Ubuntu”->选择恢复模式选项并点击回车->选择 Root(进入 root shell 提示)。
|
||||
选择第二个选项 “<ruby>Ubuntu 高级选项<rt>Advanced Options for Ubuntu</rt></ruby>”->选择“<ruby>恢复模式<rt>recovery mode</rt></ruby>”选项并点击回车->选择 <ruby>root(进入 root shell 提示符)<rt>root (Drop to root shell prompt)</rt></ruby>。
|
||||
|
||||
下面是一个例子
|
||||
下面是一个例子:
|
||||
|
||||
![Boot-Ubuntu-22-04-Rescue-Mode][4]
|
||||
|
||||
当你有了 root shell,运行命令来恢复和修复系统问题,最后使用 “systemctl reboot” 来重启系统。
|
||||
当你有了 root Shell,运行命令来恢复和修复系统问题,最后使用 `systemctl reboot` 来重启系统。
|
||||
|
||||
### 引导 Ubuntu 22.04 进入紧急模式
|
||||
|
||||
要启动系统进入紧急模式,首先进入 grub 页面。
|
||||
要启动系统进入紧急模式,首先进入 GRUB 页面。
|
||||
|
||||
![Default-Grub-Screen-Ubuntu-22-04][5]
|
||||
|
||||
选择第一个选项 “Ubuntu” 并按 “e” 键进行编辑。寻找以 linux 开头的一行,移到该行的末尾,删除字符串 $vt_handoff 并添加字符串 “systemd.unit=emergency.target”。
|
||||
选择第一个选项 “Ubuntu” 并按 `e` 键进行编辑。寻找以 `linux` 开头的一行,移到该行的末尾,删除字符串 `$vt_handoff` 并添加字符串 `systemd.unit=emergency.target`。
|
||||
|
||||
![Emergency-Mode-Ubuntu-22-04][6]
|
||||
|
||||
按 Ctrl+x 或 F10 将系统启动到紧急模式。
|
||||
按 `Ctrl + X` 或 `F10` 将系统启动到紧急模式。
|
||||
|
||||
![Command-in-Emergency-Mode-Ubuntu-22-04][7]
|
||||
|
||||
同样,在救援模式下,你可以在这个模式下执行所有的故障排除,完成后,就用 “systemctl reboot” 命令重启系统。
|
||||
同样,在紧急模式下,你可以在这个模式下执行所有的故障排除,完成后,就用 `systemctl reboot` 命令重启系统。
|
||||
|
||||
这篇文章的内容就这些。我发现它内容丰富,不要犹豫,在你的技术朋友中分享这个。请在下面的评论区发表你的疑问和反馈。
|
||||
这篇文章的内容就这些。文章内容丰富,不要犹豫,请在你的技术朋友中分享它。请在下面的评论区发表你的疑问和反馈。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@@ -70,7 +73,7 @@ via: https://www.linuxtechi.com/boot-ubuntu-22-04-rescue-emergency-mode/
|
||||
作者:[Pradeep Kumar][a]
|
||||
选题:[lkxed][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/) 荣誉推出
|
||||
|
||||
@@ -3,27 +3,26 @@
|
||||
[#]: author: "Michael Korotaev https://opensource.com/users/michaelk"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-14761-1.html"
|
||||
|
||||
用这些开源工具在 Linux 上编辑 PDF 文件
|
||||
======
|
||||
Adobe Acrobat 的开源替代品具有创建、编辑和注释 PDF 的所有必要功能。
|
||||
|
||||
![a checklist for a team][1]
|
||||

|
||||
|
||||
图片由:Opensource.com
|
||||
> Adobe Acrobat 的开源替代品具有创建、编辑和注释 PDF 的所有必要功能。
|
||||
|
||||
开源的 PDF 阅读和编辑工具通常比 “PDF 编辑器”搜索结果第一页中的应用更安全和可靠。在那里,你很可能看到带有隐藏限制和关税的专有应用,缺乏关于数据保护政策和托管的足够信息。你可以有更好的。
|
||||
开源的 PDF 阅读和编辑工具通常比 “PDF 编辑器” 搜索结果第一页中的应用更安全和可靠。在那里,你很可能看到带有隐藏的限制和关税的专有应用,缺乏关于数据保护政策和托管的足够信息。你可以有更好的。
|
||||
|
||||
这里有五个应用,可以安装在你的 Linux 系统上(和其他系统)或托管在服务器上。每一个都是免费和开源的,具有创建、编辑和注释 PDF 文件的所有必要功能。
|
||||
这里有五个应用,可以安装在你的 Linux 系统上(和其他系统)或托管在服务器上。每一个都是自由而开源的,具有创建、编辑和注释 PDF 文件的所有必要功能。
|
||||
|
||||
### LibreOffice
|
||||
|
||||
使用 [LibreOffice][2] 套件,你对应用的选择取决于最初的任务。虽然文字处理器 LibreOffice Writer,可以让你创建 PDF 文件,并从 ODF 和其他文本格式导出,但 Draw 更适合于处理现有的 PDF 文件。
|
||||
|
||||
Draw 是用来创建和编辑图形文件的,如小册子、杂志和海报。因此,该工具集主要集中在视觉对象和布局上。然而,对于 PDF 编辑,当文件具有编辑属性时,LibreOffice Draw 提供了用于修改和添加 PDF 内容的工具。如果没有的话,你仍然可以在现有的内容层上添加新的文本字段,并对文件进行注释或完成。
|
||||
Draw 是用来创建和编辑图形文件的,如小册子、杂志和海报。因此,其工具集主要用于视觉对象和布局上。然而,对于 PDF 编辑,当文件具有可编辑属性时,LibreOffice Draw 提供了用于修改和添加 PDF 内容的工具。如果没有的话,你仍然可以在现有的内容层上添加新的文本字段,并对文件进行注释或完成。
|
||||
|
||||
Draw 和 Writer 都被捆绑在 LibreOffice 桌面套件中,可在 Linux 系统、macOS 和 Windows 上安装。
|
||||
|
||||
@@ -39,7 +38,7 @@ ONLYOFFICE Docs 可以作为一个网络套件(内部或云端)集成到文
|
||||
|
||||
### PDF Arranger
|
||||
|
||||
[PDF Arranger][4] 是 PikePDF 库的一个前端应用。它不像 LibreOffice 和 ONLYOFFICE 那样对 PDF 的内容进行编辑,但它对于重新排序页面、将 PDF 分割成更小的文件、将几个 PDF 合并成一个、旋转或裁剪页面等都很好。它的界面是直观的,易于使用。
|
||||
[PDF Arranger][4] 是 PikePDF 库的一个前端应用。它不像 LibreOffice 和 ONLYOFFICE 那样用于对 PDF 的内容进行编辑,但它对于重新排序页面、将 PDF 分割成更小的文件、将几个 PDF 合并成一个、旋转或裁剪页面等都很好。它的界面是直观的,易于使用。
|
||||
|
||||
PDF Arranger 可用于 Linux 和 Windows。
|
||||
|
||||
@@ -67,7 +66,7 @@ Xournal++ 可在 Linux 系统(Ubuntu、Debian、Arch、SUSE)、MacOS 和 Win
|
||||
|
||||
如果你正在寻找一个免费和安全的专有 PDF 浏览和编辑软件的替代品,不难找到一个开源的选择,无论是桌面还是在线使用。只要记住,目前可用的解决方案在不同的使用情况下有各自的优势,没有一个工具在所有可能的任务中都同样出色。
|
||||
|
||||
这五个方案因其功能或对小众 PDF 任务的有用性而脱颖而出。对于企业使用和协作,我建议 ONLYOFFICE 或 LibreOffice Draw。PDF Arranger 是一个简单的、轻量级的工具,当你不需要改变文本时,可以用它来处理页面。Okular 为多种文件类型提供了很好的查看功能,如果你想在 PDF 中画草图和做笔记,Xournal++ 是最佳选择。
|
||||
这五个方案因其功能或对小众 PDF 任务的有用性而脱颖而出。对于企业使用和协作,我建议使用 ONLYOFFICE 或 LibreOffice Draw。PDF Arranger 是一个简单的、轻量级的工具,当你不需要改变文本时,可以用它来处理页面。Okular 为多种文件类型提供了很好的查看功能,如果你想在 PDF 中画草图和做笔记,Xournal++ 是最佳选择。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@@ -76,7 +75,7 @@ via: https://opensource.com/article/22/6/open-source-pdf-editors-linux
|
||||
作者:[Michael Korotaev][a]
|
||||
选题:[lkxed][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/) 荣誉推出
|
||||
|
||||
@@ -3,44 +3,40 @@
|
||||
[#]: author: "sk https://ostechnix.com/author/sk/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-14744-1.html"
|
||||
|
||||
在 Linux 上使用 WineZGUI 运行 Windows 应用和游戏
|
||||
======
|
||||
WineZGUI - 一个使用 Zenity 的 Wine GUI 前台
|
||||
|
||||
不久前,我们写了关于 **[Bottles][1]** 的文章,这是一个开源的图形应用,可以在 Linux 操作系统上轻松运行 Windows 软件和游戏。今天,我们将讨论一个类似的有趣项目。向 **WineZGUI** 打个招呼,它是一个 Wine GUI 前台,可以**[在 Linux 上用 Wine 运行 Windows 应用和游戏][2]**。
|
||||

|
||||
|
||||
> WineZGUI - 一个使用 Zenity 的 Wine GUI 前台
|
||||
|
||||
#### 内容
|
||||
|
||||
1. 什么是 WineZGUI?
|
||||
2. Bottles 与 WineZGUI
|
||||
3. 如何在 Linux 中安装 WineZGUI
|
||||
4. 在 Linux 中用 WineZGUI 运行 Windows 应用和游戏
|
||||
5. 总结
|
||||
不久前,我们写了关于 [Bottles][1] 的文章,这是一个开源的图形应用,可以在 Linux 操作系统上轻松运行 Windows 软件和游戏。今天,我们将讨论一个类似的有趣项目。向 **WineZGUI** 打个招呼,它是一个 Wine GUI 前台,可以 [在 Linux 上用 Wine 运行 Windows 应用和游戏][2]。
|
||||
|
||||
### 什么是 WineZGUI?
|
||||
|
||||
WineZGUI 是一个 Bash 脚本的集合,它允许你轻松地管理 wine 前缀,并在 Linux 上使用 **Zenity** 提供更容易的 wine 游戏体验。
|
||||
WineZGUI 是一个 Bash 脚本的集合,它允许你轻松地管理 Wine 前缀,并在 Linux 上使用 **Zenity** 提供更轻松的 Wine 游戏体验。
|
||||
|
||||
使用 WineZGUI,我们可以直接从文件管理器中启动 Windows exe 文件或游戏,而无需安装它们。
|
||||
(LCTT 译注:Wine 前缀是一个特殊文件夹,Wine 在其中放置所有 Wine 特定的文件,安装 Windows 程序、库和注册表代码,以及用户首选项。)
|
||||
|
||||
WineZGUI 为每个应用或游戏创建快捷方式,以便于访问,同时也为每个 exe 二进制文件创建单独的前缀。
|
||||
使用 WineZGUI,我们可以直接从文件管理器中启动 Windows EXE 文件或游戏,而无需安装它们。
|
||||
|
||||
当你用 WineZGUI 启动一个 Windows exe 文件时,它会提示你是否使用默认的 wine 前缀或创建一个新的前缀。默认的前缀是 `~/.local/share/winezgui/default`。
|
||||
WineZGUI 为每个应用或游戏创建快捷方式,以便于访问,同时也为每个 EXE 二进制文件创建单独的前缀。
|
||||
|
||||
如果你选择为 windows 二进制文件或 exe 创建一个新的前缀,WineZGUI 将尝试从 exe 文件中提取产品名称和图标,并创建一个桌面快捷方式。
|
||||
当你用 WineZGUI 启动一个 Windows EXE 文件时,它会提示你是否使用默认的 Wine 前缀或创建一个新的前缀。默认的前缀是 `~/.local/share/winezgui/default`。
|
||||
|
||||
当你以后启动相同的 exe 或二进制文件时,它将建议你用先前的相关前缀来运行它。
|
||||
如果你选择为 Windows 二进制文件(EXE)创建一个新的前缀,WineZGUI 将尝试从 EXE 文件中提取产品名称和图标,并创建一个桌面快捷方式。
|
||||
|
||||
说得通俗一点,WineZGUI 只是一个用于官方原始 wine 的 Wine 和 winetricks 的简单 GUI。当我们启动一个 exe 来玩游戏时,Wine 前缀的设置是自动的。
|
||||
当你以后启动相同的二进制文件(EXE)时,它将建议你用先前的相关前缀来运行它。
|
||||
|
||||
你只需打开一个 exe,它就会创建一个前缀和一个桌面快捷方式,并从该 exe 中提取名称和图标。
|
||||
说得通俗一点,WineZGUI 只是一个用于官方原始 Wine 的简单 GUI。当我们启动一个 EXE 来玩游戏时,Wine 前缀的设置是自动的。
|
||||
|
||||
它使用 **exiftool** 和 **icotool** 工具来分别提取名称和图标。你可以通过现有的前缀打开一个 exe 来启动该游戏,或者使用桌面快捷方式。
|
||||
你只需打开一个 EXE,它就会创建一个前缀和一个桌面快捷方式,并从该 EXE 中提取名称和图标。
|
||||
|
||||
它使用 `exiftool` 和 `icotool` 工具来分别提取名称和图标。你可以通过现有的前缀打开一个 EXE 来启动该游戏,或者使用桌面快捷方式。
|
||||
|
||||
WineZGUI 是一个在 GitHub 上免费托管的 shell 脚本。你可以抓取源代码,改进它,修复错误和增加功能。
|
||||
|
||||
@@ -48,30 +44,30 @@ WineZGUI 是一个在 GitHub 上免费托管的 shell 脚本。你可以抓取
|
||||
|
||||
你可能想知道 WineZGUI 与 Bottles 相比如何。但这些应用之间有一个微妙的区别。
|
||||
|
||||
**Bottles 是面向前缀的**和**面向运行器的**。意思是:Bottles 首先创建一个前缀,然后使用不同的 exe 文件。Bottles 不会记住 exe 的前缀。Bottles 使用不同的运行器。
|
||||
**Bottles 是面向前缀的**和**面向运行器的**。意思是:Bottles 首先创建一个前缀,然后使用不同的 EXE 文件。Bottles 不会记住 EXE 的前缀。Bottles 使用不同的运行器。
|
||||
|
||||
**WineZGUI 是面向 exe 的**。它使用 exe 只为该 exe 创建一个前缀。下次我们打开一个 exe 时,它将询问是否用现有的 exe 前缀启动。
|
||||
**WineZGUI 是面向 EXE 的**。它使用 EXE 并只为该 EXE 创建一个前缀。下次我们打开一个 EXE 时,它将询问是否用现有的 EXE 前缀启动。
|
||||
|
||||
WineZGUI 不提供像 **bottles** 或 **[lutris][3]** 那样的高级功能,如运行程序、在线安装程序等。
|
||||
WineZGUI 不提供像 Bottles 或 [lutris][3] 那样的高级功能,如运行程序、在线安装程序等。
|
||||
|
||||
### 如何在 Linux 中安装 WineZGUI
|
||||
|
||||
确保你已经安装了 WineZGUI 的必要先决条件。
|
||||
|
||||
**Debian/Ubuntu:**
|
||||
Debian/Ubuntu:
|
||||
|
||||
```
|
||||
$ sudo dpkg --add-architecture i386
|
||||
$ sudo apt install zenity wine winetricks libimage-exiftool-perl icoutils gnome-terminal
|
||||
```
|
||||
|
||||
**Fedora:**
|
||||
Fedora:
|
||||
|
||||
```
|
||||
$ sudo dnf install zenity wine winetricks perl-Image-ExifTool icoutils gnome-terminal
|
||||
```
|
||||
|
||||
官方推荐的安装 WineZGUI 的方法是使用 **[Flatpak][4]**。
|
||||
官方推荐的安装 WineZGUI 的方法是使用 [Flatpak][4]。
|
||||
|
||||
安装完 Flatpak 后,逐一运行以下命令,在 Linux 中安装 WineZGUI。
|
||||
|
||||
@@ -107,12 +103,12 @@ $ flatpak --user -y install io.github.WineZGUI_0_4_20220608.flatpak
|
||||
* 打开 Winetricks GUI 和 CLI。
|
||||
* 启动 Wine 配置。
|
||||
* 启动资源管理器。
|
||||
* 打开 BASH shell。
|
||||
* 打开 BASH Shell。
|
||||
* 关闭所有的应用/游戏,包括 WineZGUI 界面。
|
||||
* 删除 wine 前缀。
|
||||
* 删除 Wine 前缀。
|
||||
* 查看已安装的 WineZGUI 版本。
|
||||
|
||||
为了演示,我将打开一个 .exe 文件。
|
||||
为了演示,我将打开一个 EXE 文件。
|
||||
|
||||
在下一个窗口中,选择要运行的 EXE 文件。在我的例子中,它是 WinRAR。
|
||||
|
||||
@@ -126,11 +122,11 @@ $ flatpak --user -y install io.github.WineZGUI_0_4_20220608.flatpak
|
||||
|
||||
![Install WinRAR In Linux][9]
|
||||
|
||||
点击 OK 来完成 WinRAR 的安装。
|
||||
点击 “OK” 来完成 WinRAR 的安装。
|
||||
|
||||
![Complete WinRAR Installation][10]
|
||||
|
||||
点击“运行 WinRAR” 来启动它。
|
||||
点击 “<ruby>运行 WinRAR<rt>Run WinRAR</rt></ruby>” 来启动它。
|
||||
|
||||
![Run WinRAR][11]
|
||||
|
||||
@@ -140,13 +136,13 @@ $ flatpak --user -y install io.github.WineZGUI_0_4_20220608.flatpak
|
||||
|
||||
### 总结
|
||||
|
||||
WineZGUI 是俱乐部的新人。 如果你正在寻找一种在 Linux 桌面上使用 Wine 运行 Windows 应用和游戏的更简单方法,WineZGUI 可能是一个不错的选择。
|
||||
WineZGUI 是俱乐部的新人。如果你正在寻找一种在 Linux 桌面上使用 Wine 运行 Windows 应用和游戏的更简单方法,WineZGUI 可能是一个不错的选择。
|
||||
|
||||
在 WineZGUI 的帮助下,用户可以选择在与 `.exe` 相同的文件夹中创建一个 wine 前缀,并创建一个相对链接的 `.desktop` 条目来自动执行此操作。
|
||||
在 WineZGUI 的帮助下,用户可以选择在与 EXE 相同的文件夹中创建一个 Wine 前缀,并创建一个相对链接的 `.desktop` 条目来自动执行此操作。
|
||||
|
||||
原因是使用 wine 前缀备份和删除游戏更容易,并且让它生成一个 `.desktop` 将使其能够适应移动和转移。
|
||||
原因是使用 Wine 前缀备份和删除游戏更容易,并且让它生成一个 `.desktop` 将使其能够适应移动和转移。
|
||||
|
||||
一个很酷的场景是使用应用进行设置,然后将 wine 前缀分享给你的朋友和其他人,他们只需要一个具有所有依赖性和保存的工作 wine 前缀。
|
||||
一个很酷的场景是使用该应用进行设置,然后将 Wine 前缀分享给你的朋友和其他人,他们只需要一个具有所有依赖性和保存的工作 Wine 前缀。
|
||||
|
||||
请试一试它,在下面的评论区告诉我们你对这个项目的看法。
|
||||
|
||||
@@ -161,7 +157,7 @@ via: https://ostechnix.com/winezgui-run-windows-apps-and-games-on-linux/
|
||||
作者:[sk][a]
|
||||
选题:[lkxed][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,89 @@
|
||||
[#]: subject: "Ubuntu Runs on a Google Nest Hub, Wait, What?"
|
||||
[#]: via: "https://news.itsfoss.com/ubuntu-google-nest/"
|
||||
[#]: author: "Ankush Das https://news.itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "lkxed"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-14746-1.html"
|
||||
|
||||
Ubuntu 可以运行在谷歌 Nest Hub 上了?!
|
||||
======
|
||||
|
||||
> 一名安全专家成功地在谷歌 Nest Hub(第 2 代)上运行了 Ubuntu,嗯,然后呢?
|
||||
|
||||
![Ubuntu Google][1]
|
||||
|
||||
我刚刚看到了一个关于在谷歌 Nest Hub(第 2 代)上运行的 Ubuntu 的消息。
|
||||
|
||||
嗯,这实在是让人兴奋!
|
||||
|
||||
所以,让我在这里分享更多关于它的信息吧。
|
||||
|
||||
### 破解谷歌 Nest Hub 以安装 Ubuntu
|
||||
|
||||
是的,破解使得这成为可能。
|
||||
|
||||
网络安全专家 Frédéric Basse 破解了谷歌 Nest Hub(第 2 代)的安全启动,并成功运行 Ubuntu。
|
||||
|
||||
当然,谷歌 Nest Hub 并没有正式支持启动一个自定义操作系统。但是,Fred 使用了一个安全漏洞,从而成功运行了 Ubuntu。
|
||||
|
||||
虽然这很有趣,但对于始终在线的谷歌智能家居显示器来说,这也是一个严重的安全问题。
|
||||
|
||||

|
||||
|
||||
正如这位安全专家在 [博客文章][2] 中所解释的,他使用了树莓派 Pico 微控制器,利用引导加载程序中的 USB 漏洞,从而破坏了安全启动链。
|
||||
|
||||
这位安全专家得出结论:
|
||||
|
||||
> 因此,攻击者可以通过插入恶意 USB 设备并按下两个按钮,从而在早期启动阶段(内核执行之前)执行任意代码。
|
||||
|
||||
如果你想进行实验(适合安全研究人员),他还在 [GitHub][3] 上提供了相关代码(关于如何利用这个引导加载程序漏洞)。
|
||||
|
||||
### 让 Ubuntu 在 Google Nest 上运行
|
||||
|
||||
![][4]
|
||||
|
||||
该漏洞允许攻击者启动未签名的操作系统。但是,在那之前,攻击者必须对为树莓派(64 位 ARM 版)量身定制的预装 Ubuntu 镜像进行一些修改。
|
||||
|
||||
这位安全专家还提到了以下内容:
|
||||
|
||||
> 我们构建了一个自定义 U-Boot 引导加载程序,禁用了安全引导,并更改了引导流程以从 USB 闪存驱动器加载环境。我们还为 elaine 构建了一个自定义 Linux 内核,其中包括包括了一些 [额外驱动,例如 USB 鼠标][5] 。重新打包了来自 Ubuntu 的初始 ramdisk(initrd),以集成触摸屏所需的固件二进制文件。引导镜像是基于自定义 Linux 内核和修改的 initrd 创建的。
|
||||
|
||||
因此,很明显,你不会获得完整的 Ubuntu 体验,但由于该漏洞,我们现在知道,如果你愿意破解 谷歌 Nest 进行测试的话(真心不建议!),Ubuntu 是可以在谷歌 Nest 上作运行的。
|
||||
|
||||
### 智能家居安全担忧 + Linux
|
||||
|
||||
网络安全专家指出,该漏洞已在上游(两次)修复。
|
||||
|
||||
但是,研究人员也指出,缺乏分配的 CVE 编号可能会导致修复程序无法向下游传播。
|
||||
|
||||
毫无疑问,看到有人在不受支持的设备上运行 Linux 真是太棒了。这让我思考,我们是否应该也制造一些 **由 Linux 驱动的商业智能家居设备?**
|
||||
|
||||
*或者说,已经有类似的东西了吗?*
|
||||
|
||||
然而,智能家居设备容易受到简单攻击,也同样令人担忧。
|
||||
|
||||
你怎么看?在下面的评论中分享你的想法吧。
|
||||
|
||||
**本文最初发布于** [Liliputing][6]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/ubuntu-google-nest/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[lkxed](https://github.com/lkxed)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://news.itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://news.itsfoss.com/wp-content/uploads/2022/06/hacker-installs-ubuntu-on-google-nest-hub.jpg
|
||||
[2]: https://fredericb.info/2022/06/breaking-secure-boot-on-google-nest-hub-2nd-gen-to-run-ubuntu.html
|
||||
[3]: https://github.com/frederic/chipicopwn
|
||||
[4]: https://news.itsfoss.com/wp-content/uploads/2022/06/ubuntu-google-nest.jpg
|
||||
[5]: https://github.com/frederic/elaine-linux/commit/11068237d9178e77d79e3a5d27fc4f8f9b923c51
|
||||
[6]: https://liliputing.com/2022/06/hacker-installs-ubuntu-on-a-google-nest-hub-2nd-gen-smart-display.html
|
||||
@@ -0,0 +1,108 @@
|
||||
[#]: subject: "Compress Images in Linux Easily With Curtail GUI App"
|
||||
[#]: via: "https://itsfoss.com/curtail-image-compress/"
|
||||
[#]: author: "Abhishek Prakash https://itsfoss.com/author/abhishek/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-14748-1.html"
|
||||
|
||||
用 Curtail GUI 应用轻松压缩 Linux 中的图像
|
||||
======
|
||||
|
||||

|
||||
|
||||
有一大堆文件尺寸巨大的图片占用了太多的磁盘空间?或者你必须将图片上传到有文件大小限制的门户网站?
|
||||
|
||||
你可能有很多原因想要压缩图片。有大量的工具可以帮助你,我在这里说的不是命令行的工具。
|
||||
|
||||
你可以使用一个成熟的图像编辑器,如 GIMP。你也可以使用像 [Squoosh][1] 这样的网络工具,这是谷歌的一个开源项目。它甚至可以让你比较每个压缩级别的文件。
|
||||
|
||||
然而,所有这些工具都是针对单个图像工作的。如果你想批量压缩照片怎么办?Curtail 是一个能帮助你的应用。
|
||||
|
||||
### Curtail: Linux 中用于图像压缩的灵巧工具
|
||||
|
||||
使用 Python 和 GTK3 构建的 Curtail 是一个简单的 GUI 应用,使用 OptiPNG、[jpegoptim][2] 等开源库来提供图像压缩功能。
|
||||
|
||||
它有一个 [Flatpak 应用][3]。请确保你的系统已启用 [Flatpak 支持][4]。
|
||||
|
||||
首先添加 Flathub 仓库:
|
||||
|
||||
```
|
||||
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
```
|
||||
|
||||
然后使用下面的命令来安装 Curtail:
|
||||
|
||||
```
|
||||
flatpak install flathub com.github.huluti.Curtail
|
||||
```
|
||||
|
||||
安装后,在你的 Linux 系统的菜单中寻找它,并从那里启动它。
|
||||
|
||||
![curtail app][5]
|
||||
|
||||
界面朴素而简单。你可以选择你想要无损压缩还是有损压缩。
|
||||
|
||||
有损压缩会有质量差的图像,但尺寸较小。无损压缩会有更好的质量,但尺寸可能不会比原来的小很多。
|
||||
|
||||
![curtail app interface][6]
|
||||
|
||||
你可以浏览图片,或者把它们拖到应用中。
|
||||
|
||||
是的,你可以用 Curtail 一键压缩多张图片。
|
||||
|
||||
事实上,你甚至不需要点击。只要你选择图片或拖放它们,它们就会被压缩,你会看到压缩过程的摘要。
|
||||
|
||||
![curtail image compression summary][7]
|
||||
|
||||
正如你在上面的图片中看到的,我的一张图片的尺寸减少了 35%,另外两张图片的尺寸减少了 3% 和 8%。这是在无损压缩的情况下。
|
||||
|
||||
这些图片以 `-min` 为后缀(默认),保存在与原始图片相同的目录中。
|
||||
|
||||
虽然它看起来很简约,但有几个选项可以配置 Curtail。点击菜单,你会看到一些设置选项。
|
||||
|
||||
![curtail configuration options][8]
|
||||
|
||||
你可以选择是将压缩文件保存为新文件还是替换现有文件。如果你选择新文件(默认行为),你也可以为压缩后的图像提供一个不同的后缀。保留文件属性的选项也在这里。
|
||||
|
||||
在下一个选项卡中,你可以配置有损压缩的设置。默认情况下,压缩级别为 90%。
|
||||
|
||||
![curtail compression options][9]
|
||||
|
||||
高级选项卡让你可以选择配置 PNG 和 WebP 文件的无损压缩级别。
|
||||
|
||||
![curtain advanced options][10]
|
||||
|
||||
### 总结
|
||||
|
||||
正如我前面所说,这不是一个突破性的工具。你可以用其他工具如 GIMP 做同样的事情。它只是使图像压缩的任务更简单,特别是对于批量图像压缩。
|
||||
|
||||
我很想看到在压缩时有[转换图像文件格式][11]的选项,就像我们在 Converseen 等工具中所拥有的那样。
|
||||
|
||||
总的来说,对于图像压缩的具体目的来说,这是一个不错的小工具。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/curtail-image-compress/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lkxed][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/lkxed
|
||||
[1]: https://squoosh.app/
|
||||
[2]: https://github.com/tjko/jpegoptim
|
||||
[3]: https://itsfoss.com/what-is-flatpak/
|
||||
[4]: https://itsfoss.com/flatpak-guide/
|
||||
[5]: https://itsfoss.com/wp-content/uploads/2022/06/curtail-app.png
|
||||
[6]: https://itsfoss.com/wp-content/uploads/2022/06/curtail-app-interface.png
|
||||
[7]: https://itsfoss.com/wp-content/uploads/2022/06/curtail-image-compression-summary.png
|
||||
[8]: https://itsfoss.com/wp-content/uploads/2022/06/curtail-configuration-options.png
|
||||
[9]: https://itsfoss.com/wp-content/uploads/2022/06/curtail-compression-options.png
|
||||
[10]: https://itsfoss.com/wp-content/uploads/2022/06/curtain-advanced-options.png
|
||||
[11]: https://itsfoss.com/converseen/
|
||||
@@ -0,0 +1,92 @@
|
||||
[#]: subject: "Manjaro 21.3.0 ‘Ruah’ Release Adds Latest Calmares 3.2, GNOME 42, and More Upgrades"
|
||||
[#]: via: "https://news.itsfoss.com/manjaro-21-3-0-release/"
|
||||
[#]: author: "Ankush Das https://news.itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "lkxed"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-14754-1.html"
|
||||
|
||||
Manjaro 21.3.0 Ruah 发布:增加了最新的 Calmares 3.2、GNOME 42 和更多升级
|
||||
======
|
||||
|
||||
> Manjaro Linux 21.3.0 发行包包含一些最新和最强大的更新,包括改进的安装程序。
|
||||
|
||||

|
||||
|
||||
Manjaro Linux 是一个滚动发布的发行版。因此,从技术上讲,如果你定期更新系统的话,你一直都会使用最新版本。
|
||||
|
||||
升级到 Manjaro 21.3.0 应该没什么大不了的,考虑到我已经在正式发布前几天就已经在稳定运行它了,毫无问题。
|
||||
|
||||
**另外**,你可能想阅读一下我 [从 Ubuntu 切换到 Manjaro][2] 的初步体验(如果你对于升级仍然犹豫不决的话)。
|
||||
|
||||
那么,Manjaro 21.3.0 带来了什么更新呢?
|
||||
|
||||
### Manjaro 21.3.0 更新内容
|
||||
|
||||
![][3]
|
||||
|
||||
桌面环境升级到了最新的稳定版本,而内核版本仍然是 [Linux 内核 5.15 LTS][4]。
|
||||
|
||||
此外,这个版本还包括最终的 Clamares v3.2 版本。让我们来看看它有哪些变化吧。
|
||||
|
||||
#### Calamares v3.2.59
|
||||
|
||||
Calamares v3.2.59 安装程序是 3.2 系列的最终版本,它有许多有意义的改进。这次,分区模块包含了对 LUKS 分区的支持和更多改进,以避免那些可能会弄乱 Manjaro 安装的设置。
|
||||
|
||||
Calamares 3.2 的所有未来版本都将仅是错误修复。
|
||||
|
||||
#### GNOME 42 + Libadwaita
|
||||
|
||||
最初的版本包含了 GNOME 42,而最新的版本包含了 GNOME 42.2(附带最新的更新)。
|
||||
|
||||
总体而言,你将获得 [GNOME 42][5] 引入的所有优点,包括系统范围的深色模式、基于 GTK 4 的 GNOME 应用的现代用户界面、升级的应用程序以及其他一些重大变化。
|
||||
|
||||
![][6]
|
||||
|
||||
#### KDE Plasma 5.24
|
||||
|
||||
不幸的是,考虑到它差不多是在同一周发布的,因此该版本无法包含 [KDE Plasma 5.25][7]。
|
||||
|
||||
[KDE Plasma 5.24][8] 是一个不错的升级,具有更新的主题和概览效果。
|
||||
|
||||
#### XFCE 4.16
|
||||
|
||||
在 Xfce 4.16 中,窗口管理器得到了许多更新和改进,以支持小数倍数的缩放和更多功能。
|
||||
|
||||
### 下载 Manjaro 21.3.0
|
||||
|
||||
到目前为止,我在 Manjaro 21.3.0 GNOME 版本中没有遇到任何问题。一切看起来都不错,升级也很顺利。
|
||||
|
||||
但是,如果你不想重新安装或丢失重要文件,则应始终进行备份。
|
||||
|
||||
你可以从 [Manjaro 的下载页面][9] 下载最新版本。你也应该可以通过 pamac 包管理器获得更新。
|
||||
|
||||
无论哪种情况,你都可以在终端中输入以下命令进行升级:
|
||||
|
||||
```
|
||||
sudo pacmane -Syu
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/manjaro-21-3-0-release/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[lkxed](https://github.com/lkxed)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://news.itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://news.itsfoss.com/wp-content/uploads/2022/06/manjaro-21-3-0-ruah-release.jpg
|
||||
[2]: https://news.itsfoss.com/manjaro-linux-experience/
|
||||
[3]: https://news.itsfoss.com/wp-content/uploads/2022/06/manjaro-gnome-42-2-1024x576.jpg
|
||||
[4]: https://news.itsfoss.com/linux-kernel-5-15-release/
|
||||
[5]: https://news.itsfoss.com/gnome-42-release/
|
||||
[6]: https://news.itsfoss.com/wp-content/uploads/2022/06/manjaro-21-3-neofetch.png
|
||||
[7]: https://news.itsfoss.com/kde-plasma-5-25-release/
|
||||
[8]: https://news.itsfoss.com/kde-plasma-5-24-lts-release/
|
||||
[9]: https://manjaro.org/download/
|
||||
@@ -0,0 +1,40 @@
|
||||
[#]: subject: "Microsoft To Charge For Available Open Source Software In Microsoft Store"
|
||||
[#]: via: "https://www.opensourceforu.com/2022/06/microsoft-to-charge-for-available-open-source-software-in-microsoft-store/"
|
||||
[#]: author: "Laveesh Kocher https://www.opensourceforu.com/author/laveesh-kocher/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "lkxed"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-14755-1.html"
|
||||
|
||||
微软将对应用商店中开源软件的收费进行限制
|
||||
======
|
||||
|
||||

|
||||
|
||||
2022 年 6 月 16 日,微软更新了其应用商店的策略。其中一项禁止了发布者对开源或免费的软件收取费用,另一项则针对的是商店使用的不合理高价。如果你在过去几年中访问过微软应用商店,你可能已经注意到,它正在成为越来越多的开源和免费产品的所在地。如果原始开发者将应用程序和游戏上传到商店,这将是有益的,但情况并非如此,因为它们是由第三方上传的。
|
||||
|
||||
更糟糕的是,其中许多程序仅作为付费应用提供,而不是免费下载。换句话说,微软的客户必须付费才能购买应用商店的版本,而它们在其他地方是免费的!在应用商店中,免费版和付费版有时并存。为免费应用付费已经够糟糕的了,但这并不是用户在购买时可能遇到的唯一问题。更新也可能是一个问题,因为山寨应用可能不会像源头应用程序那样频繁或快速地更新。
|
||||
|
||||
在更新的微软商店政策中,微软在 10.8.7 节下指出:
|
||||
|
||||
> 在您决定产品或应用内购买的定价时,您的数字产品或服务的所有定价(包括销售或折扣)必须:
|
||||
>
|
||||
> 遵守所有适用的法律、法规和监管要求,包括联邦贸易委员会的《反欺骗性定价指南》。您不得试图从开源软件或其他可免费获得的软件中获利,您的产品也不应提供一个(与它提供的特性和功能相比)过高的不合理定价。
|
||||
|
||||
这个新策略在更新部分中得到了确认。如果开源和免费产品普遍免费提供,则它们不得在微软应用商店上出售,发布者也不得对其产品收取不合理的高价。开源和免费应用的开发者可以在微软应用商店上为其产品收费。例如,Paint.net 的开发者就是这样做的。如果微软强制执行这些策略,许多应用将从应用商店中删除。以前,开发者可以向微软报告应用程序,但在新策略下,微软可以直接控制应用的列出和提交。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.opensourceforu.com/2022/06/microsoft-to-charge-for-available-open-source-software-in-microsoft-store/
|
||||
|
||||
作者:[Laveesh Kocher][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[lkxed](https://github.com/lkxed)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.opensourceforu.com/author/laveesh-kocher/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://www.opensourceforu.com/wp-content/uploads/2022/06/microsoft-e1655714723942.jpg
|
||||
@@ -0,0 +1,76 @@
|
||||
[#]: subject: "Mysterious GeckoLinux Creator Reveals a New Debian Remix Distro"
|
||||
[#]: via: "https://news.itsfoss.com/debian-remix-spiral-linux/"
|
||||
[#]: author: "Ankush Das https://news.itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "lkxed"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-14758-1.html"
|
||||
|
||||
神秘的 GeckoLinux 创建者推出了一个新的 Debian 合成发行版
|
||||
======
|
||||
|
||||
> GeckoLinux 创建者推出了一个基于 Debian 的新 Linux 发行版,专注于简单性和可用性。
|
||||
|
||||
![Linux 螺旋][1]
|
||||
|
||||
GeckoLinux 改进了的 openSUSE 体验,它的创建者一直保持匿名。
|
||||
|
||||
我不会评论这是好事还是坏事,但现在,开发者又带着另一个基于 Debian 的类似项目回来了。
|
||||
|
||||
**SpiralLinux**,这是一个基于 Debian 的发行版,旨在使 Debian 适合最终用户使用。
|
||||
|
||||
### SpiralLinux:基于 Debian 构建的发行版
|
||||
|
||||
![SpiralLinux][2]
|
||||
|
||||
毫不奇怪,大多数用户友好的 Linux 发行版都将 Debian 作为其原始基础。Ubuntu 就是在此基础上进行了大量改进,从而提供了良好的桌面体验,即使对于没有 Linux 经验的用户也是如此。
|
||||
|
||||
那么,这个发行版有什么不同呢?
|
||||
|
||||
嗯,它的创建者说,这个项目旨在帮助你获得 Debian 的所有核心优势,而无需定制很多东西。
|
||||
|
||||
如果你想在桌面上使用 Debian,SpiralLinux 是一种接近原版的体验。你还可以根据需要升级到最新的稳定 Debian 版本(或不稳定/测试版),而不会丢失方便易用的自定义设置。
|
||||
|
||||
换句话说,SpiralLinux 使 Debian 适合桌面使用,而最终用户只需付出最小的努力。
|
||||
|
||||
为了实现这一点,SpiralLinux 使用了 Debian 官方软件包存储库,并提供了现场安装方式,让你能够定制自己的 Debian 系统。
|
||||
|
||||
此外,SpiralLinux 还具有以下功能:
|
||||
|
||||
* 开箱即用的 VirtualBox 支持
|
||||
* 预装了专有的媒体编解码器和非自由软件包存储库
|
||||
* 预装了专有固件
|
||||
* 打印机支持
|
||||
* 通过 GUI(软件中心)支持 Flatpak
|
||||
* 默认启用 zRAM 交换
|
||||
* 多种桌面环境(Cinnamon、XFCE、Gnome、Plasma、MATE、Budgie、LXQt)
|
||||
|
||||
Debian 始终坚持使用开源和自由软件包,最终用户必须自己搞定编解码器、驱动程序和其他软件包,才能使许多功能正常工作,获得令他们满意的桌面体验。
|
||||
|
||||
而 SpiralLinux 似乎可以作为 Debian 的一个有用的替代品,就像 GeckoLinux 之于 openSUSE 一样。
|
||||
|
||||
### 下载 SpiralLinux
|
||||
|
||||
如果你一直想尝试 Debian,但又不想在初始配置上费尽心思,你可以尝试 SpiralLinux。
|
||||
|
||||
你可以前往其托管在 GitHub 上的官网以了解更多信息,链接如下:
|
||||
|
||||
> **[SpiralLinux][3]**
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/debian-remix-spiral-linux/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[lkxed](https://github.com/lkxed)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://news.itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://news.itsfoss.com/wp-content/uploads/2022/06/spiral-linux-debian-remix-distro.jpg
|
||||
[2]: https://news.itsfoss.com/wp-content/uploads/2022/06/spirallinux.jpg
|
||||
[3]: https://spirallinux.github.io/
|
||||
@@ -0,0 +1,91 @@
|
||||
[#]: subject: "GitHub Copilot is Now Available for All and Not Everyone Likes It"
|
||||
[#]: via: "https://news.itsfoss.com/github-copilot/"
|
||||
[#]: author: "Jacob Crume https://news.itsfoss.com/author/jacob/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "lkxed"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-14759-1.html"
|
||||
|
||||
GitHub Copilot 现已可供所有人使用,但并非所有人都喜欢它
|
||||
======
|
||||
|
||||
> GitHub Copilot 来了,它能帮助程序员,为他们提供人工智能的编码建议,不过,它是否会让事情变得更糟呢?
|
||||
|
||||
![GitHub][1]
|
||||
|
||||
在 2021 年,我曾花了好几个小时来翻阅 GitHub Copilot 文档,试图弄清楚如何能够加入它的技术预览计划。还好,这一切都得到了回报,我成功加入了预览计划。
|
||||
|
||||
而现在,它终于可供所有人使用啦!
|
||||
|
||||
如果你还不知道的话,[GitHub Copilot][2] 是一个 AI 助手,可帮助你更快、更高效地编写代码。
|
||||
|
||||
我能想到的最类似的东西,就是你手机上的(输入法的)自动完成功能。不过,与自动完成功能不同,GitHub Copilot 编写代码,就相当于是在完成整段的句子。
|
||||
|
||||
### Copilot 现已可供大众使用
|
||||
|
||||
正如我在前面提到的,Copilot 已经处于技术预览阶段将近一年了。这意味着,GitHub 只允许非常有限数量的开发者免费使用它,以换取同意 GitHub 监控他们的使用情况,从而改进程序的最终版本。
|
||||
|
||||
看起来 GitHub 终于满意地向公众发布了它。现在,任何拥有 GitHub 帐户的人都应该能够使用它,尽管需要付出一定的代价(我很快就会在下面提到)。
|
||||
|
||||
[公告][3] 中提到:
|
||||
|
||||
> 直到不久前,人工智能都没有能够帮助改进代码,开发软件的过程几乎完全是手动的。现在,这种情况正在改变。今天,我很高兴地宣布,我们正在向所有个人开发者提供 [GitHub Copilot][4]。你的 AI 配对程序员来啦。
|
||||
>
|
||||
> —— [Thomas Dohmke][5],GitHub CEO
|
||||
|
||||
Copilot 作为免费的编辑器扩展,已经帮助数百万开发者加快了他们的编程速度。然而,它确实是有代价的,无论是直接的还是间接的。
|
||||
|
||||
### GitHub Copilot 定价
|
||||
|
||||
与几乎所有令人兴奋的新技术一样,Copilot 对某些人来说可能过于昂贵。它将花费你 10 美元/月或 100 美元/年。
|
||||
|
||||
如果你是开源项目维护者或经过验证的学生,那么你可以免费使用它。
|
||||
|
||||
### GitHub Copilot 不道德吗?
|
||||
|
||||
围绕 GitHub Copilot 产品的争议巨大且令人担忧。从技术上讲,这个人工智能是使用大家托管在 GitHub 上的代码来进行训练的。
|
||||
|
||||
因此,基本上,GitHub 是通过使用你的代码来提供一个新产品(如果你愿意的话,还可以加点料)。而且,关于 Copilot,可别忘了,自由软件基金会(FSF)也 [建议][6] 不要在 GitHub 上托管代码。
|
||||
|
||||
我们知道,企业总是喜欢利用事物,但有些人认为这应该不会直接损害托管在 GitHub 上的项目/代码。
|
||||
|
||||
**但是,是这样吗?**
|
||||
|
||||
简而言之,在 Copilot 发布后,许多开发者都分享说,他们发现 GitHub Copilot 生成了受版权保护的代码:
|
||||
|
||||
> 我试了下 GitHub Copilot,这是一项付费服务,来看看它是否会使用带有限制性许可证的存储库的代码。我检查了它,看看它是否有我在之前雇主那里编写的代码,该代码有一个许可证,只允许其用于免费游戏,并且需要附加许可证。是的,它确实有。
|
||||
|
||||
![图源:推特上的 Chris Green][7]
|
||||
|
||||
当然,如果我们查看 GitHub Copilot 的常见问题解答(FAQ),其中提到:
|
||||
|
||||
> GitHub 不拥有 GitHub Copilot 生成的建议。您在 GitHub Copilot 的帮助下编写的代码属于您自己,由您自己负责。
|
||||
|
||||
所以说,你为一项服务付了费,最终却为你的项目增加了不便和更多的工作?
|
||||
|
||||
在我看来,就简化开发者的任务而言,这听起来一点儿也不令人兴奋。
|
||||
|
||||
*你对此有什么想法?请在下面的评论区中分享一下吧!*
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/github-copilot/
|
||||
|
||||
作者:[Jacob Crume][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[lkxed](https://github.com/lkxed)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://news.itsfoss.com/author/jacob/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://news.itsfoss.com/wp-content/uploads/2022/06/github-copilot.jpg
|
||||
[2]: https://copilot.github.com/
|
||||
[3]: https://github.blog/2022-06-21-github-copilot-is-generally-available-to-all-developers/
|
||||
[4]: http://copilot.github.com
|
||||
[5]: https://github.blog/author/ashtom/
|
||||
[6]: https://www.fsf.org/blogs/licensing/fsf-funded-call-for-white-papers-on-philosophical-and-legal-questions-around-copilot
|
||||
[7]: https://pbs.twimg.com/media/FV45qM_VEAALLv6?format=png&name=medium
|
||||
[8]: https://twitter.com/ChrisGr93091552/status/1539731632931803137?ref_src=twsrc%5Etfw
|
||||
@@ -1,87 +0,0 @@
|
||||
[#]: subject: "Ubuntu Runs on a Google Nest Hub, Wait, What?"
|
||||
[#]: via: "https://news.itsfoss.com/ubuntu-google-nest/"
|
||||
[#]: author: "Ankush Das https://news.itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Ubuntu Runs on a Google Nest Hub, Wait, What?
|
||||
======
|
||||
A hacker successfully managed to run Ubuntu on a Google Nest Hub (2nd Gen), say, what now?
|
||||
|
||||
![ubuntu google][1]
|
||||
|
||||
I just spotted a story about Ubuntu running on a Google Nest Hub (2nd Gen).
|
||||
|
||||
Well, that is certainly exciting!
|
||||
|
||||
So, let me share more about it here.
|
||||
|
||||
### Hacking Google Nest Hub to Install Ubuntu
|
||||
|
||||
Yes, a hacking attempt made this possible.
|
||||
|
||||
A cybersecurity professional, **Frédéric Basse**, broke the secure boot on Google Nest Hub (2nd gen) and managed to run Ubuntu.
|
||||
|
||||
Of course, Google Nest Hub does not officially support booting a custom OS. But, a security vulnerability allowed Fred to use an exploit and run Ubuntu.
|
||||
|
||||
While this is fun, it is also a severe problem for an always-connected smart home display by Google.
|
||||
|
||||
As explained in his [blog post][2], the hacker utilized a Raspberry Pi Pico microcontroller to exploit a USB bug in the bootloader to break the secure boot chain.
|
||||
|
||||
The security expert concluded:
|
||||
|
||||
> As a result, an attacker can execute arbitrary code at early boot stage (before kernel execution) by plugging a malicious USB device and pressing two buttons
|
||||
|
||||
He has also made the bootloader exploit available on [GitHub][3], if you want to experiment (suited for security researchers).
|
||||
|
||||
### Making Ubuntu Work on Google Nest
|
||||
|
||||
![][4]
|
||||
|
||||
The exploit allowed the attacker to boot an unsigned OS. However, he had to make some modifications with the preinstalled Ubuntu image tailored for Raspberry Pi (64-bit ARM).
|
||||
|
||||
Here’s what he mentions about it:
|
||||
|
||||
> We build a custom U-Boot bootloader with secure boot disabled and boot flow altered to load environment from USB flash drive. We also build a custom Linux kernel for elaine with [additionnal d][5]r[ivers like USB mouse][6]. The initial ramdisk (initrd) from Ubuntu is repacked to integrate firmware binaries required for the touchscreen. The boot image is created based on the custom Linux kernel and modified initrd.
|
||||
|
||||
So, it is evident that you will not get a full-fledged Ubuntu experience, but thanks to the exploit, we now know that Ubuntu can run on a Google Nest as an experiment if you’re willing to break your Google Nest for the test (don’t do that, really!).
|
||||
|
||||
### Smart Home Security Concern + Linux
|
||||
|
||||
The cybersecurity expert mentions that the vulnerability has been fixed upstream (twice).
|
||||
|
||||
But, the lack of CVE may have influenced the fix not propagating downstream, as the researcher suggests.
|
||||
|
||||
Undoubtedly, seeing Linux running on an unsupported device is awesome. Makes me wonder if we should have someone make **commercial smart home devices powered by Linux?**
|
||||
|
||||
*Is there something like that already available?*
|
||||
|
||||
Nevertheless, it is equally concerning for smart home devices to be vulnerable to easy attacks.
|
||||
|
||||
What do you think? Share your thoughts in the comments down below.
|
||||
|
||||
**Via**: [Liliputing][7]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/ubuntu-google-nest/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://news.itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://news.itsfoss.com/wp-content/uploads/2022/06/hacker-installs-ubuntu-on-google-nest-hub.jpg
|
||||
[2]: https://fredericb.info/2022/06/breaking-secure-boot-on-google-nest-hub-2nd-gen-to-run-ubuntu.html
|
||||
[3]: https://github.com/frederic/chipicopwn
|
||||
[4]: https://news.itsfoss.com/wp-content/uploads/2022/06/ubuntu-google-nest.jpg
|
||||
[5]: https://github.com/frederic/elaine-linux/commit/11068237d9178e77d79e3a5d27fc4f8f9b923c51
|
||||
[6]: https://github.com/frederic/elaine-linux/commit/11068237d9178e77d79e3a5d27fc4f8f9b923c51
|
||||
[7]: https://liliputing.com/2022/06/hacker-installs-ubuntu-on-a-google-nest-hub-2nd-gen-smart-display.html
|
||||
@@ -1,91 +0,0 @@
|
||||
[#]: subject: "Manjaro 21.3.0 ‘Ruah’ Release Adds Latest Calmares 3.2, GNOME 42, and More Upgrades"
|
||||
[#]: via: "https://news.itsfoss.com/manjaro-21-3-0-release/"
|
||||
[#]: author: "Ankush Das https://news.itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Manjaro 21.3.0 ‘Ruah’ Release Adds Latest Calmares 3.2, GNOME 42, and More Upgrades
|
||||
======
|
||||
Manjaro Linux 21.3.0 release packs in some of the latest and greatest updates, including an improved installer.
|
||||
|
||||
![manjaro 21.3.0][1]
|
||||
|
||||
Manjaro Linux is a rolling-release distribution. So, technically, you will be on the latest version if you regularly update your system.
|
||||
|
||||
It should not be a big deal to upgrade to Manjaro 21.3.0, considering I am already running it without issues for a few days before the official announcement.
|
||||
|
||||
**Also,**you might want to read my initial experience [switching to Manjaro from Ubuntu][2] (if you’re still on the fence).
|
||||
|
||||
So, what does the Manjaro 21.3.0 upgrade introduce?
|
||||
|
||||
### Manjaro 21.3.0: What’s New?
|
||||
|
||||
![][3]
|
||||
|
||||
The desktop environments upgraded to their latest stable versions while the core [Linux Kernel 5.15 LTS][4] remains.
|
||||
|
||||
Also, this release includes the final Clamares v3.2 version. Let us take a look at the changes:
|
||||
|
||||
#### Calamares v3.2.59
|
||||
|
||||
Calamares v3.2.59 installer is the final release of the 3.2 series with meaningful improvements. This time the partition module includes support for LUKS partitions and more refinements to avoid settings that can mess up the Manjaro installation.
|
||||
|
||||
All the future releases for Calamares 3.2 will be bug fixes only.
|
||||
|
||||
#### GNOME 42 + Libadwaita
|
||||
|
||||
While the initial release included GNOME 42, now we have GNOME 42.2 available with the latest updates.
|
||||
|
||||
Overall, you get all the goodies introduced with [GNOME 42][5], including the system-wide dark mode, a modern user interface based on GTK 4 for GNOME apps, upgraded applications, and several other significant changes.
|
||||
|
||||
![][6]
|
||||
|
||||
#### KDE Plasma 5.24
|
||||
|
||||
Unfortunately, the release couldn’t feature [KDE Plasma 5.25][7], considering it was released around the same week.
|
||||
|
||||
[KDE Plasma 5.24][8] is a nice upgrade, with a refreshed theme and an overview effect.
|
||||
|
||||
#### XFCE 4.16
|
||||
|
||||
With Xfce 4.16, the window manager received numerous updates and refinements to support fractional scaling and more capabilities.
|
||||
|
||||
### Download Manjaro 21.3.0
|
||||
|
||||
As of now, I have no issues with Manjaro 21.3.0 GNOME edition. Everything looks good, and the upgrade went smoothly.
|
||||
|
||||
However, you should always take backups if you do not want to re-install or lose your important files.
|
||||
|
||||
You can download the latest version from [Manjaro’s download page][9]. The upgrade should be available through the pamac package manager.
|
||||
|
||||
In either case, you can enter the following command in the terminal to upgrade:
|
||||
|
||||
```
|
||||
sudo pacmane -Syu
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/manjaro-21-3-0-release/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://news.itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://news.itsfoss.com/wp-content/uploads/2022/06/manjaro-21-3-0-ruah-release.jpg
|
||||
[2]: https://news.itsfoss.com/manjaro-linux-experience/
|
||||
[3]: https://news.itsfoss.com/wp-content/uploads/2022/06/manjaro-gnome-42-2-1024x576.jpg
|
||||
[4]: https://news.itsfoss.com/linux-kernel-5-15-release/
|
||||
[5]: https://news.itsfoss.com/gnome-42-release/
|
||||
[6]: https://news.itsfoss.com/wp-content/uploads/2022/06/manjaro-21-3-neofetch.png
|
||||
[7]: https://news.itsfoss.com/kde-plasma-5-25-release/
|
||||
[8]: https://news.itsfoss.com/kde-plasma-5-24-lts-release/
|
||||
[9]: https://manjaro.org/download/
|
||||
@@ -1,39 +0,0 @@
|
||||
[#]: subject: "Microsoft To Charge For Available Open Source Software In Microsoft Store"
|
||||
[#]: via: "https://www.opensourceforu.com/2022/06/microsoft-to-charge-for-available-open-source-software-in-microsoft-store/"
|
||||
[#]: author: "Laveesh Kocher https://www.opensourceforu.com/author/laveesh-kocher/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Microsoft To Charge For Available Open Source Software In Microsoft Store
|
||||
======
|
||||
![microsoft][1]
|
||||
|
||||
On June 16, 2022, Microsoft updated the Microsoft Store policies. One of the changes prohibits publishers from charging fees for open source or freely available software. Another example is the store’s use of irrationally high pricing. If you’ve been to the Microsoft Store in the last few years, you’ve probably noticed that it’s becoming more and more home to open source and free products. While this would be beneficial if the original developer had uploaded the apps and games to the store, it is not the case because the uploads were made by third parties.
|
||||
|
||||
Worse, many of these programs are only available as paid applications rather than free downloads. In other words, Microsoft customers must pay to purchase a Store version of an app that is free elsewhere. In the Store, free and paid versions coexist at times. Paying for a free app is bad enough, but this isn’t the only problem that users may encounter when they make the purchase. Updates may also be a concern, as copycat programs may not be updated as frequently or as quickly as the source applications.
|
||||
|
||||
In the updated Microsoft Store Policies, Microsoft notes under 10.8.7:
|
||||
|
||||
In cases where you determine the pricing for your product or in-app purchases, all pricing for your digital products or services, including sales or discounts, must:
|
||||
|
||||
Comply with all applicable laws, regulations, and regulatory guidelines, including the Federal Trade Commission’s Guides Against Deceptive Pricing. You must not attempt to profit from open-source or other software that is otherwise freely available, nor should your product be priced irrationally high in comparison to the features and functionality it provides.
|
||||
|
||||
The new policies are confirmed in the updated section. Open source and free products may no longer be sold on the Microsoft Store if they are generally available for free, and publishers may no longer charge irrationally high prices for their products. Developers of open source and free applications may charge for their products on the Microsoft Store; for example, the developer of Paint.net does so. Many applications will be removed from the Store if Microsoft enforces the policies. Developers could previously report applications to Microsoft, but the new policies give Microsoft direct control over application listings and submissions.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.opensourceforu.com/2022/06/microsoft-to-charge-for-available-open-source-software-in-microsoft-store/
|
||||
|
||||
作者:[Laveesh Kocher][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.opensourceforu.com/author/laveesh-kocher/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://www.opensourceforu.com/wp-content/uploads/2022/06/microsoft-e1655714723942.jpg
|
||||
@@ -1,75 +0,0 @@
|
||||
[#]: subject: "Mysterious GeckoLinux Creator Reveals a New Debian Remix Distro"
|
||||
[#]: via: "https://news.itsfoss.com/debian-remix-spiral-linux/"
|
||||
[#]: author: "Ankush Das https://news.itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Mysterious GeckoLinux Creator Reveals a New Debian Remix Distro
|
||||
======
|
||||
GeckoLinux creator unveils a new Linux distribution based on Debian, focusing on simplicity and usability.
|
||||
|
||||
![spiral linux][1]
|
||||
|
||||
The creator of GeckoLinux (providing an improved openSUSE experience) remains anonymous.
|
||||
|
||||
And, I won’t comment if it is a good or bad thing, but now the developer is back with another similar project based on Debian.
|
||||
|
||||
**SpiralLinux**, a Debian-based distribution that aims to make Debian usable for the end-users.
|
||||
|
||||
### SpiralLinux: A Distro Built from Debian
|
||||
|
||||
![spirallinux][2]
|
||||
|
||||
It is no surprise that most of the user-friendly Linux distributions have Debian as its original base. Ubuntu has managed to do a lot of improvements on top of it to make it a good desktop experience, even for users without prior Linux experience.
|
||||
|
||||
So, how is this different?
|
||||
|
||||
Well, the creator says that this project aims to help you use Debian with all its core strengths without customizing a lot of things.
|
||||
|
||||
SpiralLinux is a close-to-vanilla experience if you want to use Debian on your desktop. You can also upgrade to the latest stable Debian version (or unstable/testing) as you require without losing the user-friendly customizations.
|
||||
|
||||
In other words, SpiralLinux makes Debian fit for desktop usage with minimal efforts to the end-user.
|
||||
|
||||
And, to achieve this, SpiralLinux uses official Debian package repositories providing a live installation method to let you setup a customized Debian system.
|
||||
|
||||
Additionally, you have the following features in SpiralLinux:
|
||||
|
||||
* VirtualBox support out-of-the-box
|
||||
* Preinstalled proprietary media codecs and non-free package repositories
|
||||
* Preinstalled proprietary firmware
|
||||
* Printer support
|
||||
* Flatpak support through a GUI (software center)
|
||||
* zRAM swap enabled by default
|
||||
* Multiple desktop environments (Cinnamon, XFCE, Gnome, Plasma, MATE, Budgie, LXQt)
|
||||
|
||||
Considering Debian always sticks to the open-source and free packages, the end-user has to figure out the codecs, drivers, and other packages to make a lot of things work for a proper desktop experience.
|
||||
|
||||
And, it seems like SpiralLinux could live as a useful alternative to Debian just like GeckoLinux is to openSUSE.
|
||||
|
||||
### Download SpiralLinux
|
||||
|
||||
If you always wanted to try Debian, but did not want to fiddle around a lot for initial configuration, you can try SpiralLinux.
|
||||
|
||||
You can head to its official webpage hosted on GitHub to explore more about it.
|
||||
|
||||
[SpiralLinux][3]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/debian-remix-spiral-linux/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://news.itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://news.itsfoss.com/wp-content/uploads/2022/06/spiral-linux-debian-remix-distro.jpg
|
||||
[2]: https://news.itsfoss.com/wp-content/uploads/2022/06/spirallinux.jpg
|
||||
[3]: https://spirallinux.github.io/
|
||||
@@ -1,55 +0,0 @@
|
||||
[#]: subject: "The Final Version Of 7-Zip 22.00 Is Now Available"
|
||||
[#]: via: "https://www.opensourceforu.com/2022/06/the-final-version-of-7-zip-22-00-is-now-available/"
|
||||
[#]: author: "Laveesh Kocher https://www.opensourceforu.com/author/laveesh-kocher/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
The Final Version Of 7-Zip 22.00 Is Now Available
|
||||
======
|
||||
![7-zip-2200-500x312][1]
|
||||
|
||||
7-Zip is a well-known open source file archiver for Windows, Mac, and Linux. 7-Zip 22.00 is now available; it is the first stable release of 2022. The most recent release was 7-Zip 21.07, which was released in December 2021. Users of 7-Zip can obtain the most recent version of the application from the official website. Downloads are available for Windows 64-bit, 32-bit, and ARM versions. The programme is still compatible with out-of-date versions of Windows, such as XP and Vista. All officially supported Windows versions, including server versions, are also supported. 7-Zip 22.00 for Linux is already available for download, but the Mac OS version is not.
|
||||
|
||||
7-Zip 22.00 includes several new features that enhance the application’s functionality. The archiver now supports the extraction of Apple File System APFS images. Several years ago, Apple introduced the Apple File System in Mac OS 10.13 and iOS. The file system has been designed with flash and solid state drive storage in mind.
|
||||
|
||||
7-Zip 22.00 includes several enhancements to its TAR archive support. Using the switches -ttar -mm=pax or -ttar -mm=posix, 7-Zip can now create TAR archives in POSIX tar format. Additionally, using the switches ttar -mm=pax -mtp=3 -mtc -mta, 7-Zip can store file timestamps with high precision in tar/pax archives.
|
||||
|
||||
* snoi: save owner/group ids in the archive or copy owner/group ids from the archive to the extracted files.
|
||||
* snon: keep owner/group names in the archive
|
||||
|
||||
7-Zip 22.00 for Windows adds support for the -snz switch, which propagates the Zone.
|
||||
|
||||
To extract files, use the identifier stream. Windows uses the stream for security purposes; it can be used to determine whether a file was created locally or downloaded from the Internet.
|
||||
|
||||
7-Zip 22.00 includes several new features that enhance the application’s functionality. The archiver now supports the extraction of Apple File System APFS images. Several years ago, Apple introduced the Apple File System in Mac OS 10.13 and iOS. The file system has been designed with flash and solid state drive storage in mind.
|
||||
|
||||
7-Zip 22.00 includes several enhancements to its TAR archive support. Using the switches -ttar -mm=pax or -ttar -mm=posix, 7-Zip can now create TAR archives in POSIX tar format. Additionally, using the switches ttar -mm=pax -mtp=3 -mtc -mta, 7-Zip can store file timestamps with high precision in tar/pax archives.
|
||||
|
||||
Finally, Linux users can use the following two new switches with TAR archives:
|
||||
|
||||
* snoi: save owner/group ids in the archive or copy owner/group ids from the archive to the extracted files.
|
||||
* snon: keep owner/group names in the archive
|
||||
|
||||
7-Zip 22.00 for Windows adds support for the -snz switch, which propagates the Zone.
|
||||
|
||||
To extract files, use the identifier stream. Windows uses the stream for security purposes; it can be used to determine whether a file was created locally or downloaded from the Internet.
|
||||
|
||||
In the “add to archive” configuration dialogue, 7-Zip 22.00 includes a new options window. It includes options for changing the timestamp precision, changing other time-related configuration options, and preventing the source files’ last access time from changing.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.opensourceforu.com/2022/06/the-final-version-of-7-zip-22-00-is-now-available/
|
||||
|
||||
作者:[Laveesh Kocher][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.opensourceforu.com/author/laveesh-kocher/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://www.opensourceforu.com/wp-content/uploads/2022/06/7-zip-2200-500x312-1.jpg
|
||||
@@ -1,69 +0,0 @@
|
||||
[#]: subject: "This Open-Source Project Proves Chrome Extensions Can Track You"
|
||||
[#]: via: "https://news.itsfoss.com/chrome-extension-tracking/"
|
||||
[#]: author: "Ankush Das https://news.itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
This Open-Source Project Proves Chrome Extensions Can Track You
|
||||
======
|
||||
Is this a reason to ditch Chromium-based browsers and start using Firefox? Maybe, you decide.
|
||||
|
||||
![chrome extension tracker][1]
|
||||
|
||||
Even with all the privacy extensions and fancy protection features, there are still ways to identify you or track you.
|
||||
|
||||
Note that it is not the case for all browsers, here, we focus on Chromium-based browsers and Google Chrome as the prime suspect.
|
||||
|
||||
While detecting installed extensions in a Chromium browser was already possible, numerous extensions implemented certain protections to prevent it.
|
||||
|
||||
However, a security researcher, also known as “**z0ccc**”, discovered a new method to detect installed Chrome browser extensions, which can be further used to track you through browser fingerprinting.
|
||||
|
||||
**In case you did not know**: Browser fingerprinting refers to the tracking method where various information about your device/browser gets collected to create a unique fingerprint ID (hash) to identify you across the internet. Information like browser name, version, operating system, extensions installed, screen resolution, and similar technical data.
|
||||
|
||||
It sounds like a harmless data collection technique, but you can be tracked online with this tracking method.
|
||||
|
||||
### Detecting Google Chrome Extensions
|
||||
|
||||
The researcher shared an open-source project “**Extension Fingerprints**” which you can use to test if Chrome extensions installed on your browser are being detected.
|
||||
|
||||
The new technique involves a time-difference method where the tool compares the time to fetch resources for the extensions. A protected extension takes more time to fetch compared to other extensions not installed on your browser. So, that helps identify some extensions from the list of over 1000 extensions.
|
||||
|
||||
The point is—even with all the advancements and techniques to prevent tracking, extensions from the Google Web Store can be detected.
|
||||
|
||||
![][2]
|
||||
|
||||
And, with the installed extensions detected, you can be tracked online using browser fingerprinting.
|
||||
|
||||
Surprisingly, even if you have extensions like **uBlocker, AdBlocker,**or**Privacy Badger** (some popular privacy-focused extensions), they all get detected using this method.
|
||||
|
||||
You can explore all the technical details on its [GitHub page][3]. And, if you want to test it yourself, head to its [Extension Fingerprints site][4] to check for yourself.
|
||||
|
||||
### Firefox To The Rescue?
|
||||
|
||||
It seems like it, considering [I keep coming back to Firefox][5] for various reasons.
|
||||
|
||||
The discovered method should work with all the Chromium-based browsers. I tested it with Brave and Google Chrome. The researcher also mentions that the tool does not work with Microsoft Edge using extensions from Microsoft’s store. But, it is possible with the same method of tracking.
|
||||
|
||||
Mozilla Firefox is safe from this because the extension IDs for every browser instance are unique, as the researcher suggested.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/chrome-extension-tracking/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://news.itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://news.itsfoss.com/wp-content/uploads/2022/06/opensource-project-tracker-chrome-extensions.jpg
|
||||
[2]: https://news.itsfoss.com/wp-content/uploads/2022/06/extension-fingerprints.jpg
|
||||
[3]: https://github.com/z0ccc/extension-fingerprints
|
||||
[4]: https://z0ccc.github.io/extension-fingerprints/
|
||||
[5]: https://news.itsfoss.com/why-mozilla-firefox/
|
||||
@@ -1,90 +0,0 @@
|
||||
[#]: subject: "Should Businesses Opt for Serverless Computing?"
|
||||
[#]: via: "https://www.opensourceforu.com/2021/12/should-businesses-opt-for-serverless-computing/"
|
||||
[#]: author: "Krishna Mohan Koyya https://www.opensourceforu.com/author/krishna-mohan-koyya/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "lkxed"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Should Businesses Opt for Serverless Computing?
|
||||
======
|
||||
Serverless computing removes the server from the equation and enables businesses to give undivided attention to the application functionality. Does that make serverless computing the automatic choice? Let’s find out.
|
||||
|
||||
![Severless-Cloud-Computing-Featured-image-OSFY-Oct-2021][1]
|
||||
|
||||
Until recently, almost every product manager organised his or her engineering resources into two separate teams — the development team and the operations team. The development team is usually involved in coding, testing and building the application functionality, whereas the operations team takes the responsibility of delivery, deployment, and operational maintenance of the application.
|
||||
|
||||
When a development team builds an e-commerce application, the operations team sets up the server to host that application. Setting up a server involves several aspects, which include:
|
||||
|
||||
* Choosing the appropriate hardware and operating system
|
||||
* Applying the required set of patches
|
||||
* Installing applicable server environments like JDK, Python, Tomcat, NodeJS, etc
|
||||
* Deploying, configuring, and provisioning the actual application
|
||||
* Opening and securing appropriate ports
|
||||
* Setting up required database engines
|
||||
|
||||
… and the list just goes on.
|
||||
|
||||
Besides this, managers also break their heads on capacity planning. After all, any non-trivial application is expected to be 100 per cent available, reliable and scalable all the time. This requires optimal investment in the hardware. As we all know, shortage of hardware at crucial periods results in business loss, and on the other hand, redundant hardware hurts the bottomline. Capacity planning is crucial, irrespective of whether the application is targeted for the on-premises data centre or for cloud infrastructure.
|
||||
By now, it is clear that businesses spend a lot of time not only in building the functionality but also in delivering it.
|
||||
|
||||
Serverless computing aims at offering a seamless way to deliver the functionality without worrying about the server setup and maintenance. In other words, a serverless computing platform offers a ready-to-use environment in such a way that the businesses build and deploy the applications as a set of smaller functions as quickly as possible. That is why this approach is referred to as Function as a Service (FaaS).
|
||||
|
||||
Remember that there is still a server in serverless computing, but it is taken care of by the FaaS vendors like AWS, Microsoft, and Google.
|
||||
|
||||
For example, AWS offers a serverless computing environment in the name of Lambda functions. Developers can choose to build the applications as a set of Lambda functions that can be written in NodeJS, Java, Python, and a few other languages. AWS offers a ready-to-use environment to deploy these functions. It also offers ready-to-use database servers, file servers, application gateways, authentication servers, etc.
|
||||
|
||||
Similarly, Microsoft Azure offers an environment to build and deploy Azure functions in languages like C#.
|
||||
|
||||
### Why serverless?
|
||||
|
||||
There are two main factors driving the popularity of serverless computing.
|
||||
|
||||
#### Ready-to-use environment
|
||||
|
||||
Obviously, this is the topmost selling point in favour of serverless computing. Businesses need not procure/book hardware or instances in advance, or worry about licences and setting up and provisioning the server. And they need not bother about scaling up and down. All of this is taken care of by the FaaS vendor.
|
||||
Optimal cost: Since FaaS vendors always charge the clients based on the utilisation of the environment (pay as you use model), businesses need not worry about upfront costs and wastage of resources. For example, AWS charges the clients based on the number of requests a Lambda function receives, number of queries run on a table, etc.
|
||||
|
||||
### Challenges with serverless computing
|
||||
|
||||
Like with any other approach, serverless computing is also not the perfect approach that everyone can blindly follow. It has its own set of limitations. Here are a few of them.
|
||||
|
||||
#### Vendor locking
|
||||
|
||||
The first and most important problem associated with serverless computing is that functions like Lambda or Azure are to be written using vendor-supplied APIs. For example, the functions that are written using an AWS Lambda API cannot be deployed into Google Cloud and vice versa. Hence, serverless computing forces businesses to commit to a vendor, for years. The success or failure of the application depends not only on the functionality but also on the ability of the vendor with respect to performance, etc.
|
||||
|
||||
#### Programming language
|
||||
|
||||
No serverless computing platform supports all the possible programming languages. Moreover, it may not support all the versions of a given programming language. The application development teams are constrained to choose only the languages that are offered. This may turn out to be very crucial in terms of the capabilities of the team.
|
||||
|
||||
#### Optimal cost, really?
|
||||
|
||||
It all depends on the usage of the resources. If your application is attracting a huge load, like millions of requests per second, the bill that you foot might be exorbitant. At such a scale, having your own server on-premises or on the cloud might work cheaper. It doesn’t mean that applications with Web-scale are not suitable for serverless computing. It all boils down to the way you architect around the platform and the deal you sign with the vendor.
|
||||
|
||||
#### Ecosystem
|
||||
|
||||
No application is written for an isolated environment. It requires other components like data stores, databases, security engines, gateways, messaging servers, queues, cache, etc. Every platform offers its own set of such tools. For instance, AWS offers Dynamo DB as one of the NoSQL solutions. Obviously, other vendors offer their own NoSQL solutions. The teams are thus forced to architect the applications based on the chosen platform. Though most of the commercial FaaS vendors offer one or another component for a particular requirement, not every component may be best-in-class.
|
||||
|
||||
### What about containers?
|
||||
|
||||
Many of us migrated to containerised deployment models in the last decade, since they offer a lightweight alternative to the costly machines, physical or virtual. With orchestration tools like Kubernetes, we love to deploy containerised applications and meet Web-scale requirements. Containers offer a certain degree of isolation from the underlying environment, which makes deployment relatively easy. However, we still need investments in hardware (on-premises or cloud), licences, networking, provisioning, etc, which demands forward planning, applicable technical skills, and careful monitoring. Serverless computing frees us even from these responsibilities, albeit with its own set of pros and cons.
|
||||
|
||||
### Road ahead
|
||||
|
||||
We are in the days of continuous development, continuous integration, and continuous deployment. Every business is facing competition. Time to market (TTM) plays a significant role in gaining and retaining customers. In this backdrop, businesses love to spend more time churning out the functionality as quickly as possible rather than struggling with the nitty-gritty of deployment and maintenance. Serverless computing has the potential to meet these demands. Big players are committing huge investments to make FaaS as seamless and as affordable as possible. The future looks bright for serverless computing.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.opensourceforu.com/2021/12/should-businesses-opt-for-serverless-computing/
|
||||
|
||||
作者:[Krishna Mohan Koyya][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.opensourceforu.com/author/krishna-mohan-koyya/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://www.opensourceforu.com/wp-content/uploads/2021/10/Severless-Cloud-Computing-Featured-image-OSFY-Oct-2021.jpg
|
||||
@@ -2,7 +2,7 @@
|
||||
[#]: via: "https://www.opensourceforu.com/2022/06/ssl-certificates-make-the-right-choice/"
|
||||
[#]: author: "Jitendra Bhojwani https://www.opensourceforu.com/author/jitendra-bhojwani/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: translator: "lightchaserhy"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
[#]: subject: "Applying smart thinking to open organization principles"
|
||||
[#]: via: "https://opensource.com/open-organization/22/6/applying-smart-thinking-open-organization-principles"
|
||||
[#]: author: "Ron McFarland https://opensource.com/users/ron-mcfarland"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Applying smart thinking to open organization principles
|
||||
======
|
||||
Use your environment, repetition, and the Role of 3 to enhance your thinking habits.
|
||||
|
||||
![a magnifying glass looking at a brain illustration][1]
|
||||
|
||||
Image by: Opensource.com
|
||||
|
||||
Habits have an unfair reputation of being bad things that need to be stopped. But consider this: Automation and habits have many things in common. First, they're both repetitive. They're done over and over, the exact same way. More importantly, they reduce costs (both cost per piece and cost of energy used).
|
||||
|
||||
[Art Markman's book Smart Thinking][2] stresses the importance of creating habits to take your mind away from unimportant thoughts and redirect your attention toward more interesting and creative ideas. You can apply this concept to the use of [open organization principles][3].
|
||||
|
||||
This article is the second part of a two-part series on habits. The first part drew from a presentation I gave a few years ago. In this article, I apply new information from Markman.
|
||||
|
||||
### What is smart thinking?
|
||||
|
||||
Smart thinking is about the information you have, how you get valuable information, and how you use what you have successfully. It's also the ability to solve new problems using your current knowledge. Smart thinking is a skill you can use, practice, and improve on. Based on that definition, those benefits would be very helpful in promoting open organization principles.
|
||||
|
||||
### Forming habits
|
||||
|
||||
Markman says habits are formed, unthinkingly automatic, and rarely reviewed for their importance. A process of strategic thinking is required to do this review. If performed correctly, less effort is needed to change these habits. The human mental system is designed to avoid thinking when possible. It's preferable to just effortlessly act on routine tasks so you can direct your attention to more important issues. When you perform tasks repeatedly, you form habits so your mind doesn't have to think through them step by step.
|
||||
|
||||
That's why you can't remember things you did a few seconds ago. Markman gives the example of not remembering whether you locked the door of your apartment or house. Because you did it automatically, if you were thinking of something completely different when you locked the door, you likely don't know whether you locked it.
|
||||
|
||||
The goal of smart thinking is to develop as many good habits as possible, so your mind doesn't have to go through the effort of thinking every time you perform them. Developing checklists is a good way to avoid excessive thinking. This can be applied to open organization principles as well. To save on energy and effort, follow a list of items and act on them. This was my goal when I developed the [Communication technology maturity worksheet][4], which I wrote about in my article "[How to assess your organization's technical maturity][5]." If there's no routine and the activity is new, you must resort to a more stressful and tiring thought process.
|
||||
|
||||
### Importance of environment and repetition
|
||||
|
||||
Markman describes a formula for creating smart habits, considering two key facts:
|
||||
|
||||
* There is interaction between environment and action.
|
||||
* Only work on repeated actions to create good habits.
|
||||
|
||||
#### Environment
|
||||
|
||||
Markman defines an environment as both the outside world and one's internal mental world (such as goals, feelings, or perspectives). In the outside world, you can develop seemingly meaningless activities to create triggers and reminders. For example, you assign convenient locations for things, so you don't have to think about where they are. You can create triggers (such as lists or empty packages for resupply reminders) to highlight things you need to do, thereby avoiding a lot of thought.
|
||||
|
||||
If you want to read a book but have been putting it off, consider taking it out and putting it in front of your computer or TV. That way, you'll see it, and probably have to move it out of your way, each time you're at your computer or TV, which can be a powerful way to get you reading.
|
||||
|
||||
If you learn something in a particular place (with all its surroundings), you will recall that learning more easily if you are in a similar place or the same place. The environment triggers the information to come to the top of your mind. Because new (wanted) habits must be consciously performed, you must add elements in your environment to remind yourself to do them. Also, you must eliminate triggers that remind you of the old (unwanted) habit and replace them with another activity.
|
||||
|
||||
For the internal mental environment, consider trying to memorize useful facts that are continually required, such as names, locations, the best road routes, and so on. If I meet someone I want to get to know better, I ask for their name and use it as much as possible, then write it down when I have a chance. Later, I add that name to my personal contact information. By repeatedly seeing the name, I eventually memorize it and use it without thinking.
|
||||
|
||||
#### Repetition
|
||||
|
||||
All habits are formed through repeated use, and the first time is the hardest. After many repetitions, minimal thought is required, until the habit becomes automatic. Structure your daily life by forming beneficial habits and practicing them. Regular role playing is equally important. By getting those memories top of mind, they become faster to retrieve.
|
||||
|
||||
If you can make each habit as distinct as possible, it will be easier to remember and retrieve when needed. You know you've created a good habit when you no longer have to think about it.
|
||||
|
||||
### When good habits go bad
|
||||
|
||||
A habit can go from good to bad with a situational change. Getting rid of a bad habit and creating a productive new one takes a lot of thought. When a habit change is required, regularly getting a good night's sleep is essential. Your brain helps process the new experiences and behaviors and makes the activity more effective in the future.
|
||||
|
||||
There are two important characteristics of changing habits:
|
||||
|
||||
1. Your current habit pushes you into action. You must overcome the pressure to act.
|
||||
2. When there's pressure to act, replace the habit with a more helpful action. New memories of the desired action must be developed and stored.
|
||||
|
||||
You must develop triggers to engage the new behavior. This trigger requires your attention, as you are forcing yourself to stop the strong current habit and develop a new and, initially, weak habit. If you are distracted, the old habit remains strong. Your effort could also be disrupted by stress, fatigue, or the powerful influence of your environment.
|
||||
|
||||
Willpower alone cannot change habits, and it's extremely exhausting to try. You might have some short-term successes, but you will wear out eventually. You need environmental support. Cravings happen when you have an active goal that has been blocked. They are your mind's way of saying you must strengthen your desired goal further. You must not only stop the old habit but study what in your environment is activating it.
|
||||
|
||||
To apply these concepts to open organization principles, consider how you can create an environment that makes it easy to activate a principle while discouraging the current unproductive behavior. You must create an environment that reduces the chance of the bad habit being recalled and create triggers to activate the principles. That's the goal of the open organization leadership assessments. They become triggers.
|
||||
|
||||
### The Role of 3
|
||||
|
||||
One of Markman's key concepts is the Role of 3, which guides both effective learning and effective presentation of information in a way that will be remembered. Markman is talking about getting someone else to change his behavior. This reminds me of my sales seminar in which I wanted to improve (change) the sales associates' selling activities. There is a difference between education, which is just providing knowledge, and training. Training is developing a skill one can use and improve on. Therefore, I had to cut three-quarters of the content and repeat it four times in different ways in my seminars, including role playing. I think what Markman is saying is that stressing just three actions is ideal initially. In my sales training case, my greatest success was role playing product presentations. Not only did the sales people learn the features of the product, but they could talk about them confidently to customers. Afterward, that led to other skills that could be developed.
|
||||
|
||||
This Role of 3 applies to you too when wanting to act on something. Imagine a critical business meeting with vital information presented. Suppose you were distracted by jokes or anxiety-provoking rumors (about layoffs, demotions, or inadequate performance). The meeting could be a waste of your time unless you manage your attention on specific issues.
|
||||
|
||||
Here is what Markman recommends before, during, and after an important event, to learn three key points:
|
||||
|
||||
1. Prepare: Consider what you want to get out of the event (be it a meeting, presentation, or one-on-one discussion) and what you want to achieve. Consider at most three things. Information connected to your goal is easier to detect and remember. Your mental preparation directs your mind to the information you seek. Psychologists call this advance organizer activity. Consider what will be discussed and review any available materials beforehand.
|
||||
2. Pay attention: This is hard work, particularly when there are distractions. Avoid multitasking on unrelated work (including emails and instant messaging). Working memory is an important concept: Your attention impacts what you will remember later.
|
||||
3. Review: After any critical information-gathering event (a class, meeting, reading a book or article), write down three key points. If you can't write it down, review it in your mind, or record it on your phone or digital recorder. Try to attach what you learned to what you know. Where do they match or conflict?
|
||||
|
||||
Suppose you're presenting open organization principles to a group. To make sure they remember those principles and use them, follow these procedures:
|
||||
|
||||
1. Start presentations with an agenda and outline for all to review.
|
||||
2. During the presentation, stay focused primarily on your three critical points. Present all principles, but continually review and highlight three of them.
|
||||
3. Help people connect the content to what they are doing now and how the principles will improve their activities.
|
||||
4. Share additional ways the principles can be applied with example use cases and their benefits.
|
||||
5. End all presentations with a three-point summary. An action plan can be helpful as well.
|
||||
|
||||
Say you're presenting the five open organization principles of transparency, collaboration, inclusivity, adaptability, and community. First, you present all of them in basic terms, but the Role of 3 tells you the audience will probably only pick up on three of them, so you focus on transparency, collaboration, and inclusivity.
|
||||
|
||||
Here's an example outline, following the Role of 3:
|
||||
|
||||
1. Present three key ideas.
|
||||
1. Transparency
|
||||
2. Collaboration
|
||||
3. Inclusivity
|
||||
2. Organize the presentation by describing each key idea in one sentence.
|
||||
1. Transparency is getting as much useful information to other people as possible.
|
||||
2. Collaboration is discussing issues with as many other people as appropriate and avoiding making final decisions on your own.
|
||||
3. Inclusivity is getting as many different kinds of people involved in a project as appropriate.
|
||||
3. Develop key idea relationships.
|
||||
1. How is transparency related to what people already know? The more transparent you are, the easier it is to collaborate.
|
||||
2. How is collaboration related to what people already know, including transparency? If people are doing well with transparency, mention many times that by collaborating more, their transparency will improve.
|
||||
3. How is inclusivity related to what people already know, including transparency and inclusivity? The more inclusive we are, the more diverse the ideas generated, leading to more transparency and collaboration.
|
||||
4. Provide three questions to help people remember and explain the ideas.
|
||||
1. When was the last time you paused before deciding something and decided instead to collaborate with all people concerned?
|
||||
2. Who do you think would be an easy person to collaborate with?
|
||||
3. Each week, how many people do you collaborate with? Should that number be improved upon?
|
||||
|
||||
### Better for everyone
|
||||
|
||||
Now you know what smart thinking is all about. You've learned the Role of 3, and you understand the importance of environment and repetition. These concepts can help you be more productive and happier in whatever you get involved in, including bringing the open organization principles to your own communities.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/open-organization/22/6/applying-smart-thinking-open-organization-principles
|
||||
|
||||
作者:[Ron McFarland][a]
|
||||
选题:[lkxed][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/ron-mcfarland
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/LAW_EvidencedBasedIP_520x292_CS.png
|
||||
[2]: https://www.amazon.com/Smart-Thinking-Essential-Problems-Innovate/dp/0399537759
|
||||
[3]: https://theopenorganization.org/definition/open-organization-definition/
|
||||
[4]: https://opensource.com/sites/default/files/images/open-org/communication_tech_worksheet.pdf
|
||||
[5]: https://opensource.com/open-organization/20/3/communication-technology-worksheet
|
||||
@@ -0,0 +1,130 @@
|
||||
[#]: subject: "Create a more diverse and equitable open source project with open standards"
|
||||
[#]: via: "https://opensource.com/article/22/6/open-source-standards-diversity"
|
||||
[#]: author: "Paloma Oliveira https://opensource.com/users/discombobulateme"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Create a more diverse and equitable open source project with open standards
|
||||
======
|
||||
Using open standards improves your project's quality and shareability. Most importantly, they can guide technology development by gently enforcing space for diversity and equity.
|
||||
|
||||
![multi-colored dandelions][1]
|
||||
|
||||
Image by: [Monsterkoi][2]. Modified by Opensource.com. [CC BY-SA 4.0][3]
|
||||
|
||||
This article is intended to serve as a reference so that you can understand everything you need to be proud of your repository and make your open source project more open. By using open standards, an open source project improves its quality and shareability, since such standards exist to foster better communication between creators and consumers of the project. Most importantly, open standards can guide technology development by gently enforcing space for diversity and equity.
|
||||
|
||||
### What is open source?
|
||||
|
||||
The term [open source][4] started in the late 80's as a way to guarantee access to technological development by legally guaranteeing the right to copy, modify, and redistribute software. This idea has expanded and today it is about fostering a culture of sharing that supports everything from political actions to a billion dollar technology industry.
|
||||
|
||||
The projects and their communities, which give the projects their value, have become much more complex than just the code. Today, it is impossible to think of a project outside of what I prefer to define as its ecosystem. "Ecosystem" sounds to me like a proper definition, because it acknowledges the complexity of technical things, like code and configuration, and also of people.
|
||||
|
||||
### Lack of diversity is a problem in open source
|
||||
|
||||
Without open source, the technology industry would collapse, or it wouldn't even exist. That's the scope of importance that open source has today. What a powerful feeling it is to know that we are all "standing on the shoulders of giants"? We are all benefiting from the power of the commons, using collective labor and intelligence to make something better for everyone.
|
||||
|
||||
What's rarely spoken of is that such important initiatives, in most cases, depend solely on the volunteer labor of its maintainers. This creates a huge imbalance, both from work and diversity aspects.
|
||||
|
||||
Open source is intrinsically a power to foster diversity within the development industry by valuing the contributions of what is contributed over who is contributing it. The reality is, though, that free time is often a rare commodity for many people. Many people are too busy working to generate income, caring for families and loved ones, looking for work, fighting social injustice, and are unable to dedicate time to contribute to software.
|
||||
|
||||
The very opportunity to contribute to the system depends on you being one of the lucky ones who can be part of this system. This is not a reality for many others because of their gender, skin color, or social status. Historically, women accumulate unpaid work that's invisible, but which requires a substantial proportion of their energy and time. Underprivileged people have little free time because they have to work more hours, often having more than one job.
|
||||
|
||||
This is reflected in the numbers. [Only 4.5%][5] of [open source maintainers][6] are not white males, according to research into the field. So we know that this billion dollar industry, shaping technological development, is composed of a homogeneous environment. But we also know that diversity renders robust innovative results.The question is, how can this be changed?
|
||||
|
||||
### Intentional communication with your open source community
|
||||
|
||||
Communication is key. Build a structure with transparency of communication and governance for your project. Clear, concise and respectful communication makes your project accessible to users and contributors. It helps project maintainers devote their time focusing on what they need to do. It helps interested people feel welcome and start contributing faster and more consistently, and it attracts diversity to your community.
|
||||
|
||||
Sounds great, but how can this be obtained? I grouped the rules of good practice into three categories procedural, daily, and long term. These practices are in part strategic, but if you and your community don't have the capacity to be strategic, it's also possible to substantially change your project by adding a few simple files to your repository.
|
||||
|
||||
But which files are those, and what happens when you already have several projects under your management? A few of them are:
|
||||
|
||||
* Code of conduct
|
||||
* License
|
||||
* Readme
|
||||
* Changelog
|
||||
* Contributing
|
||||
* Ownership
|
||||
* Test directory
|
||||
* Issues
|
||||
* Pull request templates
|
||||
* Security
|
||||
* Support
|
||||
|
||||
To help you get started, there are many projects that offer templates. By simply cloning them, you create a repository with these documents.
|
||||
|
||||
Another tool, designed to help open source software (OSS) maintainers and open source program offices (OSPO) is [check-my-repo][7]. Created by us at [Sauce Labs' OSPO Community][8], it's an automated tool built on [Repolinter][9] that verifies whether the main necessary parameters to comply with open source best practices (including the files mentioned above and a few other rules), are present in your repositories. The web app also explains why each file needs to exist.
|
||||
|
||||
#### Procedural best practices
|
||||
|
||||
As the name implies, this is about the process:
|
||||
|
||||
* Maintain a single public issue tracker.
|
||||
* Allow open access to the issues identified by the project.
|
||||
* Have mechanisms for feedback and to discuss new features.
|
||||
* Offer public meeting spaces scheduled in advance and have them recorded.
|
||||
|
||||
Here are some files that relate to the procedural logic:
|
||||
|
||||
* README: Make it easier for anyone who lands on your project to get started.
|
||||
* Code of conduct: Establish expectations and facilitate a healthy and constructive community.
|
||||
* Ownership: Make sure that someone is put in charge of the project to prevent it from being forgotten.
|
||||
|
||||
#### Daily tasks
|
||||
|
||||
This is about the day-to-day aspects, including:
|
||||
|
||||
* Check the status of the project.
|
||||
* Explain how to submit issues, propose enhancements, and add new features.
|
||||
* Show how to contribute to the project.
|
||||
|
||||
Files related to the daily aspects of project management are:
|
||||
|
||||
* Contributing: A step by step guideline on how to contribute.
|
||||
* Changelog: Notable changes need to be logged.
|
||||
* Security: Show how to report a security vulnerability.
|
||||
* Support: How the project is being maintained.
|
||||
|
||||
#### Long term goals
|
||||
|
||||
This has information that guarantees the history and continuation of the project, such as a mission statement, key concepts and goals, a list of features and requirements, and a project roadmap.
|
||||
|
||||
Relevant files are:
|
||||
|
||||
* License: It's essential for users to know their limits, and for you to protect yourself legally.
|
||||
* Test directory: Use this to avoid regression, breaks, and many other issues.
|
||||
|
||||
### Creating and maintaining your open source project
|
||||
|
||||
Now imagine a project with all of these factors. Will it help you build and keep a community? Will noise in communication be mitigated? Will it save maintainers tons of time so they can onboard people and solve issues? Will people feel welcome?
|
||||
|
||||
Creating and maintaining an open source project is very rewarding. Creating collaboratively is an incredible experience and has the intrinsic potential to take such creation into possibilities that one person alone, or a small group could never achieve. But working openly and collaboratively is also a challenge for the maintainers and a responsibility for the community to ensure that this space is equitable and diverse.
|
||||
|
||||
There's a lot of work ahead. The result of surveys on the health of open source communities often reflect the worst of the technology industry. That's why ensuring that these standards are used is so important. To help mitigate this situation, I am betting on standards. They're a powerful tool to align our intentions and to guide us to an equitable, transparent, and shareable space. Will you join me?
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/22/6/open-source-standards-diversity
|
||||
|
||||
作者:[Paloma Oliveira][a]
|
||||
选题:[lkxed][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/discombobulateme
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/diversity-inclusion-transformation-change_20180927.png
|
||||
[2]: https://pixabay.com/en/dandelion-colorful-people-of-color-2817950/
|
||||
[3]: https://creativecommons.org/publicdomain/zero/1.0/deed.en
|
||||
[4]: https://opensource.com/article/18/2/coining-term-open-source-software
|
||||
[5]: https://www.wired.com/2017/06/diversity-open-source-even-worse-tech-overall/
|
||||
[6]: https://www.linuxfoundation.org/blog/addressing-diversity-equity-and-inclusion-in-2021-and-beyond
|
||||
[7]: https://opensource.saucelabs.com/check-my-repo
|
||||
[8]: https://opensource.saucelabs.com
|
||||
[9]: https://todogroup.github.io/repolinter
|
||||
@@ -1,18 +1,20 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Solve a charity's problem with the Julia programming language)
|
||||
[#]: via: (https://opensource.com/article/21/1/solve-problem-julia)
|
||||
[#]: author: (Chris Hermansen https://opensource.com/users/clhermansen)
|
||||
[#]: subject: "Solve a charity's problem with the Julia programming language"
|
||||
[#]: via: "https://opensource.com/article/21/1/solve-problem-julia"
|
||||
[#]: author: "Chris Hermansen https://opensource.com/users/clhermansen"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Solve a charity's problem with the Julia programming language
|
||||
======
|
||||
See how Julia differs from Java, Python, and Groovy to solve a food
|
||||
bank's real-world problem.
|
||||
See how Julia differs from Java, Python, and Groovy to solve a food bank's real-world problem.
|
||||
|
||||
![Puzzle pieces coming together to form a computer screen][1]
|
||||
|
||||
Image by: Opensource.com
|
||||
|
||||
I have been writing a series of articles about solving a nice, small, and somewhat unusual problem in different programming languages ([Groovy][2], [Python][3], and [Java][4] so far).
|
||||
|
||||
Briefly, the problem is how to unpack bulk supplies into their units (for example, dividing a 10 pack of one-pound bags of your favorite coffee) and repackage them into hampers of similar value to distribute to struggling neighbors in the community.
|
||||
@@ -29,10 +31,9 @@ But enough speculation, let's code something!
|
||||
|
||||
### The Julia solution
|
||||
|
||||
My first decision is how to implement the data model. Julia supports _composite types_, seemingly similar to `struct` in C, and Julia even uses the keyword `struct`. Of note is that a `struct` is immutable (unless declared a `mutable struct`), which is fine for this problem since the data doesn't need to be mutated.
|
||||
|
||||
By following the approach I took in the Java solution, the `Unit struct` can be defined as:
|
||||
My first decision is how to implement the data model. Julia supports *composite types*, seemingly similar to `struct` in C, and Julia even uses the keyword `struct`. Of note is that a `struct` is immutable (unless declared a `mutable struct` ), which is fine for this problem since the data doesn't need to be mutated.
|
||||
|
||||
By following the approach I took in the Java solution, the `Unit struct` can be defined as:
|
||||
|
||||
```
|
||||
struct Unit
|
||||
@@ -44,13 +45,12 @@ end
|
||||
|
||||
Similarly, `Pack` is defined as the bulk package of `Unit` instances:
|
||||
|
||||
|
||||
```
|
||||
struct Pack
|
||||
unit::Unit
|
||||
count::Int
|
||||
Pack(item, brand, unitCount,p ackPrice) =
|
||||
new(Unit(item, brand, [div][6](packPrice,unitCount)), unitCount)
|
||||
new(Unit(item, brand, div(packPrice,unitCount)), unitCount)
|
||||
end
|
||||
```
|
||||
|
||||
@@ -58,7 +58,6 @@ There is an interesting thing here: a Julia "inner constructor." In the Java sol
|
||||
|
||||
Because Julia isn't object-oriented, I can't add methods to `Pack` to give unit price vs. pack price or to unpack it into a list of `Unit` instances. I can declare "getter" functions that accomplish the same tasks. (I probably don't need these, but I'll do it anyway to see how Julia methods work):
|
||||
|
||||
|
||||
```
|
||||
item(pack::Pack) = pack.unit.item
|
||||
brand(pack::Pack) = pack.unit.brand
|
||||
@@ -68,17 +67,16 @@ packPrice(pack::Pack) = pack.unit.price * pack.count
|
||||
unpack(pack::Pack) = Iterators.collect(Iterators.repeated(pack.unit,pack.count))
|
||||
```
|
||||
|
||||
The `unpack()` method is quite similar to the method of the same name I declared in the Java class `Pack`. The function `Iterators.repeated(thing,N)` creates an iterator that will deliver `N` copies of `thing`. The `Iterators.collect` (`iterator`) function processes the `iterator` to yield an array made up of the elements it delivers.
|
||||
|
||||
Finally, the `Bought struct`:
|
||||
The `unpack()` method is quite similar to the method of the same name I declared in the Java class `Pack`. The function `Iterators.repeated(thing,N)` creates an iterator that will deliver `N` copies of `thing`. The `Iterators.collect` (`iterator` ) function processes the `iterator` to yield an array made up of the elements it delivers.
|
||||
|
||||
Finally, the `Bought struct` :
|
||||
|
||||
```
|
||||
struct Bought
|
||||
pack::Pack
|
||||
count::Int
|
||||
end
|
||||
unpack(bought::Bought) =
|
||||
unpack(bought::Bought) =
|
||||
Iterators.collect(Iterators.flatten(Iterators.repeated(unpack(bought.pack),
|
||||
bought.count)))
|
||||
```
|
||||
@@ -87,7 +85,6 @@ Once again, I'm creating an array of an array of unpacked `Pack` instances (i.e.
|
||||
|
||||
Now I can construct the list of what I bought:
|
||||
|
||||
|
||||
```
|
||||
packs = [
|
||||
Bought(Pack("Rice","Best Family",10,5650),1),
|
||||
@@ -111,12 +108,11 @@ I'm starting to see a pattern here… this looks surprisingly like the Java solu
|
||||
|
||||
With the list packs of what I bought, I can now unpack into the units before working on redistributing them:
|
||||
|
||||
|
||||
```
|
||||
`units = Iterators.collect(Iterators.flatten(unpack.(packs)))`
|
||||
units = Iterators.collect(Iterators.flatten(unpack.(packs)))
|
||||
```
|
||||
|
||||
What's going on here? Well, a construct like `unpack.(packs)`—that is, the dot between the function name and the argument list—applies the function `unpack()` to each element in the list `packs`. This will generate a list of lists corresponding to the unpacked groups of `Packs` I bought. To turn that into a flat list of units, I apply `Iterators.flatten()`. Because `Iterators.flatten()` is lazy, to make the flatten thing happen, I wrap it in `Iterators.collect()`. This kind of composition of functions adheres to the spirit of functional programming, even though you don't see the functions chained together, as programmers who write functionally in JavaScript, Java, or what-have-you are familiar with.
|
||||
What's going on here? Well, a construct like `unpack.(packs)` —that is, the dot between the function name and the argument list—applies the function `unpack()` to each element in the list `packs`. This will generate a list of lists corresponding to the unpacked groups of `Packs` I bought. To turn that into a flat list of units, I apply `Iterators.flatten()`. Because `Iterators.flatten()` is lazy, to make the flatten thing happen, I wrap it in `Iterators.collect()`. This kind of composition of functions adheres to the spirit of functional programming, even though you don't see the functions chained together, as programmers who write functionally in JavaScript, Java, or what-have-you are familiar with.
|
||||
|
||||
One observation is that the list of units created here is actually an array whose starting index is 1, not 0.
|
||||
|
||||
@@ -124,63 +120,59 @@ With units being the list of units purchased and unpacked, I can now take on rep
|
||||
|
||||
Here's the code, which is not exceptionally different than the versions in Groovy, Python, and Java:
|
||||
|
||||
|
||||
```
|
||||
1 valueIdeal = 5000
|
||||
2 valueMax = round(valueIdeal * 1.1)
|
||||
3 hamperNumber = 0
|
||||
|
||||
4 while length(units) > 0
|
||||
4 while length(units) > 0
|
||||
5 global hamperNumber += 1
|
||||
6 hamper = Unit[]
|
||||
7 value = 0
|
||||
8 canAdd = true
|
||||
9 while canAdd
|
||||
10 u = [rand][7](0:(length(units)-1))
|
||||
10 u = rand(0:(length(units)-1))
|
||||
11 canAdd = false
|
||||
12 for o = 0:(length(units)-1)
|
||||
13 uo = (u + o) % length(units) + 1
|
||||
14 unit = units[uo]
|
||||
15 if length(units) < 3 || findfirst(u -> u == unit,hamper) === nothing && (value + unit.price) < valueMax
|
||||
15 if length(units) < 3 || findfirst(u -> u == unit,hamper) === nothing && (value + unit.price) < valueMax
|
||||
16 push!(hamper,unit)
|
||||
17 value += unit.price
|
||||
18 deleteat!(units,uo)
|
||||
19 canAdd = length(units) > 0
|
||||
19 canAdd = length(units) > 0
|
||||
20 break
|
||||
21 end
|
||||
22 end
|
||||
23 end
|
||||
24 Printf.@[printf][8]("\nHamper %d value %d:\n",hamperNumber,value)
|
||||
24 Printf.@printf("\nHamper %d value %d:\n",hamperNumber,value)
|
||||
25 for unit in hamper
|
||||
26 Printf.@[printf][8]("%-25s%-25s%7d\n",unit.item,unit.brand,unit.price)
|
||||
26 Printf.@printf("%-25s%-25s%7d\n",unit.item,unit.brand,unit.price)
|
||||
27 end
|
||||
28 Printf.@[printf][8]("Remaining units %d\n",length(units))
|
||||
28 Printf.@printf("Remaining units %d\n",length(units))
|
||||
29 end
|
||||
```
|
||||
|
||||
Some clarification, by line numbers:
|
||||
|
||||
* Lines 1–3: Set up the ideal and maximum values to be loaded into any given hamper and initialize Groovy's random number generator and the hamper number
|
||||
* Lines 4–29: This `while` loop redistributes units into hampers, as long as there are more available
|
||||
* Lines 5–7: Increment the (global) hamper number, get a new empty hamper (an array of `Unit` instances), and set its value to 0
|
||||
* Line 8 and 9–23: As long as I can add units to the hamper…
|
||||
* Line 10: Gets a random number between zero and the number of remaining units minus 1
|
||||
* Line 11: Assumes I can't find more units to add
|
||||
* Lines 12–22: This `for` loop, starting at the randomly chosen index, will try to find a unit that can be added to the hamper
|
||||
* Lines 13–14: Figure out which unit to look at (remember arrays start at index 1) and get it
|
||||
* Lines 15–21: I can add this unit to the hamper if there are only a few left or if the value of the hamper isn't too high once the unit is added and if that unit isn't already in the hamper
|
||||
* Lines 16–18: Add the unit to the hamper, increment the hamper value by the unit price, and remove the unit from the available units list
|
||||
* Lines 19–20: As long as there are units left, I can add more, so break out of this loop to keep looking
|
||||
* Line 22: On exit from this `for` loop, if I have inspected every remaining unit and could not find one to add to the hamper, the hamper is complete; otherwise, I found one and can continue looking for more
|
||||
* Line 23: On exit from this `while` loop, the hamper is as full as I can make it, so…
|
||||
* Lines 24–28: Print out the contents of the hamper and the remaining units info
|
||||
* Line 29: When I exit this loop, there are no more units left
|
||||
|
||||
|
||||
* Lines 1–3: Set up the ideal and maximum values to be loaded into any given hamper and initialize Groovy's random number generator and the hamper number
|
||||
* Lines 4–29: This `while` loop redistributes units into hampers, as long as there are more available
|
||||
* Lines 5–7: Increment the (global) hamper number, get a new empty hamper (an array of `Unit` instances), and set its value to 0
|
||||
* Line 8 and 9–23: As long as I can add units to the hamper…
|
||||
* Line 10: Gets a random number between zero and the number of remaining units minus 1
|
||||
* Line 11: Assumes I can't find more units to add
|
||||
* Lines 12–22: This `for` loop, starting at the randomly chosen index, will try to find a unit that can be added to the hamper
|
||||
* Lines 13–14: Figure out which unit to look at (remember arrays start at index 1) and get it
|
||||
* Lines 15–21: I can add this unit to the hamper if there are only a few left or if the value of the hamper isn't too high once the unit is added and if that unit isn't already in the hamper
|
||||
* Lines 16–18: Add the unit to the hamper, increment the hamper value by the unit price, and remove the unit from the available units list
|
||||
* Lines 19–20: As long as there are units left, I can add more, so break out of this loop to keep looking
|
||||
* Line 22: On exit from this `for` loop, if I have inspected every remaining unit and could not find one to add to the hamper, the hamper is complete; otherwise, I found one and can continue looking for more
|
||||
* Line 23: On exit from this `while` loop, the hamper is as full as I can make it, so…
|
||||
* Lines 24–28: Print out the contents of the hamper and the remaining units info
|
||||
* Line 29: When I exit this loop, there are no more units left
|
||||
|
||||
The output of running this code looks quite similar to the output from the other programs:
|
||||
|
||||
|
||||
```
|
||||
Hamper 1 value 5020:
|
||||
Tea Superior 544
|
||||
@@ -238,9 +230,8 @@ Once again, the random-number-driven list manipulation seems to make the "workin
|
||||
|
||||
Given that the main effort revolves around `for` and `while` loops, in Julia, I don't see any construct similar to:
|
||||
|
||||
|
||||
```
|
||||
`for (boolean canAdd = true; canAdd; ) { … }`
|
||||
for (boolean canAdd = true; canAdd; ) { … }
|
||||
```
|
||||
|
||||
This means I have to declare the `canAdd` variable outside the `while` loop. Which is too bad—but not a terrible thing.
|
||||
@@ -249,27 +240,24 @@ I do miss not being able to attach behavior directly to my data, but that's just
|
||||
|
||||
Good things: low ceremony, check; decent list-handling, check; compact and readable code, check. All in all, a pleasant experience, supporting the idea that Julia can be a decent choice to solve "ordinary problems" and as a scripting language.
|
||||
|
||||
Next time, I'll do this exercise in [Go][9].
|
||||
Next time, I'll do this exercise in [Go][6].
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/solve-problem-julia
|
||||
|
||||
作者:[Chris Hermansen][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/clhermansen
|
||||
[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)
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/puzzle_computer_solve_fix_tool.png
|
||||
[2]: https://opensource.com/article/20/9/groovy
|
||||
[3]: https://opensource.com/article/20/9/solve-problem-python
|
||||
[4]: https://opensource.com/article/20/9/problem-solving-java
|
||||
[5]: https://julialang.org/
|
||||
[6]: http://www.opengroup.org/onlinepubs/009695399/functions/div.html
|
||||
[7]: http://www.opengroup.org/onlinepubs/009695399/functions/rand.html
|
||||
[8]: http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
|
||||
[9]: https://golang.org/
|
||||
[6]: https://golang.org/
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to customize your voice assistant with the voice of your choice)
|
||||
[#]: via: (https://opensource.com/article/21/1/customize-voice-assistant)
|
||||
[#]: author: (Rich Lucente https://opensource.com/users/rlucente)
|
||||
[#]: subject: "How to customize your voice assistant with the voice of your choice"
|
||||
[#]: via: "https://opensource.com/article/21/1/customize-voice-assistant"
|
||||
[#]: author: "Rich Lucente https://opensource.com/users/rlucente"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
How to customize your voice assistant with the voice of your choice
|
||||
======
|
||||
The Nana and Poppy project enables a voice assistant to greet users with
|
||||
their great-grandchildren's voices instead of a generic AI.
|
||||
The Nana and Poppy project enables a voice assistant to greet users with their great-grandchildren's voices instead of a generic AI.
|
||||
|
||||
![radio communication signals][1]
|
||||
|
||||
Image by: [Internet Archive Book Images][2]. Modified by Opensource.com. [CC BY-SA 4.0][3]
|
||||
|
||||
It can be hard to find meaningful gifts for relatives that already have almost everything. My wife and I have given our parents "experiences" to try something novel, such as going to a themed restaurant or seeing a concert, but as our parents get older, it becomes more difficult. This year was no exception—until I thought about a way open source could give them something really special.
|
||||
|
||||
What if when they request help from an artificial intelligence (AI) voice assistant such as [Mycroft][2], my in-laws could get a special greeting? I looked at the existing voice assistant APIs to see if something like this was already available. There was something close, but not exactly what I was looking for. My idea was to record their great-grandchildren speaking a short greeting that would play whenever they push the button and before the conversation with the voice assistant begins. The greeting would be something like:
|
||||
What if when they request help from an artificial intelligence (AI) voice assistant such as [Mycroft][4], my in-laws could get a special greeting? I looked at the existing voice assistant APIs to see if something like this was already available. There was something close, but not exactly what I was looking for. My idea was to record their great-grandchildren speaking a short greeting that would play whenever they push the button and before the conversation with the voice assistant begins. The greeting would be something like:
|
||||
|
||||
> "Good morning, Nana and Poppy. Today is December 25th. The time is 3:10 pm. The current temperature for Waynesboro is 47 degrees. The current temperature for Ocean City is 50 degrees."
|
||||
|
||||
@@ -25,168 +27,166 @@ When they press the button, my in-laws would hear their great-grandchildren repo
|
||||
|
||||
The first problem was figuring out what phrases the voice assistant would need to say. Thinking about all the dates, times, and temperatures that I would need to cover, I arrived at a list of 79 phrases. I sent these instructions to my nieces:
|
||||
|
||||
> _Please record the kids saying each line below. Sorry there are so many. It's okay to do this in one setting with prompting them if it makes it easier. I can edit the audio files and deal with most formats, so none of that should be a problem. Just record using your phone in whatever way is easiest._
|
||||
>
|
||||
> _Make sure that the kids say each line clearly and loudly. There should be a slight pause between each line to make editing easier (prompting helps like "Repeat after me …"). That will make it easier for me to chop these up into individual sound files._
|
||||
>
|
||||
> _Whenever the button on the device is pushed, it will respond with a random grandchild saying the correct date/time/temperature, like:_
|
||||
>
|
||||
> _"Good afternoon, Nana and Poppy. Today is January third. The time is one oh four pm. The current temperature for Waynesboro is thirty degrees. The current temperature for Ocean City is thirty four degrees."_
|
||||
>
|
||||
> _PLEASE RECORD EACH CHILD SAYING THE FOLLOWING PHRASES WITH A SHORT PAUSE BETWEEN EACH ONE:_
|
||||
> Please record the kids saying each line below. Sorry there are so many. It's okay to do this in one setting with prompting them if it makes it easier. I can edit the audio files and deal with most formats, so none of that should be a problem. Just record using your phone in whatever way is easiest.
|
||||
|
||||
> Make sure that the kids say each line clearly and loudly. There should be a slight pause between each line to make editing easier (prompting helps like "Repeat after me …"). That will make it easier for me to chop these up into individual sound files.*
|
||||
|
||||
> Whenever the button on the device is pushed, it will respond with a random grandchild saying the correct date/time/temperature, like: "Good afternoon, Nana and Poppy. Today is January third. The time is one oh four pm. The current temperature for Waynesboro is thirty degrees. The current temperature for Ocean City is thirty four degrees."
|
||||
|
||||
> PLEASE RECORD EACH CHILD SAYING THE FOLLOWING PHRASES WITH A SHORT PAUSE BETWEEN EACH ONE:
|
||||
|
||||
Then I provided the following list of words for the children to record:
|
||||
|
||||
_Good
|
||||
morning
|
||||
afternoon
|
||||
evening
|
||||
night_
|
||||
(这个表格有问题,待修复)
|
||||
|
||||
_Nana and Poppy_
|
||||
| - | - | - |
|
||||
| :- | :- | :- |
|
||||
| Good
|
||||
morning
|
||||
afternoon
|
||||
evening
|
||||
night
|
||||
Nana and Poppy
|
||||
The time
|
||||
Today
|
||||
The current temperature for
|
||||
Waynesboro
|
||||
Ocean City
|
||||
is
|
||||
and
|
||||
degrees
|
||||
minus
|
||||
am
|
||||
pm
|
||||
January
|
||||
February
|
||||
March
|
||||
April
|
||||
May | June
|
||||
July
|
||||
August
|
||||
September
|
||||
October
|
||||
November
|
||||
December
|
||||
first
|
||||
second
|
||||
third
|
||||
fourth
|
||||
fifth
|
||||
sixth
|
||||
seventh
|
||||
eighth
|
||||
ninth
|
||||
tenth
|
||||
eleventh
|
||||
twelfth
|
||||
thirteenth
|
||||
fourteenth
|
||||
fifteenth
|
||||
sixteenth
|
||||
seventeenth
|
||||
eighteenth
|
||||
nineteenth
|
||||
twentieth
|
||||
thirtieth
|
||||
oh | one
|
||||
two
|
||||
three
|
||||
four
|
||||
five
|
||||
six
|
||||
seven
|
||||
eight
|
||||
nine
|
||||
ten
|
||||
eleven
|
||||
twelve
|
||||
thirteen
|
||||
fourteen
|
||||
fifteen
|
||||
sixteen
|
||||
seventeen
|
||||
eighteen
|
||||
nineteen
|
||||
twenty
|
||||
thirty
|
||||
forty
|
||||
fifty
|
||||
sixty
|
||||
seventy
|
||||
eighty
|
||||
ninety
|
||||
hundred |
|
||||
|
||||
_The time
|
||||
Today
|
||||
The current temperature for
|
||||
Waynesboro
|
||||
Ocean City
|
||||
is
|
||||
and
|
||||
degrees
|
||||
minus_
|
||||
*Nana and Poppy*
|
||||
|
||||
_am
|
||||
pm_
|
||||
*The time
|
||||
Today
|
||||
The current temperature for
|
||||
Waynesboro
|
||||
Ocean City
|
||||
is
|
||||
and
|
||||
degrees
|
||||
minus*
|
||||
|
||||
_January
|
||||
February
|
||||
March
|
||||
April
|
||||
May_
|
||||
*am
|
||||
pm*
|
||||
|
||||
| _June
|
||||
July
|
||||
August
|
||||
September
|
||||
October
|
||||
November
|
||||
December
|
||||
first
|
||||
second
|
||||
third
|
||||
fourth
|
||||
fifth
|
||||
sixth
|
||||
seventh
|
||||
eighth
|
||||
ninth
|
||||
tenth
|
||||
eleventh
|
||||
twelfth
|
||||
thirteenth
|
||||
fourteenth
|
||||
fifteenth
|
||||
sixteenth
|
||||
seventeenth
|
||||
eighteenth
|
||||
nineteenth
|
||||
twentieth
|
||||
thirtieth
|
||||
oh_ | _one
|
||||
two
|
||||
three
|
||||
four
|
||||
five
|
||||
six
|
||||
seven
|
||||
eight
|
||||
nine
|
||||
ten
|
||||
eleven
|
||||
twelve
|
||||
thirteen
|
||||
fourteen
|
||||
fifteen
|
||||
sixteen
|
||||
seventeen
|
||||
eighteen
|
||||
nineteen
|
||||
twenty
|
||||
thirty
|
||||
forty
|
||||
fifty
|
||||
sixty
|
||||
seventy
|
||||
eighty
|
||||
ninety
|
||||
hundred_
|
||||
---|---|---
|
||||
*January
|
||||
February
|
||||
March
|
||||
April
|
||||
May*
|
||||
|
||||
My nieces are doubly blessed with children under 10 years old and near-infinite patience. So, after a couple of months of prodding, I received a three-minute audio file for each child.
|
||||
|
||||
Now my problem was how to edit them. I needed to normalize the recordings, reduce noise, and chop them into audio clips for individual words and phrases. I also wanted to take advantage of lossless audio, and I decided to convert the tracks to Waveform Audio File Format ([WAV][3]). Audacity was just the open source tool to do all of that.
|
||||
Now my problem was how to edit them. I needed to normalize the recordings, reduce noise, and chop them into audio clips for individual words and phrases. I also wanted to take advantage of lossless audio, and I decided to convert the tracks to Waveform Audio File Format ([WAV][5]). Audacity was just the open source tool to do all of that.
|
||||
|
||||
### Audacity to the rescue!
|
||||
|
||||
[Audacity][4] is a feature-rich open source sound-editing tool. The software's features and capabilities can be overwhelming, so I'll describe the workflow I followed to accomplish my goals. I make no claims to being an Audacity expert, but the steps I followed seemed to work pretty well. (Comments are always welcome on how to improve what I've done.)
|
||||
[Audacity][6] is a feature-rich open source sound-editing tool. The software's features and capabilities can be overwhelming, so I'll describe the workflow I followed to accomplish my goals. I make no claims to being an Audacity expert, but the steps I followed seemed to work pretty well. (Comments are always welcome on how to improve what I've done.)
|
||||
|
||||
Audacity has [downloads][5] for Linux, Windows, and macOS. I grabbed the most recent macOS binary and quickly installed it on my laptop. Launching Audacity opens an empty new project. I imported all of the children's audio files using the **Import** feature.
|
||||
Audacity has [downloads][7] for Linux, Windows, and macOS. I grabbed the most recent macOS binary and quickly installed it on my laptop. Launching Audacity opens an empty new project. I imported all of the children's audio files using the **Import** feature.
|
||||
|
||||
![Import audio files in Audacity][6]
|
||||
|
||||
(Rich Lucente, [CC BY-SA 4.0][7])
|
||||
![Import audio files in Audacity][8]
|
||||
|
||||
#### Normalizing audio files
|
||||
|
||||
Some of the children spoke louder than others, so the various audio files had different volume levels. I needed to normalize the audio tracks so that the greeting's volume would be the same regardless of which child was speaking. To normalize the volumes, I began by selecting all of the audio tracks after they were imported.
|
||||
|
||||
![Selecting all the audio tracks][8]
|
||||
|
||||
(Rich Lucente, [CC BY-SA 4.0][7])
|
||||
![Selecting all the audio tracks][9]
|
||||
|
||||
To normalize the children's peaks and valleys, so one child wasn't louder than the other, I used Audacity's **Normalize** effect.
|
||||
|
||||
![Normalize effect][9]
|
||||
|
||||
(Rich Lucente, [CC BY-SA 4.0][7])
|
||||
![Normalize effect][10]
|
||||
|
||||
It's important to understand that the Normalize and Amplify effects do very different things. Normalize adjusts the highest peaks and lowest valleys for multiple tracks, so they are all similar, whereas Amplify exaggerates the existing peaks and valleys. If I had used Amplify instead of Normalize, the louder child would have become even louder. I used the default settings to normalize the two audio tracks.
|
||||
|
||||
![Normalize defaults][10]
|
||||
|
||||
(Rich Lucente, [CC BY-SA 4.0][7])
|
||||
![Normalize defaults][11]
|
||||
|
||||
#### Remove background noise
|
||||
|
||||
Another thing I noticed is that there was noise between the spoken phrases on the tracks. Audacity has tooling to help reduce background noise and result in much cleaner audio. To reduce noise, select a sample of an audio track with background noise. I used the **View->Zoom** menu option to see the track's noise more easily.
|
||||
Another thing I noticed is that there was noise between the spoken phrases on the tracks. Audacity has tooling to help reduce background noise and result in much cleaner audio. To reduce noise, select a sample of an audio track with background noise. I used the **View->Zoom** menu option to see the track's noise more easily.
|
||||
|
||||
![Background noise sample][11]
|
||||
![Background noise sample][12]
|
||||
|
||||
(Rich Lucente, [CC BY-SA 4.0][7])
|
||||
To make sure I selected only the background noise, I listened to the selected audio clip using the **Play** button in the toolbar. Next, I selected **Effect->Noise Reduction**.
|
||||
|
||||
To make sure I selected only the background noise, I listened to the selected audio clip using the **Play** button in the toolbar. Next, I selected **Effect->Noise Reduction**.
|
||||
|
||||
![Noise Reduction effect][12]
|
||||
|
||||
(Rich Lucente, [CC BY-SA 4.0][7])
|
||||
![Noise Reduction effect][13]
|
||||
|
||||
Then I created a **Noise Profile** using step 1 in the **Noise Reduction** dialog.
|
||||
|
||||
![Get a Noise Profile from audio sample][13]
|
||||
|
||||
(Rich Lucente, [CC BY-SA 4.0][7])
|
||||
![Get a Noise Profile from audio sample][14]
|
||||
|
||||
Audacity characterizes the background noise in the audio sample so that it can be removed. To remove the background noise, I selected the entire audio track by pressing the small **Select** button to the left of the track.
|
||||
|
||||
![Select whole audio track button][14]
|
||||
|
||||
(Rich Lucente, [CC BY-SA 4.0][7])
|
||||
![Select whole audio track button][15]
|
||||
|
||||
I applied the **Noise Reduction** effect again, but this time I pressed **OK** in step 2 of the dialog. I accepted the default settings.
|
||||
|
||||
![Noise Reduction effect step 2][15]
|
||||
|
||||
(Rich Lucente, [CC BY-SA 4.0][7])
|
||||
![Noise Reduction effect step 2][16]
|
||||
|
||||
I repeated these steps for each child's audio track, so I had normalized audio tracks, and the background noise was characterized and removed.
|
||||
|
||||
@@ -194,110 +194,106 @@ I repeated these steps for each child's audio track, so I had normalized audio t
|
||||
|
||||
The remaining task was to zoom and scroll through each track and export the specific clips as separate audio files in WAV format. When working with one child's track, I needed to mute the other tracks using either the small **Mute** button to the left of each audio track or, since there were so many tracks, selecting the **Solo** button for the track I wanted to work with.
|
||||
|
||||
![Mute and Solo buttons for multiple tracks][16]
|
||||
|
||||
(Rich Lucente, [CC BY-SA 4.0][7])
|
||||
![Mute and Solo buttons for multiple tracks][17]
|
||||
|
||||
Selecting each word and phrase can be tricky, but the ability to zoom into an audio track was my friend. I tried to set each audio clip's start and end to just before and just after the word or phrase being spoken. Before exporting any audio clips, I played the selected clip using the **Play** icon on the toolbar to make sure I got it all.
|
||||
|
||||
One interesting thing is how waveforms map to spoken words. The waveforms for "six" and "sixth" are incredibly similar, with the latter having a smaller audio waveform to the right for the "th" sound. I carefully tested each clip before exporting it to make sure I had captured the full word or phrase.
|
||||
|
||||
After selecting an audio clip for a word or phrase, I exported the selected audio using the **File->Export** menu.
|
||||
After selecting an audio clip for a word or phrase, I exported the selected audio using the **File->Export** menu.
|
||||
|
||||
![Exporting selected audio][17]
|
||||
|
||||
(Rich Lucente, [CC BY-SA 4.0][7])
|
||||
![Exporting selected audio][18]
|
||||
|
||||
I had to make sure to save each clip using the correct file name from the list of words and phrases. This is because the application I used to customize the voice assistant expects the file name to match an entry in the phrase list.
|
||||
|
||||
The expected file names for the audio clips (without the .wav extension) are listed below. Note the underscores within the phrases. If you're doing this project, adjust the bold file names to match your loved ones' nicknames and location preferences. You'll also have to make the same changes in the application source code.
|
||||
|
||||
_good
|
||||
morning
|
||||
afternoon
|
||||
evening
|
||||
night
|
||||
**nana_and_poppy**
|
||||
the_time
|
||||
today
|
||||
the_current_temperature_for
|
||||
**waynesboro
|
||||
ocean_city**
|
||||
is
|
||||
and
|
||||
degrees
|
||||
minus
|
||||
am
|
||||
pm
|
||||
january
|
||||
february
|
||||
march
|
||||
april
|
||||
may
|
||||
june
|
||||
july
|
||||
august
|
||||
september
|
||||
october_ | _november
|
||||
december
|
||||
first
|
||||
second
|
||||
third
|
||||
fourth
|
||||
fifth
|
||||
sixth
|
||||
seventh
|
||||
eighth
|
||||
ninth
|
||||
tenth
|
||||
eleventh
|
||||
twelfth
|
||||
thirteenth
|
||||
fourteenth
|
||||
fifteenth
|
||||
sixteenth
|
||||
seventeenth
|
||||
eighteenth
|
||||
nineteenth
|
||||
twentieth
|
||||
thirtieth
|
||||
oh
|
||||
one
|
||||
two_ | _three
|
||||
four
|
||||
five
|
||||
six
|
||||
seven
|
||||
eight
|
||||
nine
|
||||
ten
|
||||
eleven
|
||||
twelve
|
||||
thirteen
|
||||
fourteen
|
||||
fifteen
|
||||
sixteen
|
||||
seventeen
|
||||
eighteen
|
||||
nineteen
|
||||
twenty
|
||||
thirty
|
||||
forty
|
||||
fifty
|
||||
sixty
|
||||
seventy
|
||||
eighty
|
||||
ninety
|
||||
hundred_
|
||||
---|---|---
|
||||
(这个表格有问题,待修正)
|
||||
| - | - | - |
|
||||
| :- | :- | :- |
|
||||
| good
|
||||
morning
|
||||
afternoon
|
||||
evening
|
||||
night
|
||||
nana_and_poppy
|
||||
the_time
|
||||
today
|
||||
the_current_temperature_for
|
||||
waynesboro
|
||||
ocean_city
|
||||
is
|
||||
and
|
||||
degrees
|
||||
minus
|
||||
am
|
||||
pm
|
||||
january
|
||||
february
|
||||
march
|
||||
april
|
||||
may
|
||||
june
|
||||
july
|
||||
august
|
||||
september
|
||||
october | november
|
||||
december
|
||||
first
|
||||
second
|
||||
third
|
||||
fourth
|
||||
fifth
|
||||
sixth
|
||||
seventh
|
||||
eighth
|
||||
ninth
|
||||
tenth
|
||||
eleventh
|
||||
twelfth
|
||||
thirteenth
|
||||
fourteenth
|
||||
fifteenth
|
||||
sixteenth
|
||||
seventeenth
|
||||
eighteenth
|
||||
nineteenth
|
||||
twentieth
|
||||
thirtieth
|
||||
oh
|
||||
one
|
||||
two | three
|
||||
four
|
||||
five
|
||||
six
|
||||
seven
|
||||
eight
|
||||
nine
|
||||
ten
|
||||
eleven
|
||||
twelve
|
||||
thirteen
|
||||
fourteen
|
||||
fifteen
|
||||
sixteen
|
||||
seventeen
|
||||
eighteen
|
||||
nineteen
|
||||
twenty
|
||||
thirty
|
||||
forty
|
||||
fifty
|
||||
sixty
|
||||
seventy
|
||||
eighty
|
||||
ninety
|
||||
hundred |
|
||||
|
||||
This project's GitHub repository also includes a Bash script to run as a sanity check for any missing or misnamed files.
|
||||
|
||||
After choosing each clip's appropriate name, I saved the clip in the child's specific folder (child1, child2, etc.) as a WAV format file. I accepted the default export settings.
|
||||
|
||||
![Converting clip to WAV format][18]
|
||||
|
||||
(Rich Lucente, [CC BY-SA 4.0][7])
|
||||
![Converting clip to WAV format][19]
|
||||
|
||||
After exporting all the audio clips, I had a folder for each child that was fully populated with WAV files for the phrases above. This seems like a lot of work, but it took only about 90 minutes for each child, and I got way more efficient with each successive audio clip.
|
||||
|
||||
@@ -305,22 +301,19 @@ After exporting all the audio clips, I had a folder for each child that was full
|
||||
|
||||
Now that I had the audio clips for the greeting, I needed to think about the application and how to package it. I also wanted an open source-friendly solution that was open to modification.
|
||||
|
||||
About two years ago, a colleague gave me a [Google AIY Voice Kit][19] that he grabbed from the clearance bin for just $10. It's a cleverly folded box containing a speaker, microphone, and custom circuit board. You supply a Raspberry Pi and quickly have a do-it-yourself Google voice assistant. These kits are available for purchase online and in electronics stores. This small box offered an easy way to package the project.
|
||||
About two years ago, a colleague gave me a [Google AIY Voice Kit][20] that he grabbed from the clearance bin for just $10. It's a cleverly folded box containing a speaker, microphone, and custom circuit board. You supply a Raspberry Pi and quickly have a do-it-yourself Google voice assistant. These kits are available for purchase online and in electronics stores. This small box offered an easy way to package the project.
|
||||
|
||||
![Google AIY Voice Kit][20]
|
||||
|
||||
(Rich Lucente, [CC BY-SA 4.0][7])
|
||||
![Google AIY Voice Kit][21]
|
||||
|
||||
### Customize the voice assistant
|
||||
|
||||
The Google kit includes a Python API and several Python modules. I followed the kit's instructions to get the initial configuration working. The [Google Assistant gRPC][21] software is open source under an Apache 2.0 license.
|
||||
The Google kit includes a Python API and several Python modules. I followed the kit's instructions to get the initial configuration working. The [Google Assistant gRPC][22] software is open source under an Apache 2.0 license.
|
||||
|
||||
I adapted the Google Assistant gRPC demo to implement my application. The application's operation is fairly simple: First, it waits for the device's button to be pressed. The code then constructs four separate word lists for: 1. the greeting and date, 2. the current time, 3. the current temperature of the first location, and 4. the current temperature of the second location. The children's voices are randomly shuffled, and then each word list is used to play the audio clips corresponding to the child assigned to that list. (This is why it was important to strictly follow the naming convention for the audio clips.) The application then initiates a conversation with the Google Assistant API.
|
||||
|
||||
At first, I thought the code to gather weather data for the current temperature and convert numbers to words would be challenging. This proved not to be the case at all. In fact, existing open source Python modules made it all simple and intuitive.
|
||||
|
||||
There were two cases to be addressed for converting numbers to word lists: I needed to convert ordinal numbers to words (e.g., 1 and 2 to first and second), and I also needed to convert cardinal numbers to words (e.g., 28 to twenty-eight). The open source [inflect.py module][22] has functions that handle both cases quite easily.
|
||||
|
||||
There were two cases to be addressed for converting numbers to word lists: I needed to convert ordinal numbers to words (e.g., 1 and 2 to first and second), and I also needed to convert cardinal numbers to words (e.g., 28 to twenty-eight). The open source [inflect.py module][23] has functions that handle both cases quite easily.
|
||||
|
||||
```
|
||||
import inflect
|
||||
@@ -337,8 +330,7 @@ print(p.number_to_words(p.ordinal(number)).replace('-', ' ').split(' '))
|
||||
|
||||
The inflect engine returns string representations of the numbers with embedded hyphens (e.g., twenty-three) so that the code splits the strings into variable-length word lists by converting the hyphens to spaces and splitting the string into a list using a space as the delimiter.
|
||||
|
||||
The next problem to solve was getting the current temperature for the two locations. [Open Weather Map][23] offers a free-tier weather service that allows up to 60 calls a minute or 1 million calls a month, which is way more than this project needs. I signed up for the free-tier service and received an API key. It was very easy to access the service by using the open source Python wrapper module [PyOWM][24]. Here is a simplified code snippet:
|
||||
|
||||
The next problem to solve was getting the current temperature for the two locations. [Open Weather Map][24] offers a free-tier weather service that allows up to 60 calls a minute or 1 million calls a month, which is way more than this project needs. I signed up for the free-tier service and received an API key. It was very easy to access the service by using the open source Python wrapper module [PyOWM][25]. Here is a simplified code snippet:
|
||||
|
||||
```
|
||||
import pyowm
|
||||
@@ -359,46 +351,49 @@ temp = round(observation.weather.temperature('fahrenheit')['temp'])
|
||||
|
||||
### Wrapping it up with a bow
|
||||
|
||||
The full source code for the project is available in my [GitHub repository][25]. The project includes a systemd service unit file adapted from Google's demo to automatically start the application on device boot. The GitHub repository includes instructions to install the Python modules and configure the systemd service.
|
||||
The full source code for the project is available in my [GitHub repository][26]. The project includes a systemd service unit file adapted from Google's demo to automatically start the application on device boot. The GitHub repository includes instructions to install the Python modules and configure the systemd service.
|
||||
|
||||
I created a [short video][26] of the result. Five custom voice assistants were distributed during the holidays: one each for the great grandparents and grandparents of each child. For some, these gifts brought tears of joy. The children's voices are absolutely adorable and these boxes capture a fleeting moment of childhood that can be enjoyed for a very long time.
|
||||
I created a [short video][27] of the result. Five custom voice assistants were distributed during the holidays: one each for the great grandparents and grandparents of each child. For some, these gifts brought tears of joy. The children's voices are absolutely adorable and these boxes capture a fleeting moment of childhood that can be enjoyed for a very long time.
|
||||
|
||||
Image by: (Rich Lucente, CC BY-SA 4.0)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/customize-voice-assistant
|
||||
|
||||
作者:[Rich Lucente][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/rlucente
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/sound-radio-noise-communication.png?itok=KMNn9QrZ (radio communication signals)
|
||||
[2]: https://opensource.com/article/20/7/mycroft-voice-skill
|
||||
[3]: https://en.wikipedia.org/wiki/WAV
|
||||
[4]: https://www.audacityteam.org/
|
||||
[5]: https://www.audacityteam.org/download/
|
||||
[6]: https://opensource.com/sites/default/files/uploads/audacity1_importaudio.png (Import audio files in Audacity)
|
||||
[7]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[8]: https://opensource.com/sites/default/files/uploads/audacity2_selectingtracks.png (Selecting all the audio tracks)
|
||||
[9]: https://opensource.com/sites/default/files/uploads/audacity3_normalize.png (Normalize effect)
|
||||
[10]: https://opensource.com/sites/default/files/uploads/audacity4_normalizedefaults.png (Normalize defaults)
|
||||
[11]: https://opensource.com/sites/default/files/uploads/audacity5_backgroundnoise.png (Background noise sample)
|
||||
[12]: https://opensource.com/sites/default/files/uploads/audacity6_noisereduction.png (Noise Reduction effect)
|
||||
[13]: https://opensource.com/sites/default/files/uploads/audacity7_noiseprofile.png (Get a Noise Profile from audio sample)
|
||||
[14]: https://opensource.com/sites/default/files/uploads/audacity8_selecttrack.png (Select whole audio track button)
|
||||
[15]: https://opensource.com/sites/default/files/uploads/audacity9_noisereduction2.png (Noise Reduction effect step 2)
|
||||
[16]: https://opensource.com/sites/default/files/uploads/audacity10_mutesolo.png (Mute and Solo buttons for multiple tracks)
|
||||
[17]: https://opensource.com/sites/default/files/uploads/audacity11_exportaudio.png (Exporting selected audio)
|
||||
[18]: https://opensource.com/sites/default/files/uploads/audacity12_convertwav.png (Converting clip to WAV format)
|
||||
[19]: https://aiyprojects.withgoogle.com/voice/
|
||||
[20]: https://opensource.com/sites/default/files/uploads/googleaiy.png (Google AIY Voice Kit)
|
||||
[21]: https://pypi.org/project/google-assistant-grpc/
|
||||
[22]: https://pypi.org/project/inflect
|
||||
[23]: https://openweathermap.org/
|
||||
[24]: https://pypi.org/project/pyowm
|
||||
[25]: https://github.com/rlucente-se-jboss/nana-poppy-project
|
||||
[26]: https://youtu.be/Co7rigJRNUM
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/sound-radio-noise-communication.png
|
||||
[2]: https://www.flickr.com/photos/internetarchivebookimages/14571450820/in/photolist-ocCuEG-otg1AX-hPy8JE-oc9YmN-oeUU2C-8cKWej-hQz72S-rpae2k-ocNYbT-oxbPTB-odGRsQ-ouDBo1-i5GTL8-qscJfA-idDrfk-i5D6oK-6K6iNH-ouxpn7-i8SivQ-oeY1eG-i7HGbT-bqXPhH-hN5on7-i9Q8YD-ouFYDw-fpy7Lo-oeSJo1-otqUu4-hNaVhf-oydqAV-owur2M-owkTSD-oydSWR-ocayce-ovFdYk-ocdaeL-ouE9UP-zmmrhp-qxtozB-ouqnSQ-obYbwS-odrnXt-ousXXw-ocA6Uo-owme9S-ouACY2-ocajY1-oeUJQG-ouryBk-ouxMJb
|
||||
[3]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[4]: https://opensource.com/article/20/7/mycroft-voice-skill
|
||||
[5]: https://en.wikipedia.org/wiki/WAV
|
||||
[6]: https://www.audacityteam.org/
|
||||
[7]: https://www.audacityteam.org/download/
|
||||
[8]: https://opensource.com/sites/default/files/uploads/audacity1_importaudio.png
|
||||
[9]: https://opensource.com/sites/default/files/uploads/audacity2_selectingtracks.png
|
||||
[10]: https://opensource.com/sites/default/files/uploads/audacity3_normalize.png
|
||||
[11]: https://opensource.com/sites/default/files/uploads/audacity4_normalizedefaults.png
|
||||
[12]: https://opensource.com/sites/default/files/uploads/audacity5_backgroundnoise.png
|
||||
[13]: https://opensource.com/sites/default/files/uploads/audacity6_noisereduction.png
|
||||
[14]: https://opensource.com/sites/default/files/uploads/audacity7_noiseprofile.png
|
||||
[15]: https://opensource.com/sites/default/files/uploads/audacity8_selecttrack.png
|
||||
[16]: https://opensource.com/sites/default/files/uploads/audacity9_noisereduction2.png
|
||||
[17]: https://opensource.com/sites/default/files/uploads/audacity10_mutesolo.png
|
||||
[18]: https://opensource.com/sites/default/files/uploads/audacity11_exportaudio.png
|
||||
[19]: https://opensource.com/sites/default/files/uploads/audacity12_convertwav.png
|
||||
[20]: https://aiyprojects.withgoogle.com/voice/
|
||||
[21]: https://opensource.com/sites/default/files/uploads/googleaiy.png
|
||||
[22]: https://pypi.org/project/google-assistant-grpc/
|
||||
[23]: https://pypi.org/project/inflect
|
||||
[24]: https://openweathermap.org/
|
||||
[25]: https://pypi.org/project/pyowm
|
||||
[26]: https://github.com/rlucente-se-jboss/nana-poppy-project
|
||||
[27]: https://youtu.be/Co7rigJRNUM
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (A hands-on tutorial for using the GNU Project Debugger)
|
||||
[#]: via: (https://opensource.com/article/21/1/gnu-project-debugger)
|
||||
[#]: author: (Stephan Avenwedde https://opensource.com/users/hansic99)
|
||||
[#]: subject: "A hands-on tutorial for using the GNU Project Debugger"
|
||||
[#]: via: "https://opensource.com/article/21/1/gnu-project-debugger"
|
||||
[#]: author: "Stephan Avenwedde https://opensource.com/users/hansic99"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
A hands-on tutorial for using the GNU Project Debugger
|
||||
======
|
||||
The GNU Project Debugger is a powerful tool for finding bugs in
|
||||
programs.
|
||||
The GNU Project Debugger is a powerful tool for finding bugs in programs.
|
||||
|
||||
![magnifying glass on computer screen, finding a bug in the code][1]
|
||||
|
||||
Image by: Opensource.com
|
||||
|
||||
If you're a programmer and you want to put a certain functionality in your software, you start by thinking of ways to implement it—such as writing a method, defining a class, or creating new data types. Then you write the implementation in a language that the compiler or interpreter can understand. But what if the compiler or interpreter does not understand the instructions as you had them in mind, even though you're sure you did everything right? What if the software works fine most of the time but causes bugs in certain circumstances? In these cases, you have to know how to use a debugger correctly to find the source of your troubles.
|
||||
|
||||
The GNU Project Debugger ([GDB][2]) is a powerful tool for finding bugs in programs. It helps you uncover the reason for an error or crash by tracking what is going on inside the program during execution.
|
||||
|
||||
This article is a hands-on tutorial on basic GDB usage. To follow along with the examples, open the command line and clone this repository:
|
||||
|
||||
|
||||
```
|
||||
`git clone https://github.com/hANSIc99/core_dump_example.git`
|
||||
git clone https://github.com/hANSIc99/core_dump_example.git
|
||||
```
|
||||
|
||||
### Shortcuts
|
||||
@@ -30,7 +31,7 @@ Every command in GDB can be shortened. For example, `info break`, which shows th
|
||||
|
||||
### Command-line parameters
|
||||
|
||||
You can attach GDB to every executable. Navigate to the repository you cloned, and compile it by running `make`. You should now have an executable called **coredump**. (See my article on [_Creating and debugging Linux dump files_][3] for more information..
|
||||
You can attach GDB to every executable. Navigate to the repository you cloned, and compile it by running `make`. You should now have an executable called **coredump**. (See my article on [Creating and debugging Linux dump files][3] for more information..
|
||||
|
||||
To attach GDB to the executable, type: `gdb coredump`.
|
||||
|
||||
@@ -38,87 +39,66 @@ Your output should look like this:
|
||||
|
||||
![gdb coredump output][4]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
It says no debugging symbols were found.
|
||||
|
||||
Debugging information is part of the object file (the executable) and includes data types, function signatures, and the relationship between the source code and the opcode. At this point, you have two options:
|
||||
|
||||
* Continue debugging the assembly (see "[Debug without symbols][6]" below)
|
||||
* Compile with debug information using the information in the next section
|
||||
|
||||
|
||||
* Continue debugging the assembly (see "Debug without symbols" below)
|
||||
* Compile with debug information using the information in the next section
|
||||
|
||||
### Compile with debug information
|
||||
|
||||
To include debug information in the binary file, you have to recompile it. Open the **Makefile** and remove the hashtag (`#`) from line 9:
|
||||
|
||||
To include debug information in the binary file, you have to recompile it. Open the **Makefile** and remove the hashtag (`#` ) from line 9:
|
||||
|
||||
```
|
||||
`CFLAGS =-Wall -Werror -std=c++11 -g`
|
||||
CFLAGS =-Wall -Werror -std=c++11 -g
|
||||
```
|
||||
|
||||
The `g` option tells the compiler to include the debug information. Run `make clean` followed by `make` and invoke GDB again. You should get this output and can start debugging the code:
|
||||
|
||||
![GDB output with symbols][7]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![GDB output with symbols][5]
|
||||
|
||||
The additional debugging information will increase the size of the executable. In this case, it increases the executable by 2.5 times (from 26,088 byte to 65,480 byte).
|
||||
|
||||
Start the program with the `-c1` switch by typing `run -c1`. The program will start and crash when it reaches `State_4`:
|
||||
Start the program with the `-c1` switch by typing `run -c1`. The program will start and crash when it reaches `State_4` :
|
||||
|
||||
![gdb output crash on c1 switch][8]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![gdb output crash on c1 switch][6]
|
||||
|
||||
You can retrieve additional information about the program. The command `info source` provides information about the current file:
|
||||
|
||||
![gdb info source output][9]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
* 101 lines
|
||||
* Language: C++
|
||||
* Compiler (version, tuning, architecture, debug flag, language standard)
|
||||
* Debugging format: [DWARF 2][10]
|
||||
* No preprocessor macro information available (when compiled with GCC, macros are available only when [compiled with the `-g3` flag][11]).
|
||||
![gdb info source output][7]
|
||||
|
||||
|
||||
* 101 lines
|
||||
* Language: C++
|
||||
* Compiler (version, tuning, architecture, debug flag, language standard)
|
||||
* Debugging format: [DWARF 2][8]
|
||||
* No preprocessor macro information available (when compiled with GCC, macros are available only when [compiled with the `-g3` flag][9]).
|
||||
|
||||
The command `info shared` prints a list of dynamic libraries with their addresses in the virtual address space that was loaded on startup so that the program will execute:
|
||||
|
||||
![gdb info shared output][12]
|
||||
![gdb info shared output][10]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
If you want to learn about library handling in Linux, see my article [_How to handle dynamic and static libraries in Linux_][13].
|
||||
If you want to learn about library handling in Linux, see my article [How to handle dynamic and static libraries in Linux][11].
|
||||
|
||||
### Debug the program
|
||||
|
||||
You may have noticed that you can start the program inside GDB with the `run` command. The `run` command accepts command-line arguments like you would use to start the program from the console. The `-c1` switch will cause the program to crash on stage 4. To run the program from the beginning, you don't have to quit GDB; simply use the `run` command again. Without the `-c1` switch, the program executes an infinite loop. You would have to stop it with **Ctrl+C**.
|
||||
|
||||
![gdb output stopped by sigint][14]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![gdb output stopped by sigint][12]
|
||||
|
||||
You can also execute a program step by step. In C/C++, the entry point is the `main` function. Use the command `list main` to open the part of the source code that shows the `main` function:
|
||||
|
||||
![gdb output list main][15]
|
||||
![gdb output list main][13]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
The `main` function is on line 33, so add a breakpoint there by typing `break 33` :
|
||||
|
||||
The `main` function is on line 33, so add a breakpoint there by typing `break 33`:
|
||||
|
||||
![gdb output breakpoint added][16]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![gdb output breakpoint added][14]
|
||||
|
||||
Run the program by typing `run`. As expected, the program stops at the `main` function. Type `layout src` to show the source code in parallel:
|
||||
|
||||
![gdb output break at main][17]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![gdb output break at main][15]
|
||||
|
||||
You are now in GDB's text user interface (TUI) mode. Use the Up and Down arrow keys to scroll through the source code.
|
||||
|
||||
@@ -126,13 +106,11 @@ GDB highlights the line to be executed. By typing `next` (n), you can execute th
|
||||
|
||||
From time to time, you will notice that TUI's output gets a bit corrupted:
|
||||
|
||||
![gdb output corrupted][18]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![gdb output corrupted][16]
|
||||
|
||||
If this happens, press **Ctrl+L** to reset the screen.
|
||||
|
||||
Use **Ctrl+X+A** to enter and leave TUI mode at will. You can find [other key bindings][19] in the manual.
|
||||
Use **Ctrl+X+A** to enter and leave TUI mode at will. You can find [other key bindings][17] in the manual.
|
||||
|
||||
To quit GDB, simply type `quit`.
|
||||
|
||||
@@ -140,45 +118,39 @@ To quit GDB, simply type `quit`.
|
||||
|
||||
The heart of this example program consists of a state machine running in an infinite loop. The variable `n_state` is a simple enum that determines the current state:
|
||||
|
||||
|
||||
```
|
||||
while(true){
|
||||
switch(n_state){
|
||||
case State_1:
|
||||
std::cout << "State_1 reached" << std::flush;
|
||||
std::cout << "State_1 reached" << std::flush;
|
||||
n_state = State_2;
|
||||
break;
|
||||
case State_2:
|
||||
std::cout << "State_2 reached" << std::flush;
|
||||
std::cout << "State_2 reached" << std::flush;
|
||||
n_state = State_3;
|
||||
break;
|
||||
|
||||
|
||||
(.....)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You want to stop the program when `n_state` is set to the value `State_5`. To do so, stop the program at the `main` function and set a watchpoint for `n_state`:
|
||||
|
||||
You want to stop the program when `n_state` is set to the value `State_5`. To do so, stop the program at the `main` function and set a watchpoint for `n_state` :
|
||||
|
||||
```
|
||||
`watch n_state == State_5`
|
||||
watch n_state == State_5
|
||||
```
|
||||
|
||||
Setting watchpoints with the variable name works only if the desired variable is available in the current context.
|
||||
|
||||
When you continue the program's execution by typing `continue`, you should get output like:
|
||||
|
||||
![gdb output stop on watchpoint_1][20]
|
||||
![gdb output stop on watchpoint_1][18]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
If you continue the execution, GDB will stop when the watchpoint expression evaluates to `false` :
|
||||
|
||||
If you continue the execution, GDB will stop when the watchpoint expression evaluates to `false`:
|
||||
|
||||
![gdb output stop on watchpoint_2][21]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![gdb output stop on watchpoint_2][19]
|
||||
|
||||
You can specify watchpoints for general value changes, specific values, and read or write access.
|
||||
|
||||
@@ -186,21 +158,17 @@ You can specify watchpoints for general value changes, specific values, and read
|
||||
|
||||
Type `info watchpoints` to print a list of previously set watchpoints:
|
||||
|
||||
![gdb output info watchpoints][22]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![gdb output info watchpoints][20]
|
||||
|
||||
#### Delete breakpoints and watchpoints
|
||||
|
||||
As you can see, watchpoints are numbers. To delete a specific watchpoint, type `delete` followed by the number of the watchpoint. For example, my watchpoint has the number 2; to remove this watchpoint, enter `delete 2`.
|
||||
|
||||
_Caution:_ If you use `delete` without specifying a number, _all_ watchpoints and breakpoints will be deleted.
|
||||
*Caution:* If you use `delete` without specifying a number, *all* watchpoints and breakpoints will be deleted.
|
||||
|
||||
The same applies to breakpoints. In the screenshot below, I added several breakpoints and printed a list of them by typing `info breakpoint`:
|
||||
The same applies to breakpoints. In the screenshot below, I added several breakpoints and printed a list of them by typing `info breakpoint` :
|
||||
|
||||
![gdb output info breakpoints][23]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![gdb output info breakpoints][21]
|
||||
|
||||
To remove a single breakpoint, type `delete` followed by its number. Alternatively, you can remove a breakpoint by specifying its line number. For example, the command `clear 78` will remove breakpoint number 7, which is set on line 78.
|
||||
|
||||
@@ -208,9 +176,7 @@ To remove a single breakpoint, type `delete` followed by its number. Alternative
|
||||
|
||||
Instead of removing a breakpoint or watchpoint, you can disable it by typing `disable` followed by its number. In the following, breakpoints 3 and 4 are disabled and are marked with a minus sign in the code window:
|
||||
|
||||
![disabled breakpoints][24]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![disabled breakpoints][22]
|
||||
|
||||
It is also possible to modify a range of breakpoints or watchpoints by typing something like `disable 2 - 4`. If you want to reactivate the points, type `enable` followed by their numbers.
|
||||
|
||||
@@ -224,40 +190,31 @@ The `main` function includes the variable `n_state_3_count`, which is incremente
|
||||
|
||||
To add a conditional breakpoint based on the value of `n_state_3_count` type:
|
||||
|
||||
|
||||
```
|
||||
`break 54 if n_state_3_count == 3`
|
||||
break 54 if n_state_3_count == 3
|
||||
```
|
||||
|
||||
![Set conditional breakpoint][25]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![Set conditional breakpoint][23]
|
||||
|
||||
Continue the execution. The program will execute the state machine three times before it stops at line 54. To check the value of `n_state_3_count`, type:
|
||||
|
||||
|
||||
```
|
||||
`print n_state_3_count`
|
||||
print n_state_3_count
|
||||
```
|
||||
|
||||
![print variable][26]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![print variable][24]
|
||||
|
||||
#### Make breakpoints conditional
|
||||
|
||||
It is also possible to make an existing breakpoint conditional. Remove the recently added breakpoint with `clear 54`, and add a simple breakpoint by typing `break 54`. You can make this breakpoint conditional by typing:
|
||||
|
||||
|
||||
```
|
||||
`condition 3 n_state_3_count == 9`
|
||||
condition 3 n_state_3_count == 9
|
||||
```
|
||||
|
||||
The `3` refers to the breakpoint number.
|
||||
|
||||
![modify breakpoint][27]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![modify breakpoint][25]
|
||||
|
||||
#### Set breakpoints in other source files
|
||||
|
||||
@@ -269,143 +226,109 @@ In addition to breakpoints and watchpoints, you can also set catchpoints. Catchp
|
||||
|
||||
To catch the `write` syscall, which is used to write to STDOUT, enter:
|
||||
|
||||
|
||||
```
|
||||
`catch syscall write`
|
||||
catch syscall write
|
||||
```
|
||||
|
||||
![catch syscall write output][28]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![catch syscall write output][26]
|
||||
|
||||
Each time the program writes to the console output, GDB will interrupt execution.
|
||||
|
||||
In the manual, you can find a whole chapter [covering break-, watch-, and catchpoints][29].
|
||||
In the manual, you can find a whole chapter [covering break-, watch-, and catchpoints][27].
|
||||
|
||||
### Evaluate and manipulate symbols
|
||||
|
||||
Printing the values of variables is done with the `print` command. The general syntax is `print <expression> <value>`. The value of a variable can be modified by typing:
|
||||
|
||||
|
||||
```
|
||||
`set variable <variable-name> <new-value>.`
|
||||
set variable <variable-name> <new-value>.
|
||||
```
|
||||
|
||||
In the screenshot below, I gave the variable `n_state_3_count` the value _123_.
|
||||
In the screenshot below, I gave the variable `n_state_3_count` the value *123*.
|
||||
|
||||
![print variable][30]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![catch syscall write output][28]
|
||||
|
||||
The `/x` expression prints the value in hexadecimal; with the `&` operator, you can print the address within the virtual address space.
|
||||
|
||||
If you are not sure of a certain symbol's data type, you can find it with `whatis`:
|
||||
If you are not sure of a certain symbol's data type, you can find it with `whatis` :
|
||||
|
||||
![whatis output][31]
|
||||
![whatis output][29]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
If you want to list all variables that are available in the scope of the `main` function, type `info scope main` :
|
||||
|
||||
If you want to list all variables that are available in the scope of the `main` function, type `info scope main`:
|
||||
|
||||
![info scope main output][32]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![info scope main output][30]
|
||||
|
||||
The `DW_OP_fbreg` values refer to the stack offset based on the current subroutine.
|
||||
|
||||
Alternatively, if you are already inside a function and want to list all variables on the current stack frame, you can use `info locals`:
|
||||
Alternatively, if you are already inside a function and want to list all variables on the current stack frame, you can use `info locals` :
|
||||
|
||||
![info locals output][33]
|
||||
![info locals output][31]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
Check the manual to learn more about [examining symbols][34].
|
||||
Check the manual to learn more about [examining symbols][32].
|
||||
|
||||
### Attach to a running process
|
||||
|
||||
The command `gdb attach <process-id>` allows you to attach to an already running process by specifying the process ID (PID). Luckily, the `coredump` program prints its current PID to the screen, so you don't have to manually find it with [ps][35] or [top][36].
|
||||
The command `gdb attach <process-id>` allows you to attach to an already running process by specifying the process ID (PID). Luckily, the `coredump` program prints its current PID to the screen, so you don't have to manually find it with [ps][33] or [top][34].
|
||||
|
||||
Start an instance of the coredump application:
|
||||
|
||||
|
||||
```
|
||||
`./coredump`
|
||||
./coredump
|
||||
```
|
||||
|
||||
![coredump application][37]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![coredump application][35]
|
||||
|
||||
The operating system gives the PID `2849`. Open a separate console window, move to the coredump application's source directory, and attach GDB:
|
||||
|
||||
|
||||
```
|
||||
`gdb attach 2849`
|
||||
gdb attach 2849
|
||||
```
|
||||
|
||||
![attach GDB to coredump][38]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![attach GDB to coredump][36]
|
||||
|
||||
GDB immediately stops the execution when you attach it. Type `layout src` and `backtrace` to examine the call stack:
|
||||
|
||||
![layout src and backtrace output][39]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![layout src and backtrace output][37]
|
||||
|
||||
The output shows the process interrupted while executing the `std::this_thread::sleep_for<...>(...)` function that was called in line 92 of `main.cpp`.
|
||||
|
||||
As soon as you quit GDB, the process will continue running.
|
||||
|
||||
You can find more information about [attaching to a running process][40] in the GDB manual.
|
||||
You can find more information about [attaching to a running process][38] in the GDB manual.
|
||||
|
||||
#### Move through the stack
|
||||
|
||||
Return to the program by using `up` two times to move up in the stack to `main.cpp`:
|
||||
Return to the program by using `up` two times to move up in the stack to `main.cpp` :
|
||||
|
||||
![moving up the stack to main.cpp][41]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
![moving up the stack to main.cpp][39]
|
||||
|
||||
Usually, the compiler will create a subroutine for each function or method. Each subroutine has its own stack frame, so moving upwards in the stackframe means moving upwards in the callstack.
|
||||
|
||||
You can find out more about [stack evaluation][42] in the manual.
|
||||
You can find out more about [stack evaluation][40] in the manual.
|
||||
|
||||
#### Specify the source files
|
||||
|
||||
When attaching to an already running process, GDB will look for the source files in the current working directory. Alternatively, you can specify the source directories manually with the [`directory` command][43].
|
||||
When attaching to an already running process, GDB will look for the source files in the current working directory. Alternatively, you can specify the source directories manually with the [directory command][41].
|
||||
|
||||
### Evaluate dump files
|
||||
|
||||
Read [_Creating and debugging Linux dump files_][3] for information about this topic.
|
||||
Read [Creating and debugging Linux dump files][42] for information about this topic.
|
||||
|
||||
TL;DR:
|
||||
|
||||
1. I assume you're working with a recent version of Fedora
|
||||
|
||||
2. Invoke coredump with the c1 switch: `coredump -c1`
|
||||
1. I assume you're working with a recent version of Fedora
|
||||
2. Invoke coredump with the c1 switch: `coredump -c1`
|
||||
3. Load the latest dumpfile with GDB: `coredumpctl debug`
|
||||
4. Open TUI mode and enter `layout src`
|
||||
|
||||
![Crash meme][44]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
3. Load the latest dumpfile with GDB: `coredumpctl debug`
|
||||
|
||||
4. Open TUI mode and enter `layout src`
|
||||
|
||||
|
||||
|
||||
|
||||
![coredump output][45]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
The output of `backtrace` shows that the crash happened five stack frames away from `main.cpp`. Enter to jump directly to the faulty line of code in `main.cpp`:
|
||||
The output of `backtrace` shows that the crash happened five stack frames away from `main.cpp`. Enter to jump directly to the faulty line of code in `main.cpp` :
|
||||
|
||||
![up 5 output][46]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
A look at the source code shows that the program tried to free a pointer that was not returned by a memory management function. This results in undefined behavior and caused the `SIGABRT`.
|
||||
|
||||
### Debug without symbols
|
||||
@@ -416,56 +339,43 @@ Check out how it works with this example.
|
||||
|
||||
Go to the source directory, open the **Makefile**, and edit line 9 like this:
|
||||
|
||||
|
||||
```
|
||||
`CFLAGS =-Wall -Werror -std=c++11 #-g`
|
||||
CFLAGS =-Wall -Werror -std=c++11 #-g
|
||||
```
|
||||
|
||||
To recompile the program, run `make clean` followed by `make` and start GDB. The program no longer has any debugging symbols to lead the way through the source code.
|
||||
To recompile the program, run `make clean` followed by `make` and start GDB. The program no longer has any debugging symbols to lead the way through the source code.
|
||||
|
||||
![no debugging symbols][48]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
The command `info file` reveals the memory areas and entry point of the binary:
|
||||
|
||||
![info file output][49]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
The entry point corresponds with the beginning of the `.text` area, which contains the actual opcode. To add a breakpoint at the entry point, type `break *0x401110` then start execution by typing `run`:
|
||||
The entry point corresponds with the beginning of the `.text` area, which contains the actual opcode. To add a breakpoint at the entry point, type `break *0x401110` then start execution by typing `run` :
|
||||
|
||||
![breakpoint at the entry point][50]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
To set up a breakpoint at a certain address, specify it with the dereferencing operator `*`.
|
||||
|
||||
#### Choose the disassembler flavor
|
||||
|
||||
Before digging deeper into assembly, you can choose which [assembly flavor][51] to use. GDB's default is AT&T, but I prefer the Intel syntax. Change it with:
|
||||
|
||||
Before digging deeper into assembly, you can choose which [assembly flavor][51] to use. GDB's default is AT&T, but I prefer the Intel syntax. Change it with:
|
||||
|
||||
```
|
||||
`set disassembly-flavor intel`
|
||||
set disassembly-flavor intel
|
||||
```
|
||||
|
||||
![changing assembly flavor][52]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
Now open the assembly and register the window by typing `layout asm` and `layout reg`. You should now see output like this:
|
||||
|
||||
![layout asm and layout reg output][53]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
#### Save configuration files
|
||||
|
||||
Although you have already entered many commands, you haven't actually started debugging. If you are heavily debugging an application or trying to solve a reverse-engineering challenge, it can be useful to save your GDB-specific settings in a file.
|
||||
|
||||
The [config file `gdbinit`][54] in this project's GitHub repository contains the recently used commands:
|
||||
|
||||
The [config file gdbinit][54] in this project's GitHub repository contains the recently used commands:
|
||||
|
||||
```
|
||||
set disassembly-flavor intel
|
||||
@@ -486,11 +396,9 @@ With the `c2` switch applied, the program will crash. The program stops at the e
|
||||
|
||||
![continuing execution after crash][55]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
The `idiv` instruction performs an integer division with the dividend in the `RAX` register and the divisor specified as an argument. The quotient is loaded into the `RAX` register, and the remainder is loaded into `RDX`.
|
||||
|
||||
From the register overview, you can see the `RAX` contains _5_, so you have to find out which value is stored on the stack at position `RBP-0x4`.
|
||||
From the register overview, you can see the `RAX` contains *5*, so you have to find out which value is stored on the stack at position `RBP-0x4`.
|
||||
|
||||
#### Read memory
|
||||
|
||||
@@ -498,71 +406,58 @@ To read raw memory content, you must specify a few more parameters than for read
|
||||
|
||||
![stack division output][56]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
You're most interested in the value of `rbp-0x4` because this is the position where the argument for `idiv` is stored. From the screenshot, you can see that the next variable is located at `rbp-0x8`, so the variable at `rbp-0x4` is 4 bytes wide.
|
||||
|
||||
In GDB, you can use the `x` command to _examine_ any memory content:
|
||||
In GDB, you can use the `x` command to *examine* any memory content:
|
||||
|
||||
> `x/` < optional parameter `n` `f` `u` > < memory address `addr` >
|
||||
> `x/` < optional parameter `n` `f` `u` > < memory address `addr` >
|
||||
|
||||
Optional parameters:
|
||||
|
||||
* `n`: Repeat count (default: 1) refers to the unit size
|
||||
* `f`: Format specifier, like in [printf][57]
|
||||
* `u`: Unit size
|
||||
* `b`: bytes
|
||||
* `h`: half words (2 bytes)
|
||||
* `w`: word (4 bytes)(default)
|
||||
* `g`: giant word (8 bytes)
|
||||
* n: Repeat count (default: 1) refers to the unit size
|
||||
* f: Format specifier, like in [printf][57]
|
||||
* u: Unit size
|
||||
* b: `b`ytes
|
||||
h: `h`alf `w`ords (2 bytes)
|
||||
w: word (4 bytes)(default)
|
||||
* g: `g`iant word (8 bytes)
|
||||
|
||||
|
||||
|
||||
To print out the value at `rbp-0x4`, type `x/u $rbp-4`:
|
||||
To print out the value at `rbp-0x4`, type `x/u $rbp-4` :
|
||||
|
||||
![print value][58]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
If you keep this pattern in mind, it's straightforward to examine the memory. Check the [examining memory][59] section in the manual.
|
||||
|
||||
#### Manipulate the assembly
|
||||
|
||||
The arithmetic exception happened in the subroutine `zeroDivide()`. When you scroll a bit upward with the Up arrow key, you can find this pattern:
|
||||
|
||||
|
||||
```
|
||||
0x401211 <_Z10zeroDividev> push rbp
|
||||
0x401212 <_Z10zeroDividev+1> mov rbp,rsp
|
||||
0x401211 <_Z10zeroDividev> push rbp
|
||||
0x401212 <_Z10zeroDividev+1> mov rbp,rsp
|
||||
```
|
||||
|
||||
This is called the [function prologue][60]:
|
||||
|
||||
1. The base pointer (`rbp`) of the calling function is stored on the stack
|
||||
2. The value of the stack pointer (`rsp`) is loaded to the base pointer (`rbp`)
|
||||
1. The base pointer (rbp) of the calling function is stored on the stack
|
||||
2. The value of the stack pointer (rsp) is loaded to the base pointer (rbp)
|
||||
|
||||
|
||||
|
||||
Skip this subroutine completely. You can check the call stack with `backtrace`. You are only one stack frame ahead of your `main` function, so you can go back to `main` with a single `up`:
|
||||
Skip this subroutine completely. You can check the call stack with `backtrace`. You are only one stack frame ahead of your `main` function, so you can go back to `main` with a single `up` :
|
||||
|
||||
![Callstack assembly][61]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
In your `main` function, you can find this pattern:
|
||||
|
||||
|
||||
```
|
||||
0x401431 <main+497> cmp BYTE PTR [rbp-0x12],0x0
|
||||
0x401435 <main+501> je 0x40145f <main+543>
|
||||
0x401437 <main+503> call 0x401211<_Z10zeroDividev>
|
||||
0x401431 <main+497> cmp BYTE PTR [rbp-0x12],0x0
|
||||
0x401435 <main+501> je 0x40145f <main+543>
|
||||
0x401437 <main+503> call 0x401211<_Z10zeroDividev>
|
||||
```
|
||||
|
||||
The subroutine `zeroDivide()` is entered only when `jump equal (je)` evaluates to `true`. You can easily replace this with a `jump-not-equal (jne)` instruction, which has the opcode `0x75` (provided you are on an x86/64 architecture; the opcodes are different on other architectures). Restart the program by typing `run`. When the program stops at the entry function, manipulate the opcode by typing:
|
||||
|
||||
|
||||
```
|
||||
`set *(unsigned char*)0x401435 = 0x75`
|
||||
set *(unsigned char*)0x401435 = 0x75
|
||||
```
|
||||
|
||||
Finally, type `continue`. The program will skip the subroutine `zeroDivide()` and won't crash anymore.
|
||||
@@ -573,8 +468,6 @@ You can find GDB working in the background in many integrated development enviro
|
||||
|
||||
![GDB in VSCodium][63]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][5])
|
||||
|
||||
It's useful to know how to leverage GDB's functionality. Usually, not all of GDB's functions can be used from the IDE, so you benefit from having experience using GDB from the command line.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
@@ -582,74 +475,74 @@ It's useful to know how to leverage GDB's functionality. Usually, not all of GDB
|
||||
via: https://opensource.com/article/21/1/gnu-project-debugger
|
||||
|
||||
作者:[Stephan Avenwedde][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/hansic99
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/mistake_bug_fix_find_error.png?itok=PZaz3dga (magnifying glass on computer screen, finding a bug in the code)
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/mistake_bug_fix_find_error.png
|
||||
[2]: https://www.gnu.org/software/gdb/
|
||||
[3]: https://opensource.com/article/20/8/linux-dump
|
||||
[4]: https://opensource.com/sites/default/files/uploads/gdb_output_no_dbg_symbols.png (gdb coredump output)
|
||||
[5]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[6]: tmp.2p0XrqmAS5#without_symbols
|
||||
[7]: https://opensource.com/sites/default/files/uploads/gdb_output_with_symbols.png (GDB output with symbols)
|
||||
[8]: https://opensource.com/sites/default/files/uploads/gdb_output_crash_on_c1_switch.png (gdb output crash on c1 switch)
|
||||
[9]: https://opensource.com/sites/default/files/uploads/gdb_output_info_source.png (gdb info source output)
|
||||
[10]: http://dwarfstd.org/
|
||||
[11]: https://sourceware.org/gdb/current/onlinedocs/gdb/Compilation.html#Compilation
|
||||
[12]: https://opensource.com/sites/default/files/uploads/gdb_output_info_shared.png (gdb info shared output)
|
||||
[13]: https://opensource.com/article/20/6/linux-libraries
|
||||
[14]: https://opensource.com/sites/default/files/uploads/gdb_output_stopped_by_sigint.png (gdb output stopped by sigint)
|
||||
[15]: https://opensource.com/sites/default/files/uploads/gdb_output_list_main.png (gdb output list main)
|
||||
[16]: https://opensource.com/sites/default/files/uploads/gdb_output_breakpoint_added.png (gdb output breakpoint added)
|
||||
[17]: https://opensource.com/sites/default/files/uploads/gdb_output_break_at_main.png (gdb output break at main)
|
||||
[18]: https://opensource.com/sites/default/files/images/gdb_output_screen_corrupted.png (gdb output corrupted)
|
||||
[19]: https://sourceware.org/gdb/onlinedocs/gdb/TUI-Keys.html#TUI-Keys
|
||||
[20]: https://opensource.com/sites/default/files/uploads/gdb_output_stop_on_watchpoint_1.png (gdb output stop on watchpoint_1)
|
||||
[21]: https://opensource.com/sites/default/files/uploads/gdb_output_stop_on_watchpoint_2.png (gdb output stop on watchpoint_2)
|
||||
[22]: https://opensource.com/sites/default/files/uploads/gdb_output_info_watchpoints.png (gdb output info watchpoints)
|
||||
[23]: https://opensource.com/sites/default/files/uploads/gdb_output_info_breakpoints.png (gdb output info breakpoints)
|
||||
[24]: https://opensource.com/sites/default/files/uploads/gdb_output_disabled_breakpoints.png (disabled breakpoints)
|
||||
[25]: https://opensource.com/sites/default/files/uploads/gdb_output_set_conditional_breakpoint.png (Set conditional breakpoint)
|
||||
[26]: https://opensource.com/sites/default/files/uploads/gdb_output_print_variable.png (print variable)
|
||||
[27]: https://opensource.com/sites/default/files/uploads/gdb_output_modify_breakpoint.png (modify breakpoint)
|
||||
[28]: https://opensource.com/sites/default/files/uploads/gdb_output_syscall_catch.png (catch syscall write output)
|
||||
[29]: https://sourceware.org/gdb/current/onlinedocs/gdb/Breakpoints.html#Breakpoints
|
||||
[30]: https://opensource.com/sites/default/files/uploads/gdb_output_print_and_modify.png (print variable)
|
||||
[31]: https://opensource.com/sites/default/files/uploads/gdb_output_whatis.png (whatis output)
|
||||
[32]: https://opensource.com/sites/default/files/uploads/gdb_output_info_scope_main.png (info scope main output)
|
||||
[33]: https://opensource.com/sites/default/files/uploads/gdb_output_info_locals_main.png (info locals output)
|
||||
[34]: https://sourceware.org/gdb/current/onlinedocs/gdb/Symbols.html
|
||||
[35]: https://man7.org/linux/man-pages/man1/ps.1.html
|
||||
[36]: https://man7.org/linux/man-pages/man1/top.1.html
|
||||
[37]: https://opensource.com/sites/default/files/uploads/coredump_running.png (coredump application)
|
||||
[38]: https://opensource.com/sites/default/files/uploads/gdb_output_attaching_to_process.png (attach GDB to coredump)
|
||||
[39]: https://opensource.com/sites/default/files/uploads/gdb_output_backtrace.png (layout src and backtrace output)
|
||||
[40]: https://sourceware.org/gdb/current/onlinedocs/gdb/Attach.html#Attach
|
||||
[41]: https://opensource.com/sites/default/files/uploads/gdb_output_stackframe_up.png (moving up the stack to main.cpp)
|
||||
[42]: https://sourceware.org/gdb/current/onlinedocs/gdb/Stack.html#Stack
|
||||
[43]: https://ftp.gnu.org/old-gnu/Manuals/gdb/html_node/gdb_48.html#SEC49
|
||||
[44]: https://opensource.com/sites/default/files/uploads/crash.png (Crash meme)
|
||||
[45]: https://opensource.com/sites/default/files/uploads/gdb_output_coredump.png (coredump output)
|
||||
[46]: https://opensource.com/sites/default/files/uploads/gdb_output_up_five.png (up 5 output)
|
||||
[4]: https://opensource.com/sites/default/files/uploads/gdb_output_no_dbg_symbols.png
|
||||
[5]: https://opensource.com/sites/default/files/uploads/gdb_output_with_symbols.png
|
||||
[6]: https://opensource.com/sites/default/files/uploads/gdb_output_crash_on_c1_switch.png
|
||||
[7]: https://opensource.com/sites/default/files/uploads/gdb_output_info_source.png
|
||||
[8]: http://dwarfstd.org/
|
||||
[9]: https://sourceware.org/gdb/current/onlinedocs/gdb/Compilation.html#Compilation
|
||||
[10]: https://opensource.com/sites/default/files/uploads/gdb_output_info_shared.png
|
||||
[11]: https://opensource.com/article/20/6/linux-libraries
|
||||
[12]: https://opensource.com/sites/default/files/uploads/gdb_output_stopped_by_sigint.png
|
||||
[13]: https://opensource.com/sites/default/files/uploads/gdb_output_list_main.png
|
||||
[14]: https://opensource.com/sites/default/files/uploads/gdb_output_breakpoint_added.png
|
||||
[15]: https://opensource.com/sites/default/files/uploads/gdb_output_break_at_main.png
|
||||
[16]: https://opensource.com/sites/default/files/images/gdb_output_screen_corrupted.png
|
||||
[17]: https://sourceware.org/gdb/onlinedocs/gdb/TUI-Keys.html#TUI-Keys
|
||||
[18]: https://opensource.com/sites/default/files/uploads/gdb_output_stop_on_watchpoint_1.png
|
||||
[19]: https://opensource.com/sites/default/files/uploads/gdb_output_stop_on_watchpoint_2.png
|
||||
[20]: https://opensource.com/sites/default/files/uploads/gdb_output_info_watchpoints.png
|
||||
[21]: https://opensource.com/sites/default/files/uploads/gdb_output_info_breakpoints.png
|
||||
[22]: https://opensource.com/sites/default/files/uploads/gdb_output_disabled_breakpoints.png
|
||||
[23]: https://opensource.com/sites/default/files/uploads/gdb_output_set_conditional_breakpoint.png
|
||||
[24]: https://opensource.com/sites/default/files/uploads/gdb_output_print_variable.png
|
||||
[25]: https://opensource.com/sites/default/files/uploads/gdb_output_modify_breakpoint.png
|
||||
[26]: https://opensource.com/sites/default/files/uploads/gdb_output_syscall_catch.png
|
||||
[27]: https://sourceware.org/gdb/current/onlinedocs/gdb/Breakpoints.html#Breakpoints
|
||||
[28]: https://opensource.com/sites/default/files/uploads/gdb_output_print_and_modify.png
|
||||
[29]: https://opensource.com/sites/default/files/uploads/gdb_output_whatis.png
|
||||
[30]: https://opensource.com/sites/default/files/uploads/gdb_output_info_scope_main.png
|
||||
[31]: https://opensource.com/sites/default/files/uploads/gdb_output_info_locals_main.png
|
||||
[32]: https://sourceware.org/gdb/current/onlinedocs/gdb/Symbols.html
|
||||
[33]: https://man7.org/linux/man-pages/man1/ps.1.html
|
||||
[34]: https://man7.org/linux/man-pages/man1/top.1.html
|
||||
[35]: https://opensource.com/sites/default/files/uploads/coredump_running.png
|
||||
[36]: https://opensource.com/sites/default/files/uploads/gdb_output_attaching_to_process.png
|
||||
[37]: https://opensource.com/sites/default/files/uploads/gdb_output_backtrace.png
|
||||
[38]: https://sourceware.org/gdb/current/onlinedocs/gdb/Attach.html#Attach
|
||||
[39]: https://opensource.com/sites/default/files/uploads/gdb_output_stackframe_up.png
|
||||
[40]: https://sourceware.org/gdb/current/onlinedocs/gdb/Stack.html#Stack
|
||||
[41]: https://ftp.gnu.org/old-gnu/Manuals/gdb/html_node/gdb_48.html#SEC49
|
||||
[42]: https://opensource.com/article/20/8/linux-dump
|
||||
[43]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[44]: https://opensource.com/sites/default/files/uploads/crash.png
|
||||
[45]: https://opensource.com/sites/default/files/uploads/gdb_output_coredump.png
|
||||
[46]: https://opensource.com/sites/default/files/uploads/gdb_output_up_five.png
|
||||
[47]: https://en.wikipedia.org/wiki/Assembly_language
|
||||
[48]: https://opensource.com/sites/default/files/uploads/gdb_output_no_debugging_symbols.png (no debugging symbols)
|
||||
[49]: https://opensource.com/sites/default/files/uploads/gdb_output_info_file.png (info file output)
|
||||
[50]: https://opensource.com/sites/default/files/uploads/gdb_output_break_at_start.png (breakpoint at the entry point)
|
||||
[48]: https://opensource.com/sites/default/files/uploads/gdb_output_no_debugging_symbols.png
|
||||
[49]: https://opensource.com/sites/default/files/uploads/gdb_output_info_file.png
|
||||
[50]: https://opensource.com/sites/default/files/uploads/gdb_output_break_at_start.png
|
||||
[51]: https://en.wikipedia.org/wiki/X86_assembly_language#Syntax
|
||||
[52]: https://opensource.com/sites/default/files/uploads/gdb_output_disassembly_flavor.png (changing assembly flavor)
|
||||
[53]: https://opensource.com/sites/default/files/uploads/gdb_output_layout_reg_asm.png (layout asm and layout reg output)
|
||||
[52]: https://opensource.com/sites/default/files/uploads/gdb_output_disassembly_flavor.png
|
||||
[53]: https://opensource.com/sites/default/files/uploads/gdb_output_layout_reg_asm.png
|
||||
[54]: https://github.com/hANSIc99/core_dump_example/blob/master/gdbinit
|
||||
[55]: https://opensource.com/sites/default/files/uploads/gdb_output_asm_div_zero.png (continuing execution after crash)
|
||||
[56]: https://opensource.com/sites/default/files/uploads/gdb_output_stack_division.png (stack division output)
|
||||
[55]: https://opensource.com/sites/default/files/uploads/gdb_output_asm_div_zero.png
|
||||
[56]: https://opensource.com/sites/default/files/uploads/gdb_output_stack_division.png
|
||||
[57]: https://en.wikipedia.org/wiki/Printf_format_string#Type_field
|
||||
[58]: https://opensource.com/sites/default/files/uploads/gdb_output_examine_1.png (print value)
|
||||
[58]: https://opensource.com/sites/default/files/uploads/gdb_output_examine_1.png
|
||||
[59]: https://sourceware.org/gdb/current/onlinedocs/gdb/Memory.html
|
||||
[60]: https://en.wikipedia.org/wiki/Function_prologue
|
||||
[61]: https://opensource.com/sites/default/files/uploads/gdb_output_callstack_assembly_0.png (Callstack assembly)
|
||||
[61]: https://opensource.com/sites/default/files/uploads/gdb_output_callstack_assembly_0.png
|
||||
[62]: https://github.com/WebFreak001/code-debug
|
||||
[63]: https://opensource.com/sites/default/files/uploads/vs_codium_native_debug.png (GDB in VSCodium)
|
||||
[63]: https://opensource.com/sites/default/files/uploads/vs_codium_native_debug.png
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Analyze Kubernetes files for errors with KubeLinter)
|
||||
[#]: via: (https://opensource.com/article/21/1/kubelinter)
|
||||
[#]: author: (Jessica Cherry https://opensource.com/users/cherrybomb)
|
||||
[#]: subject: "Analyze Kubernetes files for errors with KubeLinter"
|
||||
[#]: via: "https://opensource.com/article/21/1/kubelinter"
|
||||
[#]: author: "Jessica Cherry https://opensource.com/users/cherrybomb"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Analyze Kubernetes files for errors with KubeLinter
|
||||
======
|
||||
Find and fix errors in your Helm charts and Kubernetes configuration
|
||||
files with KubeLinter.
|
||||
Find and fix errors in your Helm charts and Kubernetes configuration files with KubeLinter.
|
||||
|
||||
![magnifying glass on computer screen, finding a bug in the code][1]
|
||||
|
||||
Image by: Opensource.com
|
||||
|
||||
[KubeLinter][2] is an open source project released by Stackrox to analyze Kubernetes YAML files for security issues and errant code. The tool covers Helm charts and Kubernetes configuration files, including [Knative][3] files. Using it can improve cloud-native development, reduce development time, and encourage DevOps best practices.
|
||||
|
||||
### Download and install
|
||||
@@ -23,23 +25,20 @@ You have several options to install KubeLinter.
|
||||
|
||||
You can install manually from the Git repository:
|
||||
|
||||
|
||||
```
|
||||
$ git clone [git@github.com][4]:stackrox/kube-linter.git
|
||||
$ cd kube-linter && make build
|
||||
$ git clone git@github.com:stackrox/kube-linter.git
|
||||
$ cd kube-linter && make build
|
||||
$ .gobin/kube-linter version
|
||||
```
|
||||
|
||||
If you use [Homebrew][5], you can install it with the `brew` command:
|
||||
|
||||
If you use [Homebrew][4], you can install it with the `brew` command:
|
||||
|
||||
```
|
||||
`$ brew install kube-linter`
|
||||
$ brew install kube-linter
|
||||
```
|
||||
|
||||
You can also install it with Go (as I did):
|
||||
|
||||
|
||||
```
|
||||
$ GO111MODULE=on go get golang.stackrox.io/kube-linter/cmd/kube-linter
|
||||
go: finding golang.stackrox.io/kube-linter latest
|
||||
@@ -48,11 +47,10 @@ go: extracting golang.stackrox.io/kube-linter v0.0.0-20201204022312-475075c74675
|
||||
[...]
|
||||
```
|
||||
|
||||
After installing, you must make an alias in your `~/.bashrc`:
|
||||
|
||||
After installing, you must make an alias in your `~/.bashrc` :
|
||||
|
||||
```
|
||||
$ echo "alias kube-linter=$HOME/go/bin/kube-linter" >> ~/.bashrc
|
||||
$ echo "alias kube-linter=$HOME/go/bin/kube-linter" >> ~/.bashrc
|
||||
$ source ~/.bashrc
|
||||
```
|
||||
|
||||
@@ -60,7 +58,6 @@ $ source ~/.bashrc
|
||||
|
||||
Now that the tool is installed, try it out on a Helm chart. First, start Minikube with a clean build and some small configuration changes:
|
||||
|
||||
|
||||
```
|
||||
$ minikube config set kubernetes-version v1.19.0
|
||||
$ minikube config set memory 8000
|
||||
@@ -68,23 +65,22 @@ $ minikube config set memory 8000
|
||||
$ minikube config set cpus 12
|
||||
❗ These changes will take effect upon a minikube delete and then a minikube start
|
||||
$ minikube delete
|
||||
🔥 Deleting "minikube" in docker ...
|
||||
🔥 Deleting container "minikube" ...
|
||||
🔥 Removing /home/jess/.minikube/machines/minikube ...
|
||||
💀 Removed all traces of the "minikube" cluster.
|
||||
? Deleting "minikube" in docker ...
|
||||
? Deleting container "minikube" ...
|
||||
? Removing /home/jess/.minikube/machines/minikube ...
|
||||
? Removed all traces of the "minikube" cluster.
|
||||
|
||||
$ minikube start
|
||||
😄 minikube v1.14.2 on Debian bullseye/sid
|
||||
? minikube v1.14.2 on Debian bullseye/sid
|
||||
✨ Using the docker driver based on user configuration
|
||||
👍 Starting control plane node minikube in cluster minikube
|
||||
🎉 minikube 1.15.1 is available! Download it: <https://github.com/kubernetes/minikube/releases/tag/v1.15.1>
|
||||
💡 To disable this notice, run: 'minikube config set WantUpdateNotification false'
|
||||
? Starting control plane node minikube in cluster minikube
|
||||
? minikube 1.15.1 is available! Download it: https://github.com/kubernetes/minikube/releases/tag/v1.15.1
|
||||
? To disable this notice, run: 'minikube config set WantUpdateNotification false'
|
||||
|
||||
💾 Downloading Kubernetes v1.19.0 preload ...
|
||||
? Downloading Kubernetes v1.19.0 preload ...
|
||||
```
|
||||
|
||||
Once everything is running, create an example Helm chart called `first_test`:
|
||||
|
||||
Once everything is running, create an example Helm chart called `first_test` :
|
||||
|
||||
```
|
||||
$ helm create first_test
|
||||
@@ -95,7 +91,6 @@ first_test
|
||||
|
||||
Test KubeLinter against the new, unedited chart. Run the `kube-linter` command to see the available commands and flags:
|
||||
|
||||
|
||||
```
|
||||
$ kube-linter
|
||||
Usage:
|
||||
@@ -103,8 +98,8 @@ Usage:
|
||||
|
||||
Available Commands:
|
||||
checks View more information on lint checks
|
||||
help Help about any command
|
||||
lint Lint Kubernetes YAML files and Helm charts
|
||||
help Help about any command
|
||||
lint Lint Kubernetes YAML files and Helm charts
|
||||
templates View more information on check templates
|
||||
version Print version and exit
|
||||
|
||||
@@ -116,13 +111,12 @@ Use "/home/jess/go/bin/kube-linter [command] --help" for more information about
|
||||
|
||||
Then test what the basic `lint` command does to your example chart. You'll end up with many errors, so I'll grab a snippet of some issues:
|
||||
|
||||
|
||||
```
|
||||
$ kube-linter lint first_test/
|
||||
|
||||
first_test/first_test/templates/deployment.yaml: (object: <no namespace>/test-release-first_test apps/v1, Kind=Deployment) container "first_test" does not have a read-only root file system (check: no-read-only-root-fs, remediation: Set readOnlyRootFilesystem to true in your container's securityContext.)
|
||||
first_test/first_test/templates/deployment.yaml: (object: <no namespace>/test-release-first_test apps/v1, Kind=Deployment) container "first_test" does not have a read-only root file system (check: no-read-only-root-fs, remediation: Set readOnlyRootFilesystem to true in your container's securityContext.)
|
||||
|
||||
first_test/first_test/templates/deployment.yaml: (object: <no namespace>/test-release-first_test apps/v1, Kind=Deployment) container "first_test" is not set to runAsNonRoot (check: run-as-non-root, remediation: Set runAsUser to a non-zero number, and runAsNonRoot to true, in your pod or container securityContext. See <https://kubernetes.io/docs/tasks/configure-pod-container/security-context/> for more details.)
|
||||
first_test/first_test/templates/deployment.yaml: (object: <no namespace>/test-release-first_test apps/v1, Kind=Deployment) container "first_test" is not set to runAsNonRoot (check: run-as-non-root, remediation: Set runAsUser to a non-zero number, and runAsNonRoot to true, in your pod or container securityContext. See https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ for more details.)
|
||||
[...]
|
||||
Error: found 12 lint errors
|
||||
```
|
||||
@@ -131,14 +125,12 @@ For the sake of brevity, I picked two security issues that are easy for me to f
|
||||
|
||||
The `kube-linter` output provides hints about the required fixes. For instance, the first error ends with:
|
||||
|
||||
|
||||
```
|
||||
`remediation: Set readOnlyRootFilesystem to true in your container's securityContext.`
|
||||
remediation: Set readOnlyRootFilesystem to true in your container's securityContext.
|
||||
```
|
||||
|
||||
The next step is clear: Open the `values.yaml` file in a text editor (I use Vi, but you can use whatever you like) and locate the `securityContext` section:
|
||||
|
||||
|
||||
```
|
||||
securityContext: {}
|
||||
# capabilities:
|
||||
@@ -151,12 +143,11 @@ securityContext: {}
|
||||
|
||||
Uncomment the section and remove the braces:
|
||||
|
||||
|
||||
```
|
||||
securityContext:
|
||||
securityContext:
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
- ALL
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
@@ -164,20 +155,18 @@ securityContext:
|
||||
|
||||
Save the file and rerun the linter. Those errors no longer show up in the list, and the error count changes.
|
||||
|
||||
|
||||
```
|
||||
`Error: found 10 lint errors`
|
||||
Error: found 10 lint errors
|
||||
```
|
||||
|
||||
Congratulations! You have resolved security issues!
|
||||
|
||||
### Kubernetes with KubeLinter
|
||||
|
||||
This example uses an app file from my [previous article on Knative][6] to test against Kubernetes config files. I already have Knative up and running, so you may want to review that article if it's not running on your system.
|
||||
This example uses an app file from my [previous article on Knative][5] to test against Kubernetes config files. I already have Knative up and running, so you may want to review that article if it's not running on your system.
|
||||
|
||||
I downloaded the Kourier service YAML file for this example:
|
||||
|
||||
|
||||
```
|
||||
$ ls
|
||||
kourier.yaml first_test
|
||||
@@ -185,13 +174,12 @@ kourier.yaml first_test
|
||||
|
||||
Start by running the linter against `kourier.yaml`. Again, there are several issues. I'll focus on resource problems:
|
||||
|
||||
|
||||
```
|
||||
$ kube-linter lint kourier.yaml
|
||||
$ kube-linter lint kourier.yaml
|
||||
|
||||
kourier.yaml: (object: kourier-system/3scale-kourier-gateway apps/v1, Kind=Deployment) container "kourier-gateway" has cpu limit 0 (check: unset-cpu-requirements, remediation: Set your container's CPU requests and limits depending on its requirements. See <https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/\#requests-and-limits> for more details.)
|
||||
kourier.yaml: (object: kourier-system/3scale-kourier-gateway apps/v1, Kind=Deployment) container "kourier-gateway" has cpu limit 0 (check: unset-cpu-requirements, remediation: Set your container's CPU requests and limits depending on its requirements. See https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits for more details.)
|
||||
|
||||
kourier.yaml: (object: kourier-system/3scale-kourier-gateway apps/v1, Kind=Deployment) container "kourier-gateway" has memory request 0 (check: unset-memory-requirements, remediation: Set your container's memory requests and limits depending on its requirements. See <https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/\#requests-and-limits> for more details.)
|
||||
kourier.yaml: (object: kourier-system/3scale-kourier-gateway apps/v1, Kind=Deployment) container "kourier-gateway" has memory request 0 (check: unset-memory-requirements, remediation: Set your container's memory requests and limits depending on its requirements. See https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#requests-and-limits for more details.)
|
||||
|
||||
Error: found 12 lint errors
|
||||
```
|
||||
@@ -200,7 +188,6 @@ Since this is a single deployment file, you can edit it directly. Open it in a t
|
||||
|
||||
Start with deployment:
|
||||
|
||||
|
||||
```
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -214,70 +201,67 @@ metadata:
|
||||
|
||||
The containers section has some problems:
|
||||
|
||||
|
||||
```
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- --base-id 1
|
||||
- -c /tmp/config/envoy-bootstrap.yaml
|
||||
- --log-level info
|
||||
command:
|
||||
- /usr/local/bin/envoy
|
||||
image: docker.io/maistra/proxyv2-ubi8:1.1.5
|
||||
imagePullPolicy: Always
|
||||
name: kourier-gateway
|
||||
ports:
|
||||
- name: http2-external
|
||||
containerPort: 8080
|
||||
protocol: TCP
|
||||
- name: http2-internal
|
||||
containerPort: 8081
|
||||
protocol: TCP
|
||||
- name: https-external
|
||||
containerPort: 8443
|
||||
protocol: TCP
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- --base-id 1
|
||||
- -c /tmp/config/envoy-bootstrap.yaml
|
||||
- --log-level info
|
||||
command:
|
||||
- /usr/local/bin/envoy
|
||||
image: docker.io/maistra/proxyv2-ubi8:1.1.5
|
||||
imagePullPolicy: Always
|
||||
name: kourier-gateway
|
||||
ports:
|
||||
- name: http2-external
|
||||
containerPort: 8080
|
||||
protocol: TCP
|
||||
- name: http2-internal
|
||||
containerPort: 8081
|
||||
protocol: TCP
|
||||
- name: https-external
|
||||
containerPort: 8443
|
||||
protocol: TCP
|
||||
```
|
||||
|
||||
Add some specs to the container configuration:
|
||||
|
||||
|
||||
```
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- --base-id 1
|
||||
- -c /tmp/config/envoy-bootstrap.yaml
|
||||
- --log-level info
|
||||
command:
|
||||
- /usr/local/bin/envoy
|
||||
image: docker.io/maistra/proxyv2-ubi8:1.1.5
|
||||
imagePullPolicy: Always
|
||||
name: kourier-gateway
|
||||
ports:
|
||||
- name: http2-external
|
||||
containerPort: 8080
|
||||
protocol: TCP
|
||||
- name: http2-internal
|
||||
containerPort: 8081
|
||||
protocol: TCP
|
||||
- name: https-external
|
||||
containerPort: 8443
|
||||
protocol: TCP
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- --base-id 1
|
||||
- -c /tmp/config/envoy-bootstrap.yaml
|
||||
- --log-level info
|
||||
command:
|
||||
- /usr/local/bin/envoy
|
||||
image: docker.io/maistra/proxyv2-ubi8:1.1.5
|
||||
imagePullPolicy: Always
|
||||
name: kourier-gateway
|
||||
ports:
|
||||
- name: http2-external
|
||||
containerPort: 8080
|
||||
protocol: TCP
|
||||
- name: http2-internal
|
||||
containerPort: 8081
|
||||
protocol: TCP
|
||||
- name: https-external
|
||||
containerPort: 8443
|
||||
protocol: TCP
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
```
|
||||
|
||||
When you rerun the linter, you'll notice these issues no longer show in the output, and the error count changes:
|
||||
|
||||
|
||||
```
|
||||
`Error: found 8 lint errors`
|
||||
Error: found 8 lint errors
|
||||
```
|
||||
|
||||
Congratulations! You have fixed resource issues in your Kubernetes file!
|
||||
@@ -293,17 +277,16 @@ I think KubeLinter's best part is that each error message includes documentation
|
||||
via: https://opensource.com/article/21/1/kubelinter
|
||||
|
||||
作者:[Jessica Cherry][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/mistake_bug_fix_find_error.png?itok=PZaz3dga (magnifying glass on computer screen, finding a bug in the code)
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/mistake_bug_fix_find_error.png
|
||||
[2]: https://github.com/stackrox/kube-linter
|
||||
[3]: https://knative.dev/
|
||||
[4]: mailto:git@github.com
|
||||
[5]: https://opensource.com/article/20/6/homebrew-linux
|
||||
[6]: https://opensource.com/article/20/11/knative
|
||||
[4]: https://opensource.com/article/20/6/homebrew-linux
|
||||
[5]: https://opensource.com/article/20/11/knative
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Donke-Hao)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Configure a Linux workspace remotely from the command line)
|
||||
[#]: via: (https://opensource.com/article/21/1/remote-configuration-xfce4)
|
||||
[#]: author: (David Both https://opensource.com/users/dboth)
|
||||
|
||||
Configure a Linux workspace remotely from the command line
|
||||
======
|
||||
Nearly everything can be done from the Linux command line, including
|
||||
remote configuration of Xfce4.
|
||||
![Coding on a computer][1]
|
||||
|
||||
One of the things I appreciate about Linux versus proprietary operating systems is that almost everything can be managed and configured from the command line. That means that nearly everything can be configured locally or even remotely via an SSH login connection. Sometimes it takes a bit of time spent on Internet searches, but if you can think of a task, it can probably be done from the command line.
|
||||
|
||||
### The problem
|
||||
|
||||
Sometimes it is necessary to make remote modifications to a desktop using the command line. In this particular case, I needed to reduce the number of workspaces on the [Xfce][2] panel from four to three at the request of a remote user. This configuration only required about 20 minutes of searching on the Internet.
|
||||
|
||||
The default workspace count and many other settings for **xfwm4** can be found and changed in the **/usr/share/xfwm4/defaults** file. So setting _workspace_count=4_ to _workspace_count=2_ changes the default for all users on the host. Also, the **xfconf-query** command can be run by non-root users to query and set various attributes for the **xfwm4** window manager. It should be used by the user account that requires the change and not by root.
|
||||
|
||||
In the sample below, I have first verified the current setting of _four_ workspaces, then set the number to _two_, and finally confirmed the new setting.
|
||||
|
||||
|
||||
```
|
||||
[user@test1 ~]# xfconf-query -c xfwm4 -p /general/workspace_count
|
||||
4
|
||||
[user@test1 ~]# xfconf-query -c xfwm4 -p /general/workspace_count -s 2
|
||||
[user@test1 ~]# xfconf-query -c xfwm4 -p /general/workspace_count
|
||||
2
|
||||
[user@test1 ~]#
|
||||
```
|
||||
|
||||
This change takes place immediately and is visible to the user without a reboot or even logging out and back in. I had a bit of fun with this on my workstation by watching the workspace switcher change as I entered commands to set different numbers of workspaces. I get my amusements where I can these days. ;-)
|
||||
|
||||
### More exploration
|
||||
|
||||
Now that I fixed the problem, I decided to explore the **xfconf-query** command in a bit more detail. Unfortunately, there are no man or info pages for this tool, nor is there any documentation in **/usr/share**. The usual fallback of using the **-h** option resulted in little helpful information.
|
||||
|
||||
|
||||
```
|
||||
$ xfconf-query -h
|
||||
Usage:
|
||||
xfconf-query [OPTION…] - Xfconf commandline utility
|
||||
Help Options:
|
||||
-h, --help Show help options
|
||||
Application Options:
|
||||
-V, --version Version information
|
||||
-c, --channel The channel to query/modify
|
||||
-p, --property The property to query/modify
|
||||
-s, --set The new value to set for the property
|
||||
-l, --list List properties (or channels if -c is not specified)
|
||||
-v, --verbose Verbose output
|
||||
-n, --create Create a new property if it does not already exist
|
||||
-t, --type Specify the property value type
|
||||
-r, --reset Reset property
|
||||
-R, --recursive Recursive (use with -r)
|
||||
-a, --force-array Force array even if only one element
|
||||
-T, --toggle Invert an existing boolean property
|
||||
-m, --monitor Monitor a channel for property changes
|
||||
```
|
||||
|
||||
This is not a lot of help, but we can figure out a good bit from it anyway. First, _channels_ are groupings of properties that can be modified. I made the change above to the **general** channel, and the property is **workspace_count**. Let’s look at the complete list of channels.
|
||||
|
||||
|
||||
```
|
||||
$ xfconf-query -l
|
||||
Channels:
|
||||
xfwm4
|
||||
xfce4-keyboard-shortcuts
|
||||
xfce4-notifyd
|
||||
xsettings
|
||||
xfdashboard
|
||||
thunar
|
||||
parole
|
||||
xfce4-panel
|
||||
xfce4-appfinder
|
||||
xfce4-settings-editor
|
||||
xfce4-power-manager
|
||||
xfce4-session
|
||||
keyboards
|
||||
displays
|
||||
keyboard-layout
|
||||
ristretto
|
||||
xfcethemer
|
||||
xfce4-desktop
|
||||
pointers
|
||||
xfce4-settings-manager
|
||||
xfce4-mixer
|
||||
```
|
||||
|
||||
The properties for a given channel can also be viewed using the following syntax. I have used the **less** pager because the result is a long stream of data. I have pruned the listing below but left enough to see the type of entries you can expect to find.
|
||||
|
||||
|
||||
```
|
||||
$ xfconf-query -c xfwm4 -l | less
|
||||
/general/activate_action
|
||||
/general/borderless_maximize
|
||||
/general/box_move
|
||||
/general/box_resize
|
||||
/general/button_layout
|
||||
/general/button_offset
|
||||
<SNIP>
|
||||
/general/workspace_count
|
||||
/general/workspace_names
|
||||
/general/wrap_cycle
|
||||
/general/wrap_layout
|
||||
/general/wrap_resistance
|
||||
/general/wrap_windows
|
||||
/general/wrap_workspaces
|
||||
/general/zoom_desktop
|
||||
(END)
|
||||
```
|
||||
|
||||
You can explore all the channels in this manner. I discovered that the channels generally correspond to the various settings in the **Settings Manager**. The properties are the ones that you would set in those dialogs. Note that not all the icons you will find in the **Settings Manager** dialog window are part of the **Xfce** desktop, so there are no corresponding channels for them. The **Screensaver** is one example because it is a generic GNU screensaver and not unique to **Xfce**. The **Settings Manager** is just a good central place for **Xfce** to locate many of these configuration tools.
|
||||
|
||||
### Documentation
|
||||
|
||||
As mentioned previously, there do not appear to be any man or info pages for the **xconf-query** command, and I found a lot of incorrect and poorly documented information on the Internet. The best documentation I found for **Xfce4** is on the [Xfce website][2], and some specific information on **xconf-query** can be found here.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/remote-configuration-xfce4
|
||||
|
||||
作者:[David Both][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/dboth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/code_computer_laptop_hack_work.png?itok=aSpcWkcl (Coding on a computer)
|
||||
[2]: https://www.xfce.org/
|
||||
@@ -1,40 +1,40 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How I programmed a virtual gift exchange)
|
||||
[#]: via: (https://opensource.com/article/21/1/open-source-gift-exchange)
|
||||
[#]: author: (Chris Hermansen https://opensource.com/users/clhermansen)
|
||||
[#]: subject: "How I programmed a virtual gift exchange"
|
||||
[#]: via: "https://opensource.com/article/21/1/open-source-gift-exchange"
|
||||
[#]: author: "Chris Hermansen https://opensource.com/users/clhermansen"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
How I programmed a virtual gift exchange
|
||||
======
|
||||
A book club takes its annual gift exchange online with the help of HTML,
|
||||
CSS, and JavaScript.
|
||||
A book club takes its annual gift exchange online with the help of HTML, CSS, and JavaScript.
|
||||
|
||||
![Package wrapped with brown paper and red bow][1]
|
||||
|
||||
Image by: Photo by [Jess Bailey][2] on [Unsplash][3]
|
||||
|
||||
Every year, my wife's book club has a book exchange during the holidays. Due to the need to maintain physical distance in 2020, I created an online gift exchange for them to use during a book club videoconference. Apparently, the virtual book exchange worked out (at least, I received kind compliments from the book club members), so I decided to share this simple little hack.
|
||||
|
||||
### How the book exchange usually works
|
||||
|
||||
In past years, the exchange has gone something like this:
|
||||
|
||||
1. Each person buys a book and wraps it up.
|
||||
2. Everyone arrives at the host's home and puts the wrapped books in a pile.
|
||||
3. Each person draws a number out of a hat, which establishes their turn.
|
||||
4. The person who drew No. 1 selects a book from the pile and unwraps it. In turn, each subsequent person chooses to either take a wrapped book from the pile or to steal an unwrapped book from someone who has gone before.
|
||||
5. When someone's book is stolen, they can either replace it with a wrapped book from the pile or steal another book (but not the one that was stolen from them) from someone else.
|
||||
6. And so on… eventually, someone has to take the last unwrapped book to end the exchange.
|
||||
|
||||
|
||||
1. Each person buys a book and wraps it up.
|
||||
2. Everyone arrives at the host's home and puts the wrapped books in a pile.
|
||||
3. Each person draws a number out of a hat, which establishes their turn.
|
||||
4. The person who drew No. 1 selects a book from the pile and unwraps it. In turn, each subsequent person chooses to either take a wrapped book from the pile or to steal an unwrapped book from someone who has gone before.
|
||||
5. When someone's book is stolen, they can either replace it with a wrapped book from the pile or steal another book (but not the one that was stolen from them) from someone else.
|
||||
6. And so on… eventually, someone has to take the last unwrapped book to end the exchange.
|
||||
|
||||
### Designing the virtual book exchange
|
||||
|
||||
My first decision was which implementation platform to use for the book exchange. Because there would already be a browser open to host the videoconference, I decided to use HTML, CSS, and JavaScript.
|
||||
|
||||
Then it was design time. After some thinking, I decided to use rectangles to represent the book club members and the books. The books would be draggable, and when one was dropped on a member's rectangle, the book would unwrap (and stay unwrapped). I needed some "wrapping paper," so I used this source of [free-to-use images][2].
|
||||
Then it was design time. After some thinking, I decided to use rectangles to represent the book club members and the books. The books would be draggable, and when one was dropped on a member's rectangle, the book would unwrap (and stay unwrapped). I needed some "wrapping paper," so I used this source of [free-to-use images][4].
|
||||
|
||||
I took screenshots of the patterns I liked and used [GIMP][3] to scale the images to the right width and height.
|
||||
I took screenshots of the patterns I liked and used [GIMP][5] to scale the images to the right width and height.
|
||||
|
||||
I needed a way to handle draggable and droppable interactions; given that I've been using jQuery and jQuery UI for several years now, I decided to continue along that path.
|
||||
|
||||
@@ -42,25 +42,19 @@ For a while, I struggled with what a droppable element should do when something
|
||||
|
||||
Jumping to the results, here's a screenshot of the user interface at the beginning of the exchange:
|
||||
|
||||
![Virtual book exchange][4]
|
||||
|
||||
(Chris Hermansen, [CC BY-SA 4.0][5])
|
||||
![Virtual book exchange][6]
|
||||
|
||||
There are nine book club members: Wanda, Carlos, Bill, and so on. There are also nine fairly ugly wrapped parcels.
|
||||
|
||||
Let's say Wanda goes first and chooses the flower wrapping paper. The host clicks and drags that parcel to Wanda's name, and the parcel unwraps:
|
||||
|
||||
![Virtual book exchange][6]
|
||||
|
||||
(Chris Hermansen, [CC BY-SA 4.0][5])
|
||||
![Virtual book exchange][7]
|
||||
|
||||
Whoops! That title and author are a bit too long to fit on the book's "cover." Oh well, I'll fix that in the next version.
|
||||
|
||||
Carlos is next. He decides he really wants to read that book, so he steals it. Wanda then chooses the paisley pattern, and the screen looks like this:
|
||||
|
||||
![Virtual book exchange][7]
|
||||
|
||||
(Chris Hermansen, [CC BY-SA 4.0][5])
|
||||
![Virtual book exchange][8]
|
||||
|
||||
And so on until the exchange ends.
|
||||
|
||||
@@ -68,120 +62,117 @@ And so on until the exchange ends.
|
||||
|
||||
So what about the code? Here it is:
|
||||
|
||||
|
||||
```
|
||||
1 <!doctype html>
|
||||
2 <[html][8] lang="en">
|
||||
3 <[head][9]>
|
||||
4 <[meta][10] charset="utf-8">
|
||||
5 <[title][11]>Book Exchange</[title][11]>
|
||||
6 <[link][12] rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css">
|
||||
7 <[style][13]>
|
||||
8 .draggable {
|
||||
9 float: left;
|
||||
10 width: 90px;
|
||||
11 height: 90px;
|
||||
12 background: #ccc;
|
||||
13 padding: 5px;
|
||||
14 margin: 5px 5px 5px 0;
|
||||
15 }
|
||||
16 .droppable {
|
||||
17 float: left;
|
||||
18 width: 100px;
|
||||
19 height: 125px;
|
||||
20 background: #999;
|
||||
21 color: #fff;
|
||||
22 padding: 10px;
|
||||
23 margin: 10px 10px 10px 0;
|
||||
24 }
|
||||
25 </[style][13]>
|
||||
26 <[script][14] src="[https://code.jquery.com/jquery-1.12.4.js"\>\][15]</[script][14]>
|
||||
27 <[script][14] src="[https://code.jquery.com/ui/1.12.1/jquery-ui.js"\>\][16]</[script][14]>
|
||||
28 </[head][9]>
|
||||
29 <[body][17]>
|
||||
30 <[h1][18] style="color:#1a1aff;">Raffles Book Club Remote Gift Exchange</[h1][18]>
|
||||
31 <[h2][19] style="color:#aa0a0a;">The players, in random order, and the luxurious gifts, wrapped:</[h2][19]>
|
||||
32
|
||||
33 <[div][20]>
|
||||
34 <[div][20] id="wanda" class="droppable">Wanda</[div][20]>
|
||||
35 <[div][20] id="carlos" class="droppable">Carlos</[div][20]>
|
||||
36 <[div][20] id="bill" class="droppable">Bill</[div][20]>
|
||||
37 <[div][20] id="arlette" class="droppable">Arlette</[div][20]>
|
||||
38 <[div][20] id="joanne" class="droppable">Joanne</[div][20]>
|
||||
39 <[div][20] id="aleks" class="droppable">Alekx</[div][20]>
|
||||
40 <[div][20] id="ermintrude" class="droppable">Ermintrude</[div][20]>
|
||||
41 <[div][20] id="walter" class="droppable">Walter</[div][20]>
|
||||
42 <[div][20] id="hilary" class="droppable">Hilary</[div][20]>
|
||||
43 </[div][20]>
|
||||
44 <[div][20]>
|
||||
45 <[div][20] id="bows" class="draggable" style="background-image: url('bows.png');"></[div][20]>
|
||||
46 <[div][20] id="boxes" class="draggable" style="background-image: url('boxes.png');"></[div][20]>
|
||||
47 <[div][20] id="circles" class="draggable" style="background-image: url('circles.png');"></[div][20]>
|
||||
48 <[div][20] id="gerbers" class="draggable" style="background-image: url('gerbers.png');"></[div][20]>
|
||||
49 <[div][20] id="hippie" class="draggable" style="background-image: url('hippie.png');"></[div][20]>
|
||||
50 <[div][20] id="lattice" class="draggable" style="background-image: url('lattice.png');"></[div][20]>
|
||||
51 <[div][20] id="nautical" class="draggable" style="background-image: url('nautical.png');"></[div][20]>
|
||||
52 <[div][20] id="splodges" class="draggable" style="background-image: url('splodges.png');"></[div][20]>
|
||||
53 <[div][20] id="ugly" class="draggable" style="background-image: url('ugly.png');"></[div][20]>
|
||||
54 </[div][20]>
|
||||
55
|
||||
56 <[script][14]>
|
||||
57 var books = {
|
||||
58 'bows': 'Untamed by Glennon Doyle',
|
||||
59 'boxes': "The Heart's Invisible Furies by John Boyne",
|
||||
60 'circles': 'The Great Halifax Explosion by John Bacon',
|
||||
61 'gerbers': 'Homes: A Refugee Story by Abu Bakr al Rabeeah, Winnie Yeung',
|
||||
62 'hippie': 'Before We Were Yours by Lisa Wingate',
|
||||
63 'lattice': "Hamnet and Judith by Maggie O'Farrell",
|
||||
64 'nautical': 'Shuggy Bain by Douglas Stewart',
|
||||
65 'splodges': 'Magdalena by Wade Davis',
|
||||
66 'ugly': 'Funny Boy by Shyam Selvadurai'
|
||||
67 };
|
||||
68 $( ".droppable" ).droppable({
|
||||
69 drop: function(event, ui) {
|
||||
70 var element = $(ui.draggable[0]);
|
||||
71 var wrapping = element.attr('id');
|
||||
72 /* alert( $(this).text() + " got " + wrapping); */
|
||||
73 $(ui.draggable[0]).css("background-image","url(book_cover.png)");
|
||||
74 $(ui.draggable[0]).text(books[wrapping]);
|
||||
75 },
|
||||
76 out: function() {
|
||||
77 /* alert( $(this).text() + " lost it" ); */
|
||||
78 }
|
||||
79 });
|
||||
80 $( ".draggable" ).draggable();
|
||||
81 </[script][14]>
|
||||
82
|
||||
83 </[body][17]>
|
||||
84 </[html][8]>
|
||||
1 <!doctype html>
|
||||
2 <html lang="en">
|
||||
3 <head>
|
||||
4 <meta charset="utf-8">
|
||||
5 <title>Book Exchange</title>
|
||||
6 <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css">
|
||||
7 <style>
|
||||
8 .draggable {
|
||||
9 float: left;
|
||||
10 width: 90px;
|
||||
11 height: 90px;
|
||||
12 background: #ccc;
|
||||
13 padding: 5px;
|
||||
14 margin: 5px 5px 5px 0;
|
||||
15 }
|
||||
16 .droppable {
|
||||
17 float: left;
|
||||
18 width: 100px;
|
||||
19 height: 125px;
|
||||
20 background: #999;
|
||||
21 color: #fff;
|
||||
22 padding: 10px;
|
||||
23 margin: 10px 10px 10px 0;
|
||||
24 }
|
||||
25 </style>
|
||||
26 <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
|
||||
27 <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
|
||||
28 </head>
|
||||
29 <body>
|
||||
30 <h1 style="color:#1a1aff;">Raffles Book Club Remote Gift Exchange</h1>
|
||||
31 <h2 style="color:#aa0a0a;">The players, in random order, and the luxurious gifts, wrapped:</h2>
|
||||
32
|
||||
33 <div>
|
||||
34 <div id="wanda" class="droppable">Wanda</div>
|
||||
35 <div id="carlos" class="droppable">Carlos</div>
|
||||
36 <div id="bill" class="droppable">Bill</div>
|
||||
37 <div id="arlette" class="droppable">Arlette</div>
|
||||
38 <div id="joanne" class="droppable">Joanne</div>
|
||||
39 <div id="aleks" class="droppable">Alekx</div>
|
||||
40 <div id="ermintrude" class="droppable">Ermintrude</div>
|
||||
41 <div id="walter" class="droppable">Walter</div>
|
||||
42 <div id="hilary" class="droppable">Hilary</div>
|
||||
43 </div>
|
||||
44 <div>
|
||||
45 <div id="bows" class="draggable" style="background-image: url('bows.png');"></div>
|
||||
46 <div id="boxes" class="draggable" style="background-image: url('boxes.png');"></div>
|
||||
47 <div id="circles" class="draggable" style="background-image: url('circles.png');"></div>
|
||||
48 <div id="gerbers" class="draggable" style="background-image: url('gerbers.png');"></div>
|
||||
49 <div id="hippie" class="draggable" style="background-image: url('hippie.png');"></div>
|
||||
50 <div id="lattice" class="draggable" style="background-image: url('lattice.png');"></div>
|
||||
51 <div id="nautical" class="draggable" style="background-image: url('nautical.png');"></div>
|
||||
52 <div id="splodges" class="draggable" style="background-image: url('splodges.png');"></div>
|
||||
53 <div id="ugly" class="draggable" style="background-image: url('ugly.png');"></div>
|
||||
54 </div>
|
||||
55
|
||||
56 <script>
|
||||
57 var books = {
|
||||
58 'bows': 'Untamed by Glennon Doyle',
|
||||
59 'boxes': "The Heart's Invisible Furies by John Boyne",
|
||||
60 'circles': 'The Great Halifax Explosion by John Bacon',
|
||||
61 'gerbers': 'Homes: A Refugee Story by Abu Bakr al Rabeeah, Winnie Yeung',
|
||||
62 'hippie': 'Before We Were Yours by Lisa Wingate',
|
||||
63 'lattice': "Hamnet and Judith by Maggie O'Farrell",
|
||||
64 'nautical': 'Shuggy Bain by Douglas Stewart',
|
||||
65 'splodges': 'Magdalena by Wade Davis',
|
||||
66 'ugly': 'Funny Boy by Shyam Selvadurai'
|
||||
67 };
|
||||
68 $( ".droppable" ).droppable({
|
||||
69 drop: function(event, ui) {
|
||||
70 var element = $(ui.draggable[0]);
|
||||
71 var wrapping = element.attr('id');
|
||||
72 /* alert( $(this).text() + " got " + wrapping); */
|
||||
73 $(ui.draggable[0]).css("background-image","url(book_cover.png)");
|
||||
74 $(ui.draggable[0]).text(books[wrapping]);
|
||||
75 },
|
||||
76 out: function() {
|
||||
77 /* alert( $(this).text() + " lost it" ); */
|
||||
78 }
|
||||
79 });
|
||||
80 $( ".draggable" ).draggable();
|
||||
81 </script>
|
||||
82
|
||||
83 </body>
|
||||
84 </html>
|
||||
```
|
||||
|
||||
### Breaking it down
|
||||
|
||||
Let's go over this code bit by bit.
|
||||
|
||||
* **Lines 1–6:** Upfront, I have the usual HTML boilerplate, `HTML`, `HEAD`, `META`, `TITLE` elements, followed by a link to the CSS for jQuery UI.
|
||||
* **Lines 7–25:** I added two new style classes: `draggable` and `droppable`. These define the layout for the books (draggable) and the people (droppable). Note that, aside from defining the size, background color, padding, and margin, I established that these need to float left. This way, the layout adjusts to the browser window width in a reasonably acceptable form.
|
||||
* **Line 26–27:** With the CSS out of the way, it's time for the JavaScript libraries, first jQuery, then jQuery UI.
|
||||
* **Lines 29–83:** Now that the `HEAD` element is done, next is the `BODY`:
|
||||
* **Lines 30–31:** These couple of titles, `H1` and `H2`, let people know what they're doing here.
|
||||
* **Lines 33–43:** A `DIV` to contain the people:
|
||||
* **Lines 34–42:** The people are defined as droppable `DIV` elements and given `ID` fields corresponding to their names.
|
||||
* **Lines 44–54:** A `DIV` to contain the books:
|
||||
* **Lines 45–53:** The books are defined as draggable `DIV` elements. Each element is declared with a background image corresponding to the wrapping paper with no text between the `<div>` and `</div>`. The `ID` fields correspond to the wrapping paper.
|
||||
* **Lines 56–81:** These contain JavaScript to make it all work.
|
||||
* **Lines 57–67:** This JavaScript object contains the book definitions. The keys (`'bows'`, `'boxes'`, etc.) correspond to the `ID` fields of the book `DIV` elements. The values (`'Untamed by Glennon Doyle',` `"The Heart's Invisible Furies by John Boyne"`, etc.) are the book titles and authors.
|
||||
* **Lines 68–79:** This JavaScript jQuery UI function defines the droppable functionality to be attached to HTML elements whose class is `droppable`.
|
||||
* **Lines 69–75:** When a `draggable` element is dropped onto a `droppable` element, the function `drop` is called.
|
||||
* **Line 70:** The `element` variable is assigned the draggable object that was dropped (this will be a `<div id="..." class="draggable"...></div>` element.
|
||||
* **Line 71:** The `wrapping` variable is assigned the value of the `ID` field in the draggable object.
|
||||
* **Line 72:** This line is commented out, but while I was learning and testing, calls to `alert()` were useful.
|
||||
* **Line 73:** This reassigns the draggable object's background image to a bland image on which text can be read; part 1 of unwrapping is getting rid of the wrapping paper.
|
||||
* **Line 74:** This sets the text of the draggable object to the title of the book, looked up in the book's object using the draggable object's ID; part 2 of the unwrapping is showing the book title and author.
|
||||
* **Lines 76–78:** For a while, I thought I wanted something to happen when a draggable object was removed from a droppable object (e.g., when a club member stole a book), which would require using the `out` function in a droppable object. Eventually, I decided not to do anything. But, this could note that the book was stolen and make it "unstealable" for one turn; or it could show a status line that says something like: _"Wanda's book Blah Blah by Joe Blogs was stolen, and she needs to choose another."_
|
||||
* **Line 80:** This JavaScript jQuery UI function defines the draggable functionality to be attached to HTML elements whose class is `draggable`. In my case, the default behavior was all I needed.
|
||||
|
||||
|
||||
* Lines 1–6: Upfront, I have the usual `HTML` boilerplate, HTML, `HEAD`, `META`, `TITLE` elements, followed by a link to the CSS for jQuery UI.
|
||||
* Lines 7–25: I added two new style classes: `draggable` and `droppable`. These define the layout for the books (draggable) and the people (droppable). Note that, aside from defining the size, background color, padding, and margin, I established that these need to float left. This way, the layout adjusts to the browser window width in a reasonably acceptable form.
|
||||
* Line 26–27: With the CSS out of the way, it's time for the JavaScript libraries, first jQuery, then jQuery UI.
|
||||
* Lines 29–83: Now that the `HEAD` `element` is done, next is the `BODY`:
|
||||
* Lines 30–31: These couple of titles, `H1` and `H2`, let people know what they're doing here.
|
||||
Lines 33–43: A `DIV` to contain the people:
|
||||
Lines 34–42: The people are defined as `droppable` `DIV` elements and given `ID` fields corresponding to their names.
|
||||
Lines 44–54: A `DIV` to contain the books:
|
||||
Lines 45–53: The books are defined as `draggable` `DIV` elements. Each element is declared with a background image corresponding to the `wrapping` paper with no text between the `<div>` and `</div>`. The `ID` fields correspond to the wrapping paper.
|
||||
Lines 56–81: These contain JavaScript to make it all work.
|
||||
* Lines 57–67: This JavaScript object contains the book definitions. The keys ('bows', `'boxes'`, etc.) correspond to the `ID` fields of the book `DIV` elements. The values ('Untamed by Glennon Doyle', `"The Heart's Invisible Furies by John Boyne"`, etc.) are the book titles and authors.
|
||||
Lines 68–79: This JavaScript jQuery UI function defines the `droppable` functionality to be attached to HTML elements whose class is `drop`pable.
|
||||
Lines 69–75: When a `draggable` element is dropped onto a droppable element, the function drop is called.
|
||||
Line 70: The element variable is assigned the draggable object that was dropped (this will be a `<div id="..." class="draggable"...></div>` element.
|
||||
Line 71: The wrapping variable is assigned the value of the `ID` field in the draggable object.
|
||||
Line 72: This line is commented `out`, but while I was learning and testing, calls to `alert()` were useful.
|
||||
* Line 73: This reassigns the draggable object's background image to a bland image on which text can be read; part 1 of unwrapping is getting rid of the wrapping paper.
|
||||
* Line 74: This sets the text of the draggable object to the title of the book, looked up in the book's object using the draggable object's ID; part 2 of the unwrapping is showing the book title and author.
|
||||
Lines 76–78: For a while, I thought I wanted something to happen when a draggable object was removed from a droppable object (e.g., when a club member stole a book), which would require using the out function in a droppable object. Eventually, I decided not to do anything. But, this could note that the book was stolen and make it "unstealable" for one turn; or it could show a status line that says something like: "Wanda's book Blah Blah by Joe Blogs was stolen, and she needs to choose another."
|
||||
Line 80: This JavaScript jQuery UI function defines the draggable functionality to be attached to HTML elements whose class is draggable. In my case, the default behavior was all I needed.
|
||||
|
||||
That's it!
|
||||
|
||||
@@ -189,49 +180,38 @@ That's it!
|
||||
|
||||
Libraries like jQuery and jQuery UI are incredibly helpful when trying to do something complicated in JavaScript. Look at the `$().draggable()` and `$().droppable()` functions, for example:
|
||||
|
||||
|
||||
```
|
||||
`$( ".draggable" ).draggable();`
|
||||
$( ".draggable" ).draggable();
|
||||
```
|
||||
|
||||
The `".draggable"` allows associating the `draggable()` function with any HTML element whose class is "draggable." The `draggable()` function comes with all sorts of useful behavior about picking, dragging, and releasing a draggable HTML element.
|
||||
|
||||
If you haven't spent much time with jQuery, I really like the book [_jQuery in Action_][21] by Bear Bibeault, Yehuda Katz, and Aurelio De Rosa. Similarly, [_jQuery UI in Action_][22] by TJ VanToll is a great help with the jQuery UI (where draggable and droppable come from).
|
||||
If you haven't spent much time with jQuery, I really like the book [jQuery in Action][9] by Bear Bibeault, Yehuda Katz, and Aurelio De Rosa. Similarly, [jQuery UI in Action][10] by TJ VanToll is a great help with the jQuery UI (where draggable and droppable come from).
|
||||
|
||||
Of course, there are many other JavaScript libraries, frameworks, and what-nots around to do good stuff in the user interface. I haven't really started to explore all that jQuery and jQuery UI offer, and I want to play around with the rest to see what can be done.
|
||||
|
||||
Image by: (Chris Hermansen, CC BY-SA 4.0)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/open-source-gift-exchange
|
||||
|
||||
作者:[Chris Hermansen][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/clhermansen
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/brown-package-red-bow.jpg?itok=oxZYQzH- (Package wrapped with brown paper and red bow)
|
||||
[2]: https://all-free-download.com/free-vector/patterns-creative-commons.html#google_vignette
|
||||
[3]: https://opensource.com/tags/gimp
|
||||
[4]: https://opensource.com/sites/default/files/uploads/bookexchangestart.png (Virtual book exchange)
|
||||
[5]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[6]: https://opensource.com/sites/default/files/uploads/bookexchangeperson1.png (Virtual book exchange)
|
||||
[7]: https://opensource.com/sites/default/files/uploads/bookexchangeperson2.png (Virtual book exchange)
|
||||
[8]: http://december.com/html/4/element/html.html
|
||||
[9]: http://december.com/html/4/element/head.html
|
||||
[10]: http://december.com/html/4/element/meta.html
|
||||
[11]: http://december.com/html/4/element/title.html
|
||||
[12]: http://december.com/html/4/element/link.html
|
||||
[13]: http://december.com/html/4/element/style.html
|
||||
[14]: http://december.com/html/4/element/script.html
|
||||
[15]: https://code.jquery.com/jquery-1.12.4.js"\>\
|
||||
[16]: https://code.jquery.com/ui/1.12.1/jquery-ui.js"\>\
|
||||
[17]: http://december.com/html/4/element/body.html
|
||||
[18]: http://december.com/html/4/element/h1.html
|
||||
[19]: http://december.com/html/4/element/h2.html
|
||||
[20]: http://december.com/html/4/element/div.html
|
||||
[21]: https://www.manning.com/books/jquery-in-action-third-edition
|
||||
[22]: https://www.manning.com/books/jquery-ui-in-action
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/brown-package-red-bow.jpg
|
||||
[2]: https://unsplash.com/@jessbaileydesigns?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[3]: https://unsplash.com/s/photos/package?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[4]: https://all-free-download.com/free-vector/patterns-creative-commons.html#google_vignette
|
||||
[5]: https://opensource.com/tags/gimp
|
||||
[6]: https://opensource.com/sites/default/files/uploads/bookexchangestart.png
|
||||
[7]: https://opensource.com/sites/default/files/uploads/bookexchangeperson1.png
|
||||
[8]: https://opensource.com/sites/default/files/uploads/bookexchangeperson2.png
|
||||
[9]: https://www.manning.com/books/jquery-in-action-third-edition
|
||||
[10]: https://www.manning.com/books/jquery-ui-in-action
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Donkey)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (3 stress-free steps to tackling your task list)
|
||||
[#]: via: (https://opensource.com/article/21/1/break-down-tasks)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
3 stress-free steps to tackling your task list
|
||||
======
|
||||
Break your larger tasks into small steps to keep from being overwhelmed.
|
||||
![Team checklist][1]
|
||||
|
||||
In prior years, this annual series covered individual apps. This year, we are looking at all-in-one solutions in addition to strategies to help in 2021. Welcome to day 14 of 21 Days of Productivity in 2021.
|
||||
|
||||
At the start of the week, I like to review my schedule and look at the things I either need or would like to accomplish. And often, there are some items on that list that are relatively big. Whether it is an issue for work, a series of articles on productivity, or maybe an improvement to the chicken enclosures, the task can seem really daunting when taken as a single job. The odds are good that I will not be able to sit down and finish something like (just as an example, mind you) 21 articles in a single block of time, or even a single day.
|
||||
|
||||
![21 Days of Productivity project screenshot][2]
|
||||
|
||||
21 Days of Productivity (Kevin Sonney, [CC BY-SA 4.0][3])
|
||||
|
||||
So the first thing I do when I have something like this on my list is to break it down into smaller pieces. As Nobel laureate [William Faulkner][4] famously said, "The man who removes a mountain begins by carrying away small stones." We need to take our big tasks (the mountain) and find the individual steps (the small stones) that need to be done.
|
||||
|
||||
I use the following steps to break down my big tasks into little ones:
|
||||
|
||||
1. I usually have a fair idea of what needs to be done to complete a task. If not, I do a little research to figure that out.
|
||||
2. I write down the steps I think it will take, in order.
|
||||
3. Finally, I sit down with my calendar and the list and start to spread the tasks out across several days (or weeks, or months) to get an idea of when I might finish it.
|
||||
|
||||
|
||||
|
||||
Now I have not only a plan but an idea of how long it is going to take. As I complete each step, I can see that big task get not only a little smaller but closer to completion.
|
||||
|
||||
There is an old military saying that goes, "No plan survives contact with the enemy." It is almost certain that there will be a point or two (or five) where I realize that something as simple as "take a screenshot" needs to be expanded into something _much_ more complex. In fact, taking the screenshots of [Easy!Appointments][5] turned out to be:
|
||||
|
||||
1. Install and configure Easy!Appointments.
|
||||
2. Install and configure the Easy!Appointments WordPress plugin.
|
||||
3. Generate the API keys needed to sync the calendar.
|
||||
4. Take screenshots.
|
||||
|
||||
|
||||
|
||||
Even then, I had to break these tasks down into smaller pieces—download the software, configure NGINX, validate the installs…you get the idea. And that's OK. A plan, or set of tasks, is not set in stone and can be changed as needed.
|
||||
|
||||
![project completion pie chart][6]
|
||||
|
||||
About 2/3 done for this year! (Kevin Sonney, [CC BY-SA 4.0][3])
|
||||
|
||||
This is a learned skill and will take some effort the first few times. Learning how to break big tasks into smaller steps allows you to track progress towards a goal or completion of something big without getting overwhelmed in the process.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/break-down-tasks
|
||||
|
||||
作者:[Kevin Sonney][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/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/checklist_todo_clock_time_team.png?itok=1z528Q0y (Team checklist)
|
||||
[2]: https://opensource.com/sites/default/files/day14-image1.png
|
||||
[3]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[4]: https://en.wikipedia.org/wiki/William_Faulkner
|
||||
[5]: https://opensource.com/article/21/1/open-source-scheduler
|
||||
[6]: https://opensource.com/sites/default/files/day14-image2_1.png
|
||||
@@ -1,164 +1,151 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Introduction to Thunderbird mail filters)
|
||||
[#]: via: (https://fedoramagazine.org/introduction-to-thunderbird-mail-filters/)
|
||||
[#]: author: (Richard England https://fedoramagazine.org/author/rlengland/)
|
||||
[#]: subject: "Introduction to Thunderbird mail filters"
|
||||
[#]: via: "https://fedoramagazine.org/introduction-to-thunderbird-mail-filters/"
|
||||
[#]: author: "Richard England https://fedoramagazine.org/author/rlengland/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Introduction to Thunderbird mail filters
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
Everyone eventually runs into an inbox loaded with messages that they need to sort through. If you are like a lot of people, this is not a fast process. However, use of mail filters can make the task a little less tedious by letting Thunderbird pre-sort the messages into categories that reflect their source, priority, or usefulness. This article is an introduction to the creation of filters in Thunderbird.
|
||||
|
||||
Filters may be created for each email account you have created in Thunderbird. These are the accounts you see in the main Thunderbird folder pane shown at the left of the “Classic Layout”.
|
||||
|
||||
![Classic Layout][2]
|
||||
![][2]
|
||||
|
||||
There are two methods that can be used to create mail filters for your accounts. The first is based on the currently selected account and the second on the currently selected message. Both are discussed here.
|
||||
|
||||
### Message destination folder
|
||||
|
||||
Before filtering messages there has to be a destination for them. Create the destination by selecting a location to create a new folder. In this example the destination will be **Local Folders** shown in the accounts pane. Right click on **Local Folders** and select _New Folder…_ from the menu.
|
||||
Before filtering messages there has to be a destination for them. Create the destination by selecting a location to create a new folder. In this example the destination will be **Local Folders**shown in the accounts pane. Right click on **Local Folders** and select *New Folder…* from the menu.
|
||||
|
||||
![Creating a new folder][3]
|
||||
![][3]
|
||||
|
||||
Enter the name of the new folder in the menu and select _Create Folder._ The mail to filter is coming from the New York Times so that is the name entered.
|
||||
Enter the name of the new folder in the menu and select *Create Folder.* The mail to filter is coming from the New York Times so that is the name entered.
|
||||
|
||||
![Folder creation][4]
|
||||
![][4]
|
||||
|
||||
### Filter creation based on the selected account
|
||||
|
||||
Select the _Inbox_ for the account you wish to filter and select the toolbar menu item at _Tools > Message_Filters_.
|
||||
Select the *Inbox* for the account you wish to filter and select the toolbar menu item at *Tools > Message_Filters*.
|
||||
|
||||
![Message_Filters menu location][5]
|
||||
![][5]
|
||||
|
||||
The _Message Filters_ menu appears and is set to your pre-selected account as indicated at the top in the selection menu labelled _Filters for:_.
|
||||
The *Message Filters* menu appears and is set to your pre-selected account as indicated at the top in the selection menu labelled *Filters for:*.
|
||||
|
||||
![Message Filters menu][6]
|
||||
![][6]
|
||||
|
||||
Previously created filters, if any, are listed beneath the account name in the “_Filter Name”_ column. To the right of this list are controls that let you modify the filters selected. These controls are activated when you select a filter. More on this later.
|
||||
Previously created filters, if any, are listed beneath the account name in the “*Filter Name”*column. To the right of this list are controls that let you modify the filters selected. These controls are activated when you select a filter. More on this later.
|
||||
|
||||
Start creating your filter as follows:
|
||||
|
||||
1. Verify the correct account has been pre-selected. It may be changed if necessary.
|
||||
2. Select _New…_ from the menu list at the right.
|
||||
1. Verify the correct account has been pre-selected. It may be changed if necessary.
|
||||
2. Select New… from the menu list at the right.
|
||||
|
||||
|
||||
|
||||
When you select _New_ you will see the _Filter Rules_ menu where you define your filter. Note that when using _New…_ you have the option to copy an existing filter to use as a template or to simply duplicate the settings.
|
||||
When you select *New* you will see the *Filter Rules*menu where you define your filter. Note that when using *New…* you have the option to copy an existing filter to use as a template or to simply duplicate the settings.
|
||||
|
||||
Filter rules are made up of three things, the “property” to be tested, the “test”, and the “value” to be tested against. Once the condition is met, the “action” is performed.
|
||||
|
||||
![Message Filters menu][7]
|
||||
![][7]
|
||||
|
||||
Complete this filter as follows:
|
||||
|
||||
1. Enter an appropriate name in the textbox labelled _Filter name:_
|
||||
2. Select the property _From_ in the left drop down menu, if not set.
|
||||
3. Leave the test set to _contains_.
|
||||
4. Enter the value, in this case the email address of the sender.
|
||||
1. Enter an appropriate name in the textbox labelled Filter name:
|
||||
2. Select the property From in the left drop down menu, if not set.
|
||||
3. Leave the test set to contains.
|
||||
4. Enter the value, in this case the email address of the sender.
|
||||
|
||||
Under the *Perform these actions:* section at the bottom, create an action rule to move the message and choose the destination.
|
||||
|
||||
1. Select Move Messages to from the left end of the action line.
|
||||
2. Select Choose Folder… and select Local Folders > New York Times.
|
||||
3. Select OK.
|
||||
|
||||
Under the _Perform these actions:_ section at the bottom, create an action rule to move the message and choose the destination.
|
||||
By default the **Apply filter when:** is set to *Manually Run* and *Getting New Mail:*. This means that when new mail appears in the Inbox for this account the filter will be applied and you may run it manually at any time, if necessary. There are other options available but they are too numerous to be discussed in this introduction. They are, however, for the most part self explanatory.
|
||||
|
||||
1. Select _Move Messages to_ from the left end of the action line.
|
||||
2. Select _Choose Folder…_ and select _Local Folders > New York Times_.
|
||||
3. Select _OK_.
|
||||
If more than one rule or action is to be created during the same session, the “+” to the right of each entry provides that option. Additional property, test, and value entries can be added. If more than one rule is created, make certain that the appropriate option for *Match all of the following* and *Match any of the following* is selected. In this example the choice does not matter since we are only setting one filter.
|
||||
|
||||
After selecting *OK,*the *Message Filters* menu is displayed again showing your newly created filter. Note that the menu items on the right side of the menu are now active for *Edit…* and *Delete.*
|
||||
|
||||
![][8]
|
||||
|
||||
By default the **Apply filter when:** is set to _Manually Run_ and _Getting New Mail:_. This means that when new mail appears in the Inbox for this account the filter will be applied and you may run it manually at any time, if necessary. There are other options available but they are too numerous to be discussed in this introduction. They are, however, for the most part self explanatory.
|
||||
Also notice the message *“Enabled filters are run automatically in the order shown below”*. If there are multiple filters the order is changed by selecting the one to be moved and using the *Move to Top, Move Up, Move Down,*or*Move to Bottom* buttons. The order can change the destination of your messages so consider the tests used in each filter carefully when deciding the order.
|
||||
|
||||
If more than one rule or action is to be created during the same session, the “+” to the right of each entry provides that option. Additional property, test, and value entries can be added. If more than one rule is created, make certain that the appropriate option for _Match all of the following_ and _Match any of the following_ is selected. In this example the choice does not matter since we are only setting one filter.
|
||||
|
||||
After selecting _OK,_ the _Message Filters_ menu is displayed again showing your newly created filter. Note that the menu items on the right side of the menu are now active for _Edit…_ and _Delete._
|
||||
|
||||
![First filter in the Message Filters menu][8]
|
||||
|
||||
Also notice the message _“Enabled filters are run automatically in the order shown below”_. If there are multiple filters the order is changed by selecting the one to be moved and using the _Move to Top, Move Up, Move Down,_ or _Move to Bottom_ buttons. The order can change the destination of your messages so consider the tests used in each filter carefully when deciding the order.
|
||||
|
||||
Since you have just created this filter you may wish to use the _Run Now_ button to run your newly created filter on the Inbox shown to the left of the button.
|
||||
Since you have just created this filter you may wish to use the *Run Now* button to run your newly created filter on the Inbox shown to the left of the button.
|
||||
|
||||
### Filter creation based on a message
|
||||
|
||||
An alternative creation technique is to select a message from the message pane and use the _Create Filter From Message…_ option from the menu bar.
|
||||
An alternative creation technique is to select a message from the message pane and use the *Create Filter From Message…* option from the menu bar.
|
||||
|
||||
In this example the filter will use two rules to select the messages: the email address and a text string in the Subject line of the email. Start as follows:
|
||||
In this example the filter will use two rules to select the messages: the email address and a text string in the Subject line of the email. Start as follows:
|
||||
|
||||
1. Select a message in the message page.
|
||||
2. Select the filter options on the toolbar at _Message > Create Filter From Message…_.
|
||||
1. Select a message in the message page.
|
||||
2. Select the filter options on the toolbar at Message > Create Filter From Message….
|
||||
|
||||
![][9]
|
||||
|
||||
|
||||
![Create new filters from Messages][9]
|
||||
|
||||
The pre-selected message, highlighted in grey in the message pane above, determines the account used and _Create Filter From Message…_ takes you directly to the _Filter Rules_ menu.
|
||||
The pre-selected message, highlighted in grey in the message pane above, determines the account used and *Create Filter From Message…* takes you directly to the *Filter Rules* menu.
|
||||
|
||||
![][10]
|
||||
|
||||
The property (_From_), test (_is_), and value (email) are pre-set for you as shown in the image above. Complete this filter as follows:
|
||||
The property (*From*), test (*is*), and value (email) are pre-set for you as shown in the image above. Complete this filter as follows:
|
||||
|
||||
1. Enter an appropriate name in the textbox labelled _Filter name:_. _COVID_ is the name in this case.
|
||||
2. Check that the property is _From_.
|
||||
3. Verify the test is set to _is_.
|
||||
4. Confirm that the value for the email address is from the correct sender.
|
||||
5. Select the “+” to the right of the _From_ rule to create a new filter rule.
|
||||
6. In the new rule, change the default property entry _From_ to _Subject_ using the pulldown menu.
|
||||
7. Set the test to _contains_.
|
||||
8. Enter the value text to be matched in the Email “Subject” line. In this case _COVID_.
|
||||
1. Enter an appropriate name in the textbox labelled Filter name:. COVID is the name in this case.
|
||||
2. Check that the property is From.
|
||||
3. Verify the test is set to is.
|
||||
4. Confirm that the value for the email address is from the correct sender.
|
||||
5. Select the “+” to the right of the From rule to create a new filter rule.
|
||||
6. In the new rule, change the default property entry From to Subject using the pulldown menu.
|
||||
7. Set the test to contains.
|
||||
8. Enter the value text to be matched in the Email “Subject” line. In this case COVID.
|
||||
|
||||
Since we left the *Match all of the following* item checked, each message will be from the address chosen AND will have the text *COVID* in the email subject line.
|
||||
|
||||
Now use the action rule to choose the destination for the messages under the *Perform these actions:* section at the bottom:
|
||||
|
||||
Since we left the _Match all of the following_ item checked, each message will be from the address chosen AND will have the text _COVID_ in the email subject line.
|
||||
1. Select Move Messages to from the left menu.
|
||||
2. Select Choose Folder… and select Local Folders > COVID in Scotland. (This destination was created before this example was started. There was no magic here.)
|
||||
3. Select OK.
|
||||
|
||||
Now use the action rule to choose the destination for the messages under the _Perform these actions:_ section at the bottom:
|
||||
|
||||
1. Select _Move Messages to_ from the left menu.
|
||||
2. Select _Choose Folder…_ and select _Local Folders > COVID in Scotland_. (This destination was created before this example was started. There was no magic here.)
|
||||
3. Select _OK_.
|
||||
|
||||
|
||||
|
||||
_OK_ will cause the _Message Filters_ menu to appear, again, verifying that the new filter has been created.
|
||||
*OK* will cause the *Message Filters* menu to appear, again, verifying that the new filter has been created.
|
||||
|
||||
### The Message Filters menu
|
||||
|
||||
All the message filters you create will appear in the _Message Filters_ menu. Recall that the _Message Filters_ is available in the menu bar at _Tools > Message Filters_.
|
||||
All the message filters you create will appear in the *Message Filters* menu. Recall that the *Message Filters* is available in the menu bar at *Tools > Message Filters*.
|
||||
|
||||
Once you have created filters there are several options to manage them. To change a filter, select the filter in question and click on the _Edit_ button. This will take you back to the _Filter Rules_ menu for that filter. As mentioned earlier, you can change the order in which the rules are apply here using the _Move_ buttons. Disable a filter by clicking on the check mark in the _Enabled_ column.
|
||||
Once you have created filters there are several options to manage them. To change a filter, select the filter in question and click on the *Edit* button. This will take you back to the *Filter Rules* menu for that filter. As mentioned earlier, you can change the order in which the rules are apply here using the *Move* buttons. Disable a filter by clicking on the check mark in the *Enabled* column.
|
||||
|
||||
![][11]
|
||||
|
||||
The _Run Now_ button will execute the selected filter immediately. You may also run your filter from the menu bar using _Tools > Run Filters on Folder_ or _Tools > Run Filters on Message_.
|
||||
The *Run Now* button will execute the selected filter immediately. You may also run your filter from the menu bar using *Tools > Run Filters on Folder* or *Tools > Run Filters on Message*.
|
||||
|
||||
### Next step
|
||||
|
||||
This article hasn’t covered every feature available for message filtering but hopefully it provides enough information for you to get started. Places for further investigation are the “property”, “test”, and “actions” in the _Filter menu_ as well as the settings there for when your filter is to be run, _Archiving, After Sending,_ and _Periodically_.
|
||||
This article hasn’t covered every feature available for message filtering but hopefully it provides enough information for you to get started. Places for further investigation are the “property”, “test”, and “actions” in the *Filter menu* as well as the settings there for when your filter is to be run, *Archiving, After Sending,* and *Periodically*.
|
||||
|
||||
### References
|
||||
|
||||
Mozilla: [Organize][12] [Your Messages][12] [by Using Filters][12]
|
||||
Mozilla: [Organize][12][Your Messages][13][by Using Filters][14]
|
||||
|
||||
MozillaZine: [Message][13] [Filters][13]
|
||||
MozillaZine: [Message][15][Filters][16]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/introduction-to-thunderbird-mail-filters/
|
||||
|
||||
作者:[Richard England][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/rlengland/
|
||||
[b]: https://github.com/lujun9972
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2021/01/Tbird_mail_filters-1-816x345.jpg
|
||||
[2]: https://fedoramagazine.org/wp-content/uploads/2021/01/Image_001-1024x613.png
|
||||
[3]: https://fedoramagazine.org/wp-content/uploads/2021/01/Image_New_Folder.png
|
||||
@@ -171,4 +158,7 @@ via: https://fedoramagazine.org/introduction-to-thunderbird-mail-filters/
|
||||
[10]: https://fedoramagazine.org/wp-content/uploads/2021/01/Filter_rules_2-1.png
|
||||
[11]: https://fedoramagazine.org/wp-content/uploads/2021/01/Message_Filters_2nd_entry.png
|
||||
[12]: https://support.mozilla.org/en-US/kb/organize-your-messages-using-filters
|
||||
[13]: http://kb.mozillazine.org/Filters_%28Thunderbird%29
|
||||
[13]: https://support.mozilla.org/en-US/kb/organize-your-messages-using-filters
|
||||
[14]: https://support.mozilla.org/en-US/kb/organize-your-messages-using-filters
|
||||
[15]: http://kb.mozillazine.org/Filters_%28Thunderbird%29
|
||||
[16]: http://kb.mozillazine.org/Filters_%28Thunderbird%29
|
||||
|
||||
@@ -1,46 +1,43 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Interview with Shuah Khan, Kernel Maintainer & Linux Fellow)
|
||||
[#]: via: (https://www.linux.com/news/interview-with-shuah-khan-kernel-maintainer-linux-fellow/)
|
||||
[#]: author: (The Linux Foundation https://www.linuxfoundation.org/en/blog/interview-with-shuah-khan-kernel-maintainer-linux-fellow/)
|
||||
[#]: subject: "Interview with Shuah Khan, Kernel Maintainer & Linux Fellow"
|
||||
[#]: via: "https://www.linux.com/news/interview-with-shuah-khan-kernel-maintainer-linux-fellow/"
|
||||
[#]: author: "The Linux Foundation https://www.linuxfoundation.org/en/blog/interview-with-shuah-khan-kernel-maintainer-linux-fellow/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Interview with Shuah Khan, Kernel Maintainer & Linux Fellow
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
_Jason Perlow, Director of Project Insights and Editorial Content at the Linux Foundation, had an opportunity to speak with Shuah Khan about her experiences as a woman in the technology industry. She discusses how mentorship can improve the overall diversity and makeup of open source projects, why software maintainers are important for the health of open source projects such as the Linux kernel, and how language inclusivity and codes of conduct can improve relationships and communication between software maintainers and individual contributors._
|
||||
Jason Perlow, Director of Project Insights and Editorial Content at the Linux Foundation, had an opportunity to speak with Shuah Khan about her experiences as a woman in the technology industry. She discusses how mentorship can improve the overall diversity and makeup of open source projects, why software maintainers are important for the health of open source projects such as the Linux kernel, and how language inclusivity and codes of conduct can improve relationships and communication between software maintainers and individual contributors.
|
||||
|
||||
**JP:** So, Shuah, I know you wear many different hats at the Linux Foundation. What do you call yourself around here these days?
|
||||
|
||||
**SK:** <laughs> Well, I primarily call myself a Kernel Maintainer & Linux Fellow. In addition to that, I focus on two areas that are important to the continued health and sustainability of the open source projects in the Linux ecosystem. The first one is bringing more women into the Kernel community, and additionally, I am leading the mentorship program efforts overall at the Linux Foundation. And in that role, in addition to the Linux Kernel Mentorship, we are looking at how the Linux Foundation mentorship program is working overall, how it is scaling. I make sure the [LFX Mentorship][2] platform scales and serves diverse mentees and mentors’ needs in this role.
|
||||
**SK:** <laughs> Well, I primarily call myself a Kernel Maintainer & Linux Fellow. In addition to that, I focus on two areas that are important to the continued health and sustainability of the open source projects in the Linux ecosystem. The first one is bringing more women into the Kernel community, and additionally, I am leading the mentorship program efforts overall at the Linux Foundation. And in that role, in addition to the Linux Kernel Mentorship, we are looking at how the Linux Foundation mentorship program is working overall, how it is scaling. I make sure the [LFX Mentorship][1] platform scales and serves diverse mentees and mentors’ needs in this role.
|
||||
|
||||
The LF mentorships program includes several projects in the Linux kernel, LFN, HyperLedger, Open MainFrame, OpenHPC, and other technologies. [The Linux Foundation’s Mentorship Programs][3] are designed to help developers with the necessary skills–many of whom are first-time open source contributors–experiment, learn, and contribute effectively to open source communities.
|
||||
The LF mentorships program includes several projects in the Linux kernel, LFN, HyperLedger, Open MainFrame, OpenHPC, and other technologies. [The Linux Foundation’s Mentorship Programs][2] are designed to help developers with the necessary skills–many of whom are first-time open source contributors–experiment, learn, and contribute effectively to open source communities.
|
||||
|
||||
The mentorship program has been successful in its mission to train new developers and make these talented pools of prospective employees trained by experts to employers. Several graduated mentees have found jobs. New developers have improved the quality and security of various open source projects, including the Linux kernel. Several Linux kernel bugs were fixed, a new subsystem mentor was added, and a new driver maintainer is now part of the Linux kernel community. My sincere thanks to all our mentors for volunteering to share their expertise.
|
||||
|
||||
**JP:** How long have you been working on the Kernel?
|
||||
|
||||
**SK:** Since 2010, or 2011, I got involved in the [Android Mainlining project][4]. My [first patch removed the Android pmem driver][5].
|
||||
**SK:** Since 2010, or 2011, I got involved in the [Android Mainlining project][3]. My [first patch removed the Android pmem driver][4].
|
||||
|
||||
**JP:** Wow! Is there any particular subsystem that you specialize in?
|
||||
|
||||
**SK:** I am a self described generalist. I maintain the [kernel self-test][6] subsystem, the [USB over IP driver][7], [usbip tool][8], and the [cpupower][9] tool. I contributed to the media subsystem working on [Media Controller Device Allocator API][10] to resolve shared device resource management problems across device drivers from different subsystems.
|
||||
**SK:** I am a self described generalist. I maintain the [kernel self-test][5] subsystem, the [USB over IP driver][6], [usbip tool][7], and the [cpupower][8] tool. I contributed to the media subsystem working on [Media Controller Device Allocator API][9] to resolve shared device resource management problems across device drivers from different subsystems.
|
||||
|
||||
**JP:** Hey, I’ve [actually used the USB over IP driver][11] when I worked at Microsoft on Azure. And also, when I’ve used AWS and Google Compute.
|
||||
**JP:** Hey, I’ve [actually used the USB over IP driver][10] when I worked at Microsoft on Azure. And also, when I’ve used AWS and Google Compute.
|
||||
|
||||
**SK:** It’s a small niche driver used in cloud computing. Docker and other containers use that driver heavily. That’s how they provide remote access to USB devices on the server to export devices to be imported by other systems for use.
|
||||
|
||||
**JP:** I initially used it for IoT kinds of stuff in the embedded systems space. Were you the original lead developer on it, or was it one of those things you fell into because nobody else was maintaining it?
|
||||
|
||||
**SK:** Well, twofold. I was looking at USB over IP because I like that technology. it just so happened the driver was brought from the staging tree into the Mainline kernel, I volunteered at the time to maintain it. Over the last few years, we discovered some security issues with it, because it handles a lot of userspace data, so I had a lot of fun fixing all of those. <laugh>.
|
||||
**SK:** Well, twofold. I was looking at USB over IP because I like that technology. it just so happened the driver was brought from the staging tree into the Mainline kernel, I volunteered at the time to maintain it. Over the last few years, we discovered some security issues with it, because it handles a lot of userspace data, so I had a lot of fun fixing all of those. <laugh>.
|
||||
|
||||
**JP:** What drew you into the Linux operating system, and what drew you into the kernel development community in the first place?
|
||||
|
||||
**SK:** Well, I have been doing kernel development for a very long time. I worked on the [LynxOS RTOS][12], a while back, and then HP/UX, when I was working at HP, after which I transitioned into doing open source development — the [OpenHPI][13] project, to support HP’s rack server hardware, and that allowed me to work much more closely with Linux on the back end. And at some point, I decided I wanted to work with the kernel and become part of the Linux kernel community. I started as an independent contributor.
|
||||
**SK:** Well, I have been doing kernel development for a very long time. I worked on the [LynxOS RTOS][11], a while back, and then HP/UX, when I was working at HP, after which I transitioned into doing open source development — the [OpenHPI][12] project, to support HP’s rack server hardware, and that allowed me to work much more closely with Linux on the back end. And at some point, I decided I wanted to work with the kernel and become part of the Linux kernel community. I started as an independent contributor.
|
||||
|
||||
**JP:** Maybe it just displays my own ignorance, but you are the first female, hardcore Linux kernel developer I have ever met. I mean, I had met female core OS developers before — such as when I was at Microsoft and IBM — but not for Linux. Why do you suppose we lack women and diversity in general when participating in open source and the technology industry overall?
|
||||
|
||||
@@ -52,9 +49,9 @@ There’s a natural resistance to choosing certain professions that you have to
|
||||
|
||||
**SK:** Yes.
|
||||
|
||||
**JP:** It’s funny; my wife really likes this [Netflix show about matchmaking in India][14]. Are you familiar with it?
|
||||
**JP:** It’s funny; my wife really likes this [Netflix show about matchmaking in India][13]. Are you familiar with it?
|
||||
|
||||
**SK:** <laughs> Yes I enjoyed the series, and [A Suitable Girl][15] documentary film that follows three women as they navigate making decisions about their careers and family obligations.
|
||||
**SK:** <laughs> Yes I enjoyed the series, and [A Suitable Girl][14] documentary film that follows three women as they navigate making decisions about their careers and family obligations.
|
||||
|
||||
**JP:** For many Americans, this is our first introduction to what home life is like for Indian people. But many of the women featured on this show are professionals, such as doctors, lawyers, and engineers. And they are very ambitious, but of course, the family tries to set them up in a marriage to find a husband for them that is compatible. As a result, you get to learn about the traditional values and roles they still want women to play there — while at the same time, many women are coming out of higher learning institutions in that country that are seeking technical careers.
|
||||
|
||||
@@ -62,11 +59,11 @@ There’s a natural resistance to choosing certain professions that you have to
|
||||
|
||||
**JP:** Women in technical and STEM professions are becoming much more prominent in other countries, such as China, Japan, and Korea. For some reason, in the US, I tend to see more women enter the medical profession than hard technology — and it might be a level of effort and perceived reward thing. You can spend eight years becoming a medical doctor or eight years becoming a scientist or an engineer, and it can be equally difficult, but the compensation at the end may not be the same. It’s expensive to get an education, and it takes a long time and hard work, regardless of the professional discipline.
|
||||
|
||||
**SK:** I have also heard that women also like to enter professions where they can make a difference in the world — a human touch, if you will. So that may translate to them choosing careers where they can make a larger impact on people — and they may view careers in technology as not having those same attributes. Maybe when we think about attracting women to technology fields, we might have to promote technology aspects that make a difference. That may be changing now, such as the [LF Public Health][16] (LFPH) project we kicked off last year. And with [LF AI & Data Foundation][17], we are also making a difference in people’s lives, such as [detecting earthquakes][18] or [analyzing climate change][19]. If we were to promote projects such as these, we might draw more women in.
|
||||
**SK:** I have also heard that women also like to enter professions where they can make a difference in the world — a human touch, if you will. So that may translate to them choosing careers where they can make a larger impact on people — and they may view careers in technology as not having those same attributes. Maybe when we think about attracting women to technology fields, we might have to promote technology aspects that make a difference. That may be changing now, such as the [LF Public Health][15] (LFPH) project we kicked off last year. And with [LF AI & Data Foundation][16], we are also making a difference in people’s lives, such as [detecting earthquakes][17] or [analyzing climate change][18]. If we were to promote projects such as these, we might draw more women in.
|
||||
|
||||
**JP:** So clearly, one of the areas of technology where you can make a difference is in open source, as the LF is hosting some very high-concept and existential types of projects such as [LF Energy][20], for example — I had no idea what was involved in it and what its goals were until I spoke to [Shuli Goodman][21] in-depth about it. With the mentorship program, I assume we need this to attract fresh talent — because as folks like us get older and retire, and they exit the field, we need new people to replace them. So I assume mentorship, for the Linux Foundation, is an investment in our own technologies, correct?
|
||||
**JP:** So clearly, one of the areas of technology where you can make a difference is in open source, as the LF is hosting some very high-concept and existential types of projects such as [LF Energy][19], for example — I had no idea what was involved in it and what its goals were until I spoke to [Shuli Goodman][20] in-depth about it. With the mentorship program, I assume we need this to attract fresh talent — because as folks like us get older and retire, and they exit the field, we need new people to replace them. So I assume mentorship, for the Linux Foundation, is an investment in our own technologies, correct?
|
||||
|
||||
**SK:** Correct. Bringing in new developers into the fold is the primary purpose, of course — and at the same time, I view the LF as taking on mentorship provides that neutral, level playing field across the industry for all open source projects. Secondly, we offer a self-service platform, [LFX Mentorship][22], where anyone can come in and start their project. So when the COVID-19 pandemic began, we [expanded this program to help displaced people][3] — students, et cetera, and less visible projects. Not all projects typically get as much funding or attention as others do — such as a Kubernetes or Linux kernel — among the COVID mentorship program projects we are funding. I am particularly proud of supporting a climate change-related project, [Using Machine Learning to Predict Deforestation][23].
|
||||
**SK:** Correct. Bringing in new developers into the fold is the primary purpose, of course — and at the same time, I view the LF as taking on mentorship provides that neutral, level playing field across the industry for all open source projects. Secondly, we offer a self-service platform, [LFX Mentorship][21], where anyone can come in and start their project. So when the COVID-19 pandemic began, we [expanded this program to help displaced people][22] — students, et cetera, and less visible projects. Not all projects typically get as much funding or attention as others do — such as a Kubernetes or Linux kernel — among the COVID mentorship program projects we are funding. I am particularly proud of supporting a climate change-related project, [Using Machine Learning to Predict Deforestation][23].
|
||||
|
||||
The self-service approach allows us to fund and add new developers to projects where they are needed. The LF mentorships are remote work opportunities that are accessible to developers around the globe. We see people sign up for mentorship projects from places we haven’t seen before, such as Africa, and so on, thus creating a level playing field.
|
||||
|
||||
@@ -122,43 +119,43 @@ Talking about backpacking reminded me of the two-day, 22-mile backpacking trip d
|
||||
|
||||
**JP:** Awesome. I enjoyed talking to you today. So happy I finally got to meet you virtually.
|
||||
|
||||
The post [Interview with Shuah Khan, Kernel Maintainer & Linux Fellow][33] appeared first on [Linux Foundation][34].
|
||||
The post [Interview with Shuah Khan, Kernel Maintainer & Linux Fellow][33] appeared first on [Linux Foundation][34].
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/news/interview-with-shuah-khan-kernel-maintainer-linux-fellow/
|
||||
|
||||
作者:[The Linux Foundation][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.linuxfoundation.org/en/blog/interview-with-shuah-khan-kernel-maintainer-linux-fellow/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.linux.com/wp-content/uploads/2021/01/3E9C3E02-5F59-4A99-AD4A-814C7B8737A9_1_105_c.jpeg
|
||||
[2]: https://lfx.linuxfoundation.org/tools/mentorship/
|
||||
[3]: https://linuxfoundation.org/about/diversity-inclusivity/mentorship/
|
||||
[4]: https://elinux.org/Android_Mainlining_Project
|
||||
[5]: https://lkml.org/lkml/2012/1/26/368
|
||||
[6]: https://www.kernel.org/doc/html/v4.15/dev-tools/kselftest.html
|
||||
[7]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/usbip
|
||||
[8]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/usb/usbip
|
||||
[9]: https://www.systutorials.com/docs/linux/man/1-cpupower/
|
||||
[10]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/media/mc/mc-dev-allocator.c
|
||||
[11]: https://www.linux-magazine.com/Issues/2018/208/Tutorial-USB-IP
|
||||
[12]: https://en.wikipedia.org/wiki/LynxOS
|
||||
[13]: http://www.openhpi.org/Developers
|
||||
[14]: https://www.netflix.com/title/80244565
|
||||
[15]: https://en.wikipedia.org/wiki/A_Suitable_Girl_(film)
|
||||
[16]: https://www.lfph.io/
|
||||
[17]: https://lfaidata.foundation/
|
||||
[18]: https://openeew.com/
|
||||
[19]: https://www.os-climate.org/
|
||||
[20]: https://www.lfenergy.org/
|
||||
[21]: mailto:sgoodman@contractor.linuxfoundation.org
|
||||
[22]: https://mentorship.lfx.linuxfoundation.org/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://lfx.linuxfoundation.org/tools/mentorship/
|
||||
[2]: https://linuxfoundation.org/about/diversity-inclusivity/mentorship/
|
||||
[3]: https://elinux.org/Android_Mainlining_Project
|
||||
[4]: https://lkml.org/lkml/2012/1/26/368
|
||||
[5]: https://www.kernel.org/doc/html/v4.15/dev-tools/kselftest.html
|
||||
[6]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/usbip
|
||||
[7]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/usb/usbip
|
||||
[8]: https://www.systutorials.com/docs/linux/man/1-cpupower/
|
||||
[9]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/media/mc/mc-dev-allocator.c
|
||||
[10]: https://www.linux-magazine.com/Issues/2018/208/Tutorial-USB-IP
|
||||
[11]: https://en.wikipedia.org/wiki/LynxOS
|
||||
[12]: http://www.openhpi.org/Developers
|
||||
[13]: https://www.netflix.com/title/80244565
|
||||
[14]: https://en.wikipedia.org/wiki/A_Suitable_Girl_(film)
|
||||
[15]: https://www.lfph.io/
|
||||
[16]: https://lfaidata.foundation/
|
||||
[17]: https://openeew.com/
|
||||
[18]: https://www.os-climate.org/
|
||||
[19]: https://www.lfenergy.org/
|
||||
[20]: https://www.linux.com/mailto:sgoodman@contractor.linuxfoundation.org
|
||||
[21]: https://mentorship.lfx.linuxfoundation.org/
|
||||
[22]: https://linuxfoundation.org/about/diversity-inclusivity/mentorship/
|
||||
[23]: https://mentorship.lfx.linuxfoundation.org/project/926665ac-9b96-45aa-bb11-5d99096be870
|
||||
[24]: https://www.linuxfoundation.org/en/blog/preventing-supply-chain-attacks-like-solarwinds/
|
||||
[25]: https://www.linuxfoundation.org/en/press-release/new-open-source-contributor-report-from-linux-foundation-and-harvard-identifies-motivations-and-opportunities-for-improving-software-security/
|
||||
@@ -92,7 +92,7 @@ The system is trying to remove an item that does not exist in the basket, and it
|
||||
|
||||
```
|
||||
public int RemoveItem(Hashtable item) {
|
||||
if(basket.IndexOf(item) >= 0) {
|
||||
if(basket.IndexOf(item) >= 0) {
|
||||
basket.RemoveAt(basket.IndexOf(item));
|
||||
}
|
||||
return basket.Count;
|
||||
|
||||
@@ -86,7 +86,7 @@ Implement this processing logic in the `ShippingAPI` class:
|
||||
```
|
||||
private double Calculate10PercentDiscount(double total) {
|
||||
double discount = 0.00;
|
||||
if(total > 500.00) {
|
||||
if(total > 500.00) {
|
||||
discount = (total/100) * 10;
|
||||
}
|
||||
return discount;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Astrophotography with Fedora Astronomy Lab: setting up)
|
||||
[#]: via: (https://fedoramagazine.org/astrophotography-with-fedora-astronomy-lab-setting-up/)
|
||||
[#]: author: (Geoffrey Marr https://fedoramagazine.org/author/coremodule/)
|
||||
[#]: subject: "Astrophotography with Fedora Astronomy Lab: setting up"
|
||||
[#]: via: "https://fedoramagazine.org/astrophotography-with-fedora-astronomy-lab-setting-up/"
|
||||
[#]: author: "Geoffrey Marr https://fedoramagazine.org/author/coremodule/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Astrophotography with Fedora Astronomy Lab: setting up
|
||||
======
|
||||
@@ -28,21 +28,15 @@ Download Fedora Astronomy Lab from the [Fedora Labs website][4]. You will need a
|
||||
|
||||
Before you can go capturing the heavens, you need to do some minor setup in Fedora Astronomy Lab.
|
||||
|
||||
First of all, you need to add your user to the _dialout_ group so that you can access certain pieces of astronomical equipment from within the guiding software. Do that by opening the terminal (Konsole) and running this command (replacing _user_ with your username):
|
||||
First of all, you need to add your user to the *dialout* group so that you can access certain pieces of astronomical equipment from within the guiding software. Do that by opening the terminal (Konsole) and running this command (replacing *user* with your username):
|
||||
|
||||
sudo usermod -a -G dialout user
|
||||
|
||||
My personal setup includes a guide camera (QHY5 series, also known as Orion Starshoot) that does not have a driver in the mainline Fedora repositories. To enable it, ypu need to install the [qhyccd SDK][9]. (_Note that this package is not officially supported by Fedora. Use it at your own risk.)_ At the time of writing, I chose to use the latest stable release, 20.08.26. Once you download the Linux 64-bit version of the SDK, to extract it:
|
||||
```
|
||||
My personal setup includes a guide camera (QHY5 series, also known as Orion Starshoot) that does not have a driver in the mainline Fedora repositories. To enable it, ypu need to install the [qhyccd SDK][9]. (*Note that this package is not officially supported by Fedora. Use it at your own risk.)* At the time of writing, I chose to use the latest stable release, 20.08.26. Once you download the Linux 64-bit version of the SDK, to extract it:
|
||||
|
||||
```
|
||||
|
||||
tar zxvf sdk_linux64_20.08.26.tgz
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Now change into the directory you just extracted, change the permissions of the _install.sh_ file to give you execute privileges, and run the _install.sh_:
|
||||
Now change into the directory you just extracted, change the permissions of the *install.sh* file to give you execute privileges, and run the *install.sh*:
|
||||
|
||||
```
|
||||
cd sdk_linux64_20.08.26
|
||||
@@ -50,49 +44,35 @@ chmod +x install.sh
|
||||
sudo ./install.sh
|
||||
```
|
||||
|
||||
Now it’s time to install the qhyccd INDI driver. INDI is an open source software library used to control astronomical equipment. Unfortunately, the driver is unavailable in the mainline Fedora repositories, but it is in a Copr repository. (_Note: Copr is not officially supported by Fedora infrastructure. Use packages at your own risk.)_ If you prefer to have the newest (and perhaps unstable!) pieces of astronomy software, you can also enable the “bleeding” repositories at this time by following [this guide][10]. For this tutorial, you are only going to enable one repo:
|
||||
```
|
||||
Now it’s time to install the qhyccd INDI driver. INDI is an open source software library used to control astronomical equipment. Unfortunately, the driver is unavailable in the mainline Fedora repositories, but it is in a Copr repository. (*Note: Copr is not officially supported by Fedora infrastructure. Use packages at your own risk.)* If you prefer to have the newest (and perhaps unstable!) pieces of astronomy software, you can also enable the “bleeding” repositories at this time by following [this guide][10]. For this tutorial, you are only going to enable one repo:
|
||||
|
||||
```
|
||||
|
||||
sudo dnf copr enable xsnrg/indi-3rdparty-bleeding
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Install the driver by running the following command:
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
sudo dnf install indi-qhy
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
Finally, update all of your system packages:
|
||||
|
||||
sudo dnf update -y
|
||||
|
||||
To recap what you accomplished in this sectio: you added your user to the _dialout_ group, downloaded and installed the qhyccd driver, enabled the _indi-3rdparty-bleeding_ copr, installed the qhyccd-INDI driver with dnf, and updated your system.
|
||||
To recap what you accomplished in this sectio: you added your user to the *dialout* group, downloaded and installed the qhyccd driver, enabled the *indi-3rdparty-bleeding* copr, installed the qhyccd-INDI driver with dnf, and updated your system.
|
||||
|
||||
### Connecting your equipment
|
||||
|
||||
This is the time to connect all your equipment to your computer. Most astronomical equipment will connect via USB, and it’s really as easy as plugging each device into your computer’s USB ports. If you have a lot of equipment (mount, imaging camera, guide camera, focuser, filter wheel, etc), you should use an external powered-USB hub to make sure that all connected devices have adequate power. Once you have everything plugged in, run the following command to ensure that the system recognizes your equipment:
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
lsusb
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
You should see output similar to (but not the same as) the output here:
|
||||
|
||||
![][11]
|
||||
|
||||
You see in the output that the system recognizes the telescope mount (a SkyWatcher EQM-35 Pro) as _Prolific Technology, Inc. PL2303 Serial Port_, the imaging camera (a Sony a6000) as _Sony Corp. ILCE-6000_, and the guide camera (an Orion Starshoot, aka QHY5) as _Van Ouijen Technische Informatica_. Now that you have made sure your system recognizes your equipment, it’s time to open your desktop planetarium and telescope controller, KStars!
|
||||
You see in the output that the system recognizes the telescope mount (a SkyWatcher EQM-35 Pro) as *Prolific Technology, Inc. PL2303 Serial Port*, the imaging camera (a Sony a6000) as *Sony Corp. ILCE-6000*, and the guide camera (an Orion Starshoot, aka QHY5) as *Van Ouijen Technische Informatica*. Now that you have made sure your system recognizes your equipment, it’s time to open your desktop planetarium and telescope controller, KStars!
|
||||
|
||||
### Setting up KStars
|
||||
|
||||
@@ -100,15 +80,15 @@ It’s time to open [KStars][12], which is a desktop planetarium and also includ
|
||||
|
||||
![][13]
|
||||
|
||||
Follow the prompts to choose your home location (where you will be imaging from) and _Download Extra Data…_
|
||||
Follow the prompts to choose your home location (where you will be imaging from) and *Download Extra Data…*
|
||||
|
||||
![Setting your location][14]
|
||||
![][14]
|
||||
|
||||
![“Download Extra Data”][15]
|
||||
![][15]
|
||||
|
||||
![Choosing which catalogs to download][16]
|
||||
![][16]
|
||||
|
||||
This will allow you to install additional star, nebula, and galaxy catalogs. You don’t need them, but they don’t take up too much space and add to the experience of using KStars. Once you’ve completed this, hit _Done_ in the bottom right corner to continue.
|
||||
This will allow you to install additional star, nebula, and galaxy catalogs. You don’t need them, but they don’t take up too much space and add to the experience of using KStars. Once you’ve completed this, hit *Done* in the bottom right corner to continue.
|
||||
|
||||
### Getting familiar with KStars
|
||||
|
||||
@@ -116,49 +96,49 @@ Now is a good time to play around with the KStars interface. You are greeted wit
|
||||
|
||||
![][17]
|
||||
|
||||
This is the desktop planetarium which allows you to view the placement of objects in the night sky. Double-clicking an object selects it, and right clicking on an object gives you options like _Center & Track_ which will follow the object in the planetarium, compensating for [sidereal time][18]. _Show DSS Image_ shows a real [digitized sky survey][19] image of the selected object.
|
||||
This is the desktop planetarium which allows you to view the placement of objects in the night sky. Double-clicking an object selects it, and right clicking on an object gives you options like *Center & Track* which will follow the object in the planetarium, compensating for [sidereal time][18]. *Show DSS Image* shows a real [digitized sky survey][19] image of the selected object.
|
||||
|
||||
![][20]
|
||||
|
||||
Another essential feature is the _Set Time_ option in the toolbar. Clicking this will allow you to input a future (or past) time and then simulate the night sky as if that were the current date.
|
||||
Another essential feature is the *Set Time* option in the toolbar. Clicking this will allow you to input a future (or past) time and then simulate the night sky as if that were the current date.
|
||||
|
||||
![The Set Time button][21]
|
||||
![][21]
|
||||
|
||||
### Configuring capture equipment with Ekos
|
||||
|
||||
You’re familiar with the KStars layout and some basic functions, so it’s time to move on configuring your equipment using the [Ekos][22] observatory controller and automation tool. To open Ekos, click the observatory button in the toolbar or go to _Tools_ > _Ekos_.
|
||||
You’re familiar with the KStars layout and some basic functions, so it’s time to move on configuring your equipment using the [Ekos][22] observatory controller and automation tool. To open Ekos, click the observatory button in the toolbar or go to *Tools* > *Ekos*.
|
||||
|
||||
![The Ekos button on the toolbar][23]
|
||||
![][23]
|
||||
|
||||
You will see another setup wizard: the _Ekos Profile Wizard_. Click _Next_ to start the wizard.
|
||||
You will see another setup wizard: the *Ekos Profile Wizard*. Click *Next* to start the wizard.
|
||||
|
||||
![][24]
|
||||
|
||||
In this tutorial, you have all of our equipment connected directly to your computer. A future article we will cover using an INDI server installed on a remote computer to control our equipment, allowing you to connect over a network and not have to be in the same physical space as your gear. For now though, select _Equipment is attached to this device_.
|
||||
In this tutorial, you have all of our equipment connected directly to your computer. A future article we will cover using an INDI server installed on a remote computer to control our equipment, allowing you to connect over a network and not have to be in the same physical space as your gear. For now though, select *Equipment is attached to this device*.
|
||||
|
||||
![][25]
|
||||
|
||||
You are now asked to name your equipment profile. I usually name mine something like “Local Gear” to differentiate between profiles that are for remote gear, but name your profile what you wish. We will leave the button marked _Internal Guide_ checked and won’t select any additional services. Now click the _Create Profile & Select Devices_ button.
|
||||
You are now asked to name your equipment profile. I usually name mine something like “Local Gear” to differentiate between profiles that are for remote gear, but name your profile what you wish. We will leave the button marked *Internal Guide* checked and won’t select any additional services. Now click the *Create Profile & Select Devices* button.
|
||||
|
||||
![][26]
|
||||
|
||||
This next screen is where we can select your particular driver to use for each individual piece of equipment. This part will be specific to your setup depending on what gear you use. For this tutorial, I will select the drivers for my setup.
|
||||
|
||||
My mount, a [SkyWatcher EQM-35 Pro][27], uses the _EQMod Mount_ under _SkyWatcher_ in the menu (this driver is also compatible with all SkyWatcher equatorial mounts, including the [EQ6-R Pro][28] and the [EQ8-R Pro][29]). For my Sony a6000 imaging camera, I choose the _Sony DSLR_ under _DSLRs_ under the CCD category. Under _Guider_, I choose the _QHY CCD_ under _QHY_ for my Orion Starshoot (and any QHY5 series camera). That last driver we want to select will be under the Aux 1 category. We want to select _Astrometry_ from the drop-down window. This will enable the Astrometry plate-solver from within Ekos that will allow our telescope to automatically figure out where in the night sky it is pointed, saving us the time and hassle of doing a one, two, or three star calibration after setting up our mount.
|
||||
My mount, a [SkyWatcher EQM-35 Pro][27], uses the *EQMod Mount* under *SkyWatcher* in the menu (this driver is also compatible with all SkyWatcher equatorial mounts, including the [EQ6-R Pro][28] and the [EQ8-R Pro][29]). For my Sony a6000 imaging camera, I choose the *Sony DSLR* under *DSLRs* under the CCD category. Under *Guider*, I choose the *QHY CCD* under *QHY* for my Orion Starshoot (and any QHY5 series camera). That last driver we want to select will be under the Aux 1 category. We want to select *Astrometry* from the drop-down window. This will enable the Astrometry plate-solver from within Ekos that will allow our telescope to automatically figure out where in the night sky it is pointed, saving us the time and hassle of doing a one, two, or three star calibration after setting up our mount.
|
||||
|
||||
You selected your drivers. Now it’s time to configure your telescope. Add new telescope profiles by clicking on the + button in the lower right. This is essential for computing field-of-view measurements so you can tell what your images will look like when you open the shutter. Once you click the + button, you will be presented with a form where you can enter the specifications of your telescope and guide scope. For my imaging telescope, I will enter Celestron into the _Vendor_ field, SS-80 into the _Model_ field, I will leave the _Driver_ field as None, _Type_ field as Refractor, _Aperture_ as 80mm, and _Focal Length_ as 400mm.
|
||||
You selected your drivers. Now it’s time to configure your telescope. Add new telescope profiles by clicking on the + button in the lower right. This is essential for computing field-of-view measurements so you can tell what your images will look like when you open the shutter. Once you click the + button, you will be presented with a form where you can enter the specifications of your telescope and guide scope. For my imaging telescope, I will enter Celestron into the *Vendor* field, SS-80 into the *Model* field, I will leave the *Driver* field as None, *Type* field as Refractor, *Aperture* as 80mm, and *Focal Length* as 400mm.
|
||||
|
||||
![][30]
|
||||
|
||||
After you enter the data, hit the _Save_ button. You will see the data you just entered appear in the left window with an index number of 1 next to it. Now you can go about entering the specs for your guide scope following the steps above. Once you hit save here, the guide scope will also appear in the left window with an index number of 2. Once all of your scopes are entered, close this window. Now select your _Primary_ and _Guide_ telescopes from the drop-down window.
|
||||
After you enter the data, hit the *Save* button. You will see the data you just entered appear in the left window with an index number of 1 next to it. Now you can go about entering the specs for your guide scope following the steps above. Once you hit save here, the guide scope will also appear in the left window with an index number of 2. Once all of your scopes are entered, close this window. Now select your *Primary* and *Guide* telescopes from the drop-down window.
|
||||
|
||||
![][31]
|
||||
|
||||
After all that work, everything should be correctly configured! Click the _Close_ button and complete the final bit of setup.
|
||||
After all that work, everything should be correctly configured! Click the *Close* button and complete the final bit of setup.
|
||||
|
||||
### Starting your capture equipment
|
||||
|
||||
This last step before you can start taking images should be easy enough. Click the _Play_ button under Start & Stop Ekos to connect to your equipment.
|
||||
This last step before you can start taking images should be easy enough. Click the *Play* button under Start & Stop Ekos to connect to your equipment.
|
||||
|
||||
![][32]
|
||||
|
||||
@@ -166,26 +146,23 @@ You will be greeted with a screen that looks similar to this:
|
||||
|
||||
![][33]
|
||||
|
||||
When you click on the tabs at the top of the screen, they should all show a green dot next to _Connection_, indicating that they are connected to your system. On my setup, the baud rate for my mount (the EQMod Mount tab) is set incorrectly, and so the mount is not connected.
|
||||
When you click on the tabs at the top of the screen, they should all show a green dot next to *Connection*, indicating that they are connected to your system. On my setup, the baud rate for my mount (the EQMod Mount tab) is set incorrectly, and so the mount is not connected.
|
||||
|
||||
![][34]
|
||||
|
||||
This is an easy fix; click on the _EQMod Mount_ tab, then the _Connection_ sub-tab, and then change the baud rate from 9600 to 115200. Now is a good time to ensure the serial port under _Ports_ is the correct serial port for your mount. You can check which port the system has mounted your device on by running the command:
|
||||
```
|
||||
This is an easy fix; click on the *EQMod Mount* tab, then the *Connection* sub-tab, and then change the baud rate from 9600 to 115200. Now is a good time to ensure the serial port under *Ports* is the correct serial port for your mount. You can check which port the system has mounted your device on by running the command:
|
||||
|
||||
```
|
||||
|
||||
ls /dev
|
||||
|
||||
```
|
||||
| grep USB
|
||||
```
|
||||
|
||||
You should see _ttyUSB0_. If there is more than one USB-serial device plugged in at a time, you will see more than one ttyUSB port, with an incrementing following number. To figure out which port is correct. unplug your mount and run the command again.
|
||||
You should see *ttyUSB0*. If there is more than one USB-serial device plugged in at a time, you will see more than one ttyUSB port, with an incrementing following number. To figure out which port is correct. unplug your mount and run the command again.
|
||||
|
||||
Now click on the _Main Control_ sub-tab, click _Connect_ again, and wait for the mount to connect. It might take a few seconds, be patient and it should connect.
|
||||
Now click on the *Main Control* sub-tab, click *Connect* again, and wait for the mount to connect. It might take a few seconds, be patient and it should connect.
|
||||
|
||||
The last thing to do is set the sensor and pixel size parameters for my camera. Under the _Sony DSLR Alpha-A6000 (Control)_ tab, select the _Image Info_ sub-tab. This is where you can enter your sensor specifications; if you don’t know them, a quick search on the internet will bring you your sensor’s maximum resolution as well as pixel pitch. Enter this data into the right-side boxes, then press the _Set_ button to load them into the left boxes and save them into memory. Hit the _Close_ button when you are done.
|
||||
The last thing to do is set the sensor and pixel size parameters for my camera. Under the *Sony DSLR Alpha-A6000 (Control)* tab, select the *Image Info* sub-tab. This is where you can enter your sensor specifications; if you don’t know them, a quick search on the internet will bring you your sensor’s maximum resolution as well as pixel pitch. Enter this data into the right-side boxes, then press the *Set* button to load them into the left boxes and save them into memory. Hit the *Close* button when you are done.
|
||||
|
||||
![][35]
|
||||
|
||||
@@ -198,14 +175,14 @@ Your equipment is ready to use. In the next article, you will learn how to captu
|
||||
via: https://fedoramagazine.org/astrophotography-with-fedora-astronomy-lab-setting-up/
|
||||
|
||||
作者:[Geoffrey Marr][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/coremodule/
|
||||
[b]: https://github.com/lujun9972
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2021/02/astrophotography-setup-2-816x345.jpg
|
||||
[2]: https://fedoramagazine.org/wp-content/uploads/2020/11/IMG_4151-768x1024.jpg
|
||||
[3]: https://labs.fedoraproject.org/en/astronomy/
|
||||
|
||||
@@ -42,7 +42,7 @@ nvme_core.default_ps_max_latency_us=0
|
||||
|
||||
In the end I upgraded my main workstation so I could repurpose its existing Samsung EVO 960 for the HoneyComb which worked much better.
|
||||
|
||||
After some fidgeting I was able to install Fedora but it became apparent that the integrated network ports still don’t work with the mainline kernel. The NXP tech is great but requires a custom kernel build and tooling. Some earlier blogs got around this with a USB->RJ45 Ethernet adapter which works fine. Hopefully network support will be mainlined soon, but for now I snagged a kernel SRPM from the helpful engineers on Discord. With the custom kernel the 1Gbe NIC worked fine, but it turns out the SFP+ ports need more configuration. They won’t be recognized as interfaces until you use NXP’s _restool_ utility to map ports to their usage. In this case just a runtime mapping of _dmap -> dni_ was required. This is NXP’s way of mapping a MAC to a network interface via IOCTL commands. The restool binary isn’t provided either and must be built from source. It then layers on management scripts which use cheeky $arg0 references for redirection to call the restool binary with complex arguments.
|
||||
After some fidgeting I was able to install Fedora but it became apparent that the integrated network ports still don’t work with the mainline kernel. The NXP tech is great but requires a custom kernel build and tooling. Some earlier blogs got around this with a USB->RJ45 Ethernet adapter which works fine. Hopefully network support will be mainlined soon, but for now I snagged a kernel SRPM from the helpful engineers on Discord. With the custom kernel the 1Gbe NIC worked fine, but it turns out the SFP+ ports need more configuration. They won’t be recognized as interfaces until you use NXP’s _restool_ utility to map ports to their usage. In this case just a runtime mapping of _dmap -> dni_ was required. This is NXP’s way of mapping a MAC to a network interface via IOCTL commands. The restool binary isn’t provided either and must be built from source. It then layers on management scripts which use cheeky $arg0 references for redirection to call the restool binary with complex arguments.
|
||||
|
||||
Since I was starting to accumulate quite a few custom packages it was apparent that a COPR repo was needed to simplify this for Fedora. If you’re not familiar with COPR I think it’s one of Fedora’s finest resources. This repo contains the uefi build (currently failing build), 5.10.5 kernel built with network support, and the restool binary with supporting scripts. I also added a oneshot systemd unit to enable the SFP+ ports on boot:
|
||||
```
|
||||
|
||||
@@ -85,8 +85,8 @@ Describe the newly created namespace:
|
||||
```
|
||||
[root@master ~]# kubectl describe namespace test
|
||||
Name: test
|
||||
Labels: <none>
|
||||
Annotations: <none>
|
||||
Labels: <none>
|
||||
Annotations: <none>
|
||||
Status: Active
|
||||
No resource quota.
|
||||
No LimitRange resource.
|
||||
@@ -233,8 +233,8 @@ Verify the Roles:
|
||||
```
|
||||
$ kubectl describe roles -n test
|
||||
Name: list-deployments
|
||||
Labels: <none>
|
||||
Annotations: <none>
|
||||
Labels: <none>
|
||||
Annotations: <none>
|
||||
PolicyRule:
|
||||
Resources Non-Resource URLs Resource Names Verbs
|
||||
--------- ----------------- -------------- -----
|
||||
|
||||
@@ -1,57 +1,51 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Draw Mandelbrot fractals with GIMP scripting)
|
||||
[#]: via: (https://opensource.com/article/21/2/gimp-mandelbrot)
|
||||
[#]: author: (Cristiano L. Fontana https://opensource.com/users/cristianofontana)
|
||||
[#]: subject: "Draw Mandelbrot fractals with GIMP scripting"
|
||||
[#]: via: "https://opensource.com/article/21/2/gimp-mandelbrot"
|
||||
[#]: author: "Cristiano L. Fontana https://opensource.com/users/cristianofontana"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Draw Mandelbrot fractals with GIMP scripting
|
||||
======
|
||||
Create complex mathematical images with GIMP's Script-Fu language.
|
||||
|
||||
![Painting art on a computer screen][1]
|
||||
|
||||
Image by: Opensource.com
|
||||
|
||||
The GNU Image Manipulation Program ([GIMP][2]) is my go-to solution for image editing. Its toolset is very powerful and convenient, except for doing [fractals][3], which is one thing you cannot draw by hand easily. These are fascinating mathematical constructs that have the characteristic of being [self-similar][4]. In other words, if they are magnified in some areas, they will look remarkably similar to the unmagnified picture. Besides being interesting, they also make very pretty pictures!
|
||||
|
||||
![Portion of a Mandelbrot fractal using GIMPs Coldfire palette][5]
|
||||
![Rotated and magnified portion of the Mandelbrot set using Firecode][5]
|
||||
|
||||
Portion of a Mandelbrot fractal using GIMP's Coldfire palette (Cristiano Fontana, [CC BY-SA 4.0][6])
|
||||
GIMP can be automated with [Script-Fu][6] to do [batch processing of images][7] or create complicated procedures that are not practical to do by hand; drawing fractals falls in the latter category. This tutorial will show how to draw a representation of the [Mandelbrot fractal][8] using GIMP and Script-Fu.
|
||||
|
||||
GIMP can be automated with [Script-Fu][7] to do [batch processing of images][8] or create complicated procedures that are not practical to do by hand; drawing fractals falls in the latter category. This tutorial will show how to draw a representation of the [Mandelbrot fractal][9] using GIMP and Script-Fu.
|
||||
![Mandelbrot set drawn using GIMP's Firecode palette][9]
|
||||
|
||||
![Mandelbrot set drawn using GIMP's Firecode palette][10]
|
||||
|
||||
Portion of a Mandelbrot fractal using GIMP's Firecode palette. (Cristiano Fontana, [CC BY-SA 4.0][6])
|
||||
|
||||
![Rotated and magnified portion of the Mandelbrot set using Firecode.][11]
|
||||
|
||||
Rotated and magnified portion of the Mandelbrot set using the Firecode palette. (Cristiano Fontana, [CC BY-SA 4.0][6])
|
||||
![Rotated and magnified portion of the Mandelbrot set using Firecode.][10]
|
||||
|
||||
In this tutorial, you will write a script that creates a layer in an image and draws a representation of the Mandelbrot set with a colored environment around it.
|
||||
|
||||
### What is the Mandelbrot set?
|
||||
|
||||
Do not panic! I will not go into too much detail here. For the more math-savvy, the Mandelbrot set is defined as the set of [complex numbers][12] _a_ for which the succession
|
||||
Do not panic! I will not go into too much detail here. For the more math-savvy, the Mandelbrot set is defined as the set of [complex numbers][11] *a* for which the succession
|
||||
|
||||
_zn+1 = zn2 + a_
|
||||
zn+1 = zn2 + a
|
||||
|
||||
does not diverge when starting from _z₀ = 0_.
|
||||
does not diverge when starting from *z₀ = 0*.
|
||||
|
||||
In reality, the Mandelbrot set is the fancy-looking black blob in the pictures; the nice-looking colors are outside the set. They represent how many iterations are required for the magnitude of the succession of numbers to pass a threshold value. In other words, the color scale shows how many steps are required for the succession to pass an upper-limit value.
|
||||
|
||||
### GIMP's Script-Fu
|
||||
|
||||
[Script-Fu][7] is the scripting language built into GIMP. It is an implementation of the [Scheme programming language][13].
|
||||
[Script-Fu][12] is the scripting language built into GIMP. It is an implementation of the [Scheme programming language][13].
|
||||
|
||||
If you want to get more acquainted with Scheme, GIMP's documentation offers an [in-depth tutorial][14]. I also wrote an article about [batch processing images][8] using Script-Fu. Finally, the Help menu offers a Procedure Browser with very extensive documentation with all of Script-Fu's functions described in detail.
|
||||
If you want to get more acquainted with Scheme, GIMP's documentation offers an [in-depth tutorial][14]. I also wrote an article about [batch processing images][15] using Script-Fu. Finally, the Help menu offers a Procedure Browser with very extensive documentation with all of Script-Fu's functions described in detail.
|
||||
|
||||
![GIMP Procedure Browser][15]
|
||||
|
||||
(Cristiano Fontana, [CC BY-SA 4.0][6])
|
||||
|
||||
Scheme is a Lisp-like language, so a major characteristic is that it uses a [prefix notation][16] and a [lot of parentheses][17]. Functions and operators are applied to a list of operands by prefixing them:
|
||||
![GIMP Procedure Browser][16]
|
||||
|
||||
Scheme is a Lisp-like language, so a major characteristic is that it uses a [prefix notation][17] and a [lot of parentheses][18]. Functions and operators are applied to a list of operands by prefixing them:
|
||||
|
||||
```
|
||||
(function-name operand operand ...)
|
||||
@@ -67,7 +61,6 @@ Scheme is a Lisp-like language, so a major characteristic is that it uses a [pre
|
||||
|
||||
You can write your first script and save it to the **Scripts** folder found in the preferences window under **Folders → Scripts**. Mine is at `$HOME/.config/GIMP/2.10/scripts`. Write a file called `mandelbrot.scm` with:
|
||||
|
||||
|
||||
```
|
||||
; Complex numbers implementation
|
||||
(define (make-rectangular x y) (cons x y))
|
||||
@@ -111,17 +104,17 @@ You can write your first script and save it to the **Scripts** folder found in t
|
||||
(define bytes-per-pixel (car (gimp-drawable-bpp drawable)))
|
||||
|
||||
; Fractal drawing section.
|
||||
; Code from: <https://rosettacode.org/wiki/Mandelbrot\_set\#Racket>
|
||||
; Code from: https://rosettacode.org/wiki/Mandelbrot_set#Racket
|
||||
(define (iterations a z i)
|
||||
(let ((z′ (add-c (mul-c z z) a)))
|
||||
(if (or (= i num-colors) (> (magnitude z′) threshold))
|
||||
(if (or (= i num-colors) (> (magnitude z′) threshold))
|
||||
i
|
||||
(iterations a z′ (+ i 1)))))
|
||||
|
||||
(define (iter->color i)
|
||||
(if (>= i num-colors)
|
||||
(list->vector '(0 0 0))
|
||||
(list->vector (vector-ref colors i))))
|
||||
(define (iter->color i)
|
||||
(if (>= i num-colors)
|
||||
(list->vector '(0 0 0))
|
||||
(list->vector (vector-ref colors i))))
|
||||
|
||||
(define z0 (make-rectangular 0 0))
|
||||
|
||||
@@ -130,10 +123,10 @@ You can write your first script and save it to the **Scripts** folder found in t
|
||||
(real-y (- (* domain-height (/ y height)) offset-y))
|
||||
(a (make-rectangular real-x real-y))
|
||||
(i (iterations a z0 0))
|
||||
(color (iter->color i)))
|
||||
(cond ((and (< x end-x) (< y end-y)) (gimp-drawable-set-pixel drawable x y bytes-per-pixel color)
|
||||
(color (iter->color i)))
|
||||
(cond ((and (< x end-x) (< y end-y)) (gimp-drawable-set-pixel drawable x y bytes-per-pixel color)
|
||||
(loop (+ x 1) end-x y end-y))
|
||||
((and (>= x end-x) (< y end-y)) (gimp-progress-update (/ y end-y))
|
||||
((and (>= x end-x) (< y end-y)) (gimp-progress-update (/ y end-y))
|
||||
(loop 0 end-x (+ y 1) end-y)))))
|
||||
(loop 0 width 0 height)
|
||||
|
||||
@@ -161,15 +154,14 @@ You can write your first script and save it to the **Scripts** folder found in t
|
||||
SF-ADJUSTMENT "X offset" '(2.25 -20 20 0.1 1 4 0)
|
||||
SF-ADJUSTMENT "Y offset" '(1.50 -20 20 0.1 1 4 0)
|
||||
)
|
||||
(script-fu-menu-register "script-fu-mandelbrot" "<Image>/Layer/")
|
||||
(script-fu-menu-register "script-fu-mandelbrot" "<Image>/Layer/")
|
||||
```
|
||||
|
||||
I will go through the script to show you what it does.
|
||||
|
||||
### Get ready to draw the fractal
|
||||
|
||||
Since this image is all about complex numbers, I wrote a quick and dirty implementation of complex numbers in Script-Fu. I defined the complex numbers as [pairs][18] of real numbers. Then I added the few functions needed for the script. I used [Racket's documentation][19] as inspiration for function names and roles:
|
||||
|
||||
Since this image is all about complex numbers, I wrote a quick and dirty implementation of complex numbers in Script-Fu. I defined the complex numbers as [pairs][19] of real numbers. Then I added the few functions needed for the script. I used [Racket's documentation][20] as inspiration for function names and roles:
|
||||
|
||||
```
|
||||
(define (make-rectangular x y) (cons x y))
|
||||
@@ -198,7 +190,6 @@ Since this image is all about complex numbers, I wrote a quick and dirty impleme
|
||||
|
||||
The new function is called `script-fu-mandelbrot`. The best practice for writing a new function is to call it `script-fu-something` so that it can be identified in the Procedure Browser easily. The function requires a few parameters: an `image` to which it will add a layer with the fractal, the `palette-name` identifying the color palette to be used, the `threshold` value to stop the iteration, the `domain-width` and `domain-height` that identify the image boundaries, and the `offset-x` and `offset-y` to center the image to the desired feature. The script also needs some other parameters that it can deduce from the GIMP interface:
|
||||
|
||||
|
||||
```
|
||||
(define (script-fu-mandelbrot image palette-name threshold domain-width domain-height offset-x offset-y)
|
||||
(define num-colors (car (gimp-palette-get-info palette-name)))
|
||||
@@ -212,7 +203,6 @@ The new function is called `script-fu-mandelbrot`. The best practice for writing
|
||||
|
||||
Then it creates a new layer and identifies it as the script's `drawable`. A "drawable" is the element you want to draw on:
|
||||
|
||||
|
||||
```
|
||||
(define new-layer (car (gimp-layer-new image
|
||||
width height
|
||||
@@ -226,27 +216,25 @@ Then it creates a new layer and identifies it as the script's `drawable`. A "dra
|
||||
(define bytes-per-pixel (car (gimp-drawable-bpp drawable)))
|
||||
```
|
||||
|
||||
For the code determining the pixels' color, I used the [Racket][20] example on the [Rosetta Code][21] website. It is not the most optimized algorithm, but it is simple to understand. Even a non-mathematician like me can understand it. The `iterations` function determines how many steps the succession requires to pass the threshold value. To cap the iterations, I am using the number of colors in the palette. In other words, if the threshold is too high or the succession does not grow, the calculation stops at the `num-colors` value. The `iter->color` function transforms the number of iterations into a color using the provided palette. If the iteration number is equal to `num-colors`, it uses black because this means that the succession is probably bound and that pixel is in the Mandelbrot set:
|
||||
|
||||
For the code determining the pixels' color, I used the [Racket][21] example on the [Rosetta Code][22] website. It is not the most optimized algorithm, but it is simple to understand. Even a non-mathematician like me can understand it. The `iterations` function determines how many steps the succession requires to pass the threshold value. To cap the iterations, I am using the number of colors in the palette. In other words, if the threshold is too high or the succession does not grow, the calculation stops at the `num-colors` value. The `iter->color` function transforms the number of iterations into a color using the provided palette. If the iteration number is equal to `num-colors`, it uses black because this means that the succession is probably bound and that pixel is in the Mandelbrot set:
|
||||
|
||||
```
|
||||
; Fractal drawing section.
|
||||
; Code from: <https://rosettacode.org/wiki/Mandelbrot\_set\#Racket>
|
||||
; Code from: https://rosettacode.org/wiki/Mandelbrot_set#Racket
|
||||
(define (iterations a z i)
|
||||
(let ((z′ (add-c (mul-c z z) a)))
|
||||
(if (or (= i num-colors) (> (magnitude z′) threshold))
|
||||
(if (or (= i num-colors) (> (magnitude z′) threshold))
|
||||
i
|
||||
(iterations a z′ (+ i 1)))))
|
||||
|
||||
(define (iter->color i)
|
||||
(if (>= i num-colors)
|
||||
(list->vector '(0 0 0))
|
||||
(list->vector (vector-ref colors i))))
|
||||
(define (iter->color i)
|
||||
(if (>= i num-colors)
|
||||
(list->vector '(0 0 0))
|
||||
(list->vector (vector-ref colors i))))
|
||||
```
|
||||
|
||||
Because I have the feeling that Scheme users do not like to use loops, I implemented the function looping over the pixels as a recursive function. The `loop` function reads the starting coordinates and their upper boundaries. At each pixel, it defines some temporary variables with the `let*` function: `real-x` and `real-y` are the real coordinates of the pixel in the complex plane, according to the parameters; the `a` variable is the starting point for the succession; the `i` is the number of iterations; and finally `color` is the pixel color. Each pixel is colored with the `gimp-drawable-set-pixel` function that is an internal GIMP procedure. The peculiarity is that it is not undoable, and it does not trigger the image to refresh. Therefore, the image will not be updated during the operation. To play nice with the user, at the end of each row of pixels, it calls the `gimp-progress-update` function, which updates a progress bar in the user interface:
|
||||
|
||||
|
||||
```
|
||||
(define z0 (make-rectangular 0 0))
|
||||
|
||||
@@ -255,17 +243,16 @@ Because I have the feeling that Scheme users do not like to use loops, I impleme
|
||||
(real-y (- (* domain-height (/ y height)) offset-y))
|
||||
(a (make-rectangular real-x real-y))
|
||||
(i (iterations a z0 0))
|
||||
(color (iter->color i)))
|
||||
(cond ((and (< x end-x) (< y end-y)) (gimp-drawable-set-pixel drawable x y bytes-per-pixel color)
|
||||
(color (iter->color i)))
|
||||
(cond ((and (< x end-x) (< y end-y)) (gimp-drawable-set-pixel drawable x y bytes-per-pixel color)
|
||||
(loop (+ x 1) end-x y end-y))
|
||||
((and (>= x end-x) (< y end-y)) (gimp-progress-update (/ y end-y))
|
||||
((and (>= x end-x) (< y end-y)) (gimp-progress-update (/ y end-y))
|
||||
(loop 0 end-x (+ y 1) end-y)))))
|
||||
(loop 0 width 0 height)
|
||||
```
|
||||
|
||||
At the calculation's end, the function needs to inform GIMP that it modified the `drawable`, and it should refresh the interface because the image is not "automagically" updated during the script's execution:
|
||||
|
||||
|
||||
```
|
||||
(gimp-drawable-update drawable 0 0 width height)
|
||||
(gimp-displays-flush)
|
||||
@@ -275,7 +262,6 @@ At the calculation's end, the function needs to inform GIMP that it modified the
|
||||
|
||||
To use the `script-fu-mandelbrot` function in the graphical user interface (GUI), the script needs to inform GIMP. The `script-fu-register` function informs GIMP about the parameters required by the script and provides some documentation:
|
||||
|
||||
|
||||
```
|
||||
(script-fu-register
|
||||
"script-fu-mandelbrot" ; Function name
|
||||
@@ -300,71 +286,69 @@ To use the `script-fu-mandelbrot` function in the graphical user interface (GUI)
|
||||
|
||||
Then the script tells GIMP to put the new function in the Layer menu with the label "Create a Mandelbrot layer":
|
||||
|
||||
|
||||
```
|
||||
`(script-fu-menu-register "script-fu-mandelbrot" "<Image>/Layer/")`
|
||||
(script-fu-menu-register "script-fu-mandelbrot" "<Image>/Layer/")
|
||||
```
|
||||
|
||||
Having registered the function, you can visualize it in the Procedure Browser.
|
||||
|
||||
![script-fu-mandelbrot function][22]
|
||||
|
||||
(Cristiano Fontana, [CC BY-SA 4.0][6])
|
||||
![script-fu-mandelbrot function][23]
|
||||
|
||||
### Run the script
|
||||
|
||||
Now that the function is ready and registered, you can draw the Mandelbrot fractal! First, create a square image and run the script from the Layers menu.
|
||||
|
||||
![script running][23]
|
||||
|
||||
(Cristiano Fontana, [CC BY-SA 4.0][6])
|
||||
![script running][24]
|
||||
|
||||
The default values are a good starting set to obtain the following image. The first time you run the script, create a very small image (e.g., 60x60 pixels) because this implementation is slow! It took several hours for my computer to create the following image in full 1920x1920 pixels. As I mentioned earlier, this is not the most optimized algorithm; rather, it was the easiest for me to understand.
|
||||
|
||||
![Mandelbrot set drawn using GIMP's Firecode palette][10]
|
||||
|
||||
Portion of a Mandelbrot fractal using GIMP's Firecode palette. (Cristiano Fontana, [CC BY-SA 4.0][6])
|
||||
![Mandelbrot set drawn using GIMP's Firecode palette][25]
|
||||
|
||||
### Learn more
|
||||
|
||||
This tutorial showed how to use GIMP's built-in scripting features to draw an image created with an algorithm. These images show GIMP's powerful set of tools that can be used for artistic applications and mathematical images.
|
||||
|
||||
If you want to move forward, I suggest you look at the official documentation and its [tutorial][14]. As an exercise, try modifying this script to draw a [Julia set][24], and please share the resulting image in the comments.
|
||||
If you want to move forward, I suggest you look at the official documentation and its [tutorial][26]. As an exercise, try modifying this script to draw a [Julia set][27], and please share the resulting image in the comments.
|
||||
|
||||
Image by: Rotated and magnified portion of the Mandelbrot set using Firecode. (Cristiano Fontana, CC BY-SA 4.0)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/2/gimp-mandelbrot
|
||||
|
||||
作者:[Cristiano L. Fontana][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/cristianofontana
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/painting_computer_screen_art_design_creative.png?itok=LVAeQx3_ (Painting art on a computer screen)
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/painting_computer_screen_art_design_creative.png
|
||||
[2]: https://www.gimp.org/
|
||||
[3]: https://en.wikipedia.org/wiki/Fractal
|
||||
[4]: https://en.wikipedia.org/wiki/Self-similarity
|
||||
[5]: https://opensource.com/sites/default/files/uploads/mandelbrot_portion.png (Portion of a Mandelbrot fractal using GIMPs Coldfire palette)
|
||||
[6]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[7]: https://docs.gimp.org/en/gimp-concepts-script-fu.html
|
||||
[8]: https://opensource.com/article/21/1/gimp-scripting
|
||||
[9]: https://en.wikipedia.org/wiki/Mandelbrot_set
|
||||
[10]: https://opensource.com/sites/default/files/uploads/mandelbrot.png (Mandelbrot set drawn using GIMP's Firecode palette)
|
||||
[11]: https://opensource.com/sites/default/files/uploads/mandelbrot_portion2.png (Rotated and magnified portion of the Mandelbrot set using Firecode.)
|
||||
[12]: https://en.wikipedia.org/wiki/Complex_number
|
||||
[5]: https://opensource.com/sites/default/files/uploads/mandelbrot_portion.png
|
||||
[6]: https://docs.gimp.org/en/gimp-concepts-script-fu.html
|
||||
[7]: https://opensource.com/article/21/1/gimp-scripting
|
||||
[8]: https://en.wikipedia.org/wiki/Mandelbrot_set
|
||||
[9]: https://opensource.com/sites/default/files/uploads/mandelbrot.png
|
||||
[10]: https://opensource.com/sites/default/files/uploads/mandelbrot_portion2.png
|
||||
[11]: https://en.wikipedia.org/wiki/Complex_number
|
||||
[12]: https://docs.gimp.org/en/gimp-concepts-script-fu.html
|
||||
[13]: https://en.wikipedia.org/wiki/Scheme_(programming_language)
|
||||
[14]: https://docs.gimp.org/en/gimp-using-script-fu-tutorial.html
|
||||
[15]: https://opensource.com/sites/default/files/uploads/procedure_browser_0.png (GIMP Procedure Browser)
|
||||
[16]: https://en.wikipedia.org/wiki/Polish_notation
|
||||
[17]: https://xkcd.com/297/
|
||||
[18]: https://www.gnu.org/software/guile/manual/html_node/Pairs.html
|
||||
[19]: https://docs.racket-lang.org/reference/generic-numbers.html?q=make-rectangular#%28part._.Complex_.Numbers%29
|
||||
[20]: https://racket-lang.org/
|
||||
[21]: https://rosettacode.org/wiki/Mandelbrot_set#Racket
|
||||
[22]: https://opensource.com/sites/default/files/uploads/mandelbrot_documentation.png (script-fu-mandelbrot function)
|
||||
[23]: https://opensource.com/sites/default/files/uploads/script_working.png (script running)
|
||||
[24]: https://en.wikipedia.org/wiki/Julia_set
|
||||
[15]: https://opensource.com/article/21/1/gimp-scripting
|
||||
[16]: https://opensource.com/sites/default/files/uploads/procedure_browser_0.png
|
||||
[17]: https://en.wikipedia.org/wiki/Polish_notation
|
||||
[18]: https://xkcd.com/297/
|
||||
[19]: https://www.gnu.org/software/guile/manual/html_node/Pairs.html
|
||||
[20]: https://docs.racket-lang.org/reference/generic-numbers.html?q=make-rectangular#%28part._.Complex_.Numbers%29
|
||||
[21]: https://racket-lang.org/
|
||||
[22]: https://rosettacode.org/wiki/Mandelbrot_set#Racket
|
||||
[23]: https://opensource.com/sites/default/files/uploads/mandelbrot_documentation.png
|
||||
[24]: https://opensource.com/sites/default/files/uploads/script_working.png
|
||||
[25]: https://opensource.com/sites/default/files/uploads/mandelbrot.png
|
||||
[26]: https://docs.gimp.org/en/gimp-using-script-fu-tutorial.html
|
||||
[27]: https://en.wikipedia.org/wiki/Julia_set
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (A step-by-step guide to Knative eventing)
|
||||
[#]: via: (https://opensource.com/article/21/2/knative-eventing)
|
||||
[#]: author: (Jessica Cherry https://opensource.com/users/cherrybomb)
|
||||
[#]: subject: "A step-by-step guide to Knative eventing"
|
||||
[#]: via: "https://opensource.com/article/21/2/knative-eventing"
|
||||
[#]: author: "Jessica Cherry https://opensource.com/users/cherrybomb"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
A step-by-step guide to Knative eventing
|
||||
======
|
||||
Knative eventing is a way to create, send, and verify events in your
|
||||
cloud-native environment.
|
||||
Knative eventing is a way to create, send, and verify events in your cloud-native environment.
|
||||
|
||||
![Computer laptop in space][1]
|
||||
|
||||
Image by: Opensource.com
|
||||
|
||||
In a previous article, I covered [how to create a small app with Knative][2], which is an open source project that adds components to [Kubernetes][3] for deploying, running, and managing [serverless, cloud-native][4] applications. In this article, I'll explain Knative eventing, a way to create, send, and verify events in your cloud-native environment.
|
||||
|
||||
Events can be generated from many sources in your environment, and they can be confusing to manage or define. Since Knative follows the [CloudEvents][5] specification, it allows you to have one common abstraction point for your environment, where the events are defined to one specification.
|
||||
@@ -25,7 +27,6 @@ This walkthrough uses [Minikube][7] with Kubernetes 1.19.0. It also makes some c
|
||||
|
||||
**Minikube pre-configuration commands:**
|
||||
|
||||
|
||||
```
|
||||
$ minikube config set kubernetes-version v1.19.0
|
||||
$ minikube config set memory 4000
|
||||
@@ -34,7 +35,6 @@ $ minikube config set cpus 4
|
||||
|
||||
Before starting Minikube, run the following commands to make sure your configuration stays and start Minikube:
|
||||
|
||||
|
||||
```
|
||||
$ minikube delete
|
||||
$ minikube start
|
||||
@@ -44,9 +44,8 @@ $ minikube start
|
||||
|
||||
Install the Knative eventing custom resource definitions (CRDs) using kubectl. The following shows the command and a snippet of the output:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl apply --filename <https://github.com/knative/eventing/releases/download/v0.20.0/eventing-crds.yaml>
|
||||
$ kubectl apply --filename https://github.com/knative/eventing/releases/download/v0.20.0/eventing-crds.yaml
|
||||
|
||||
customresourcedefinition.apiextensions.k8s.io/apiserversources.sources.knative.dev created
|
||||
customresourcedefinition.apiextensions.k8s.io/brokers.eventing.knative.dev created
|
||||
@@ -56,9 +55,8 @@ customresourcedefinition.apiextensions.k8s.io/triggers.eventing.knative.dev crea
|
||||
|
||||
Next, install the core components using kubectl:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl apply --filename <https://github.com/knative/eventing/releases/download/v0.20.0/eventing-core.yaml>
|
||||
$ kubectl apply --filename https://github.com/knative/eventing/releases/download/v0.20.0/eventing-core.yaml
|
||||
namespace/knative-eventing created
|
||||
serviceaccount/eventing-controller created
|
||||
clusterrolebinding.rbac.authorization.k8s.io/eventing-controller created
|
||||
@@ -66,23 +64,20 @@ clusterrolebinding.rbac.authorization.k8s.io/eventing-controller created
|
||||
|
||||
Since you're running a standalone version of the Knative eventing service, you must install the in-memory channel to pass events. Using kubectl, run:
|
||||
|
||||
|
||||
```
|
||||
`$ kubectl apply --filename https://github.com/knative/eventing/releases/download/v0.20.0/in-memory-channel.yaml`
|
||||
$ kubectl apply --filename https://github.com/knative/eventing/releases/download/v0.20.0/in-memory-channel.yaml
|
||||
```
|
||||
|
||||
Install the broker, which utilizes the channels and runs the event routing:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl apply --filename <https://github.com/knative/eventing/releases/download/v0.20.0/mt-channel-broker.yaml>
|
||||
$ kubectl apply --filename https://github.com/knative/eventing/releases/download/v0.20.0/mt-channel-broker.yaml
|
||||
clusterrole.rbac.authorization.k8s.io/knative-eventing-mt-channel-broker-controller created
|
||||
clusterrole.rbac.authorization.k8s.io/knative-eventing-mt-broker-filter created
|
||||
```
|
||||
|
||||
Next, create a namespace and add a small broker to it; this broker routes events to triggers. Create your namespace using kubectl:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl create namespace eventing-test
|
||||
namespace/eventing-test created
|
||||
@@ -90,7 +85,6 @@ namespace/eventing-test created
|
||||
|
||||
Now create a small broker named `default` in your namespace. The following is the YAML from my **broker.yaml** file (which can be found in my GitHub repository):
|
||||
|
||||
|
||||
```
|
||||
apiVersion: eventing.knative.dev/v1
|
||||
kind: broker
|
||||
@@ -101,7 +95,6 @@ metadata:
|
||||
|
||||
Then apply your broker file using kubectl:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl create -f broker.yaml
|
||||
broker.eventing.knative.dev/default created
|
||||
@@ -109,11 +102,10 @@ $ kubectl create -f broker.yaml
|
||||
|
||||
Verify that everything is up and running (you should see the confirmation output) after you run the command:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl -n eventing-test get broker default
|
||||
NAME URL AGE READY REASON
|
||||
default <http://broker-ingress.knative-eventing.svc.cluster.local/eventing-test/default> 3m6s True
|
||||
default http://broker-ingress.knative-eventing.svc.cluster.local/eventing-test/default 3m6s True
|
||||
```
|
||||
|
||||
You'll need this URL from the broker output later for sending events, so save it.
|
||||
@@ -126,7 +118,6 @@ First, you need to create event consumers. You'll create two consumers in this w
|
||||
|
||||
**The hello-display YAML code:**
|
||||
|
||||
|
||||
```
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -135,7 +126,7 @@ metadata:
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels: &labels
|
||||
matchLabels: &labels
|
||||
app: hello-display
|
||||
template:
|
||||
metadata:
|
||||
@@ -145,7 +136,7 @@ spec:
|
||||
- name: event-display
|
||||
image: gcr.io/knative-releases/knative.dev/eventing-contrib/cmd/event_display
|
||||
|
||||
\---
|
||||
---
|
||||
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
@@ -162,7 +153,6 @@ spec:
|
||||
|
||||
**The goodbye-display YAML code:**
|
||||
|
||||
|
||||
```
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -171,7 +161,7 @@ metadata:
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels: &labels
|
||||
matchLabels: &labels
|
||||
app: goodbye-display
|
||||
template:
|
||||
metadata:
|
||||
@@ -179,10 +169,10 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: event-display
|
||||
# Source code: <https://github.com/knative/eventing-contrib/tree/master/cmd/event\_display>
|
||||
# Source code: https://github.com/knative/eventing-contrib/tree/master/cmd/event_display
|
||||
image: gcr.io/knative-releases/knative.dev/eventing-contrib/cmd/event_display
|
||||
|
||||
\---
|
||||
---
|
||||
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
@@ -199,7 +189,6 @@ spec:
|
||||
|
||||
The differences in the YAML between the two consumers are in the `app` and `metadata name` sections. While both consumers are on the same ports, you can target one when generating an event. Create the consumers using kubectl:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl -n eventing-test apply -f hello-display.yaml
|
||||
deployment.apps/hello-display created
|
||||
@@ -212,7 +201,6 @@ service/goodbye-display created
|
||||
|
||||
Check to make sure the deployments are running after you've applied the YAML files:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl -n eventing-test get deployments hello-display goodbye-display
|
||||
NAME READY UP-TO-DATE AVAILABLE AGE
|
||||
@@ -226,7 +214,6 @@ Now, you need to create the triggers, which define the events the consumer recei
|
||||
|
||||
**The greeting-trigger.yaml code:**
|
||||
|
||||
|
||||
```
|
||||
apiVersion: eventing.knative.dev/v1
|
||||
kind: Trigger
|
||||
@@ -246,7 +233,6 @@ spec:
|
||||
|
||||
To create the first trigger, apply your YAML file:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl -n eventing-test apply -f greeting-trigger.yaml
|
||||
trigger.eventing.knative.dev/hello-display created
|
||||
@@ -256,7 +242,6 @@ Next, make the second trigger using **sendoff-trigger.yaml**. This sends anythin
|
||||
|
||||
**The sendoff-trigger.yaml code:**
|
||||
|
||||
|
||||
```
|
||||
apiVersion: eventing.knative.dev/v1
|
||||
kind: Trigger
|
||||
@@ -276,7 +261,6 @@ spec:
|
||||
|
||||
Next, apply your second trigger definition to the cluster:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl -n eventing-test apply -f sendoff-trigger.yaml
|
||||
trigger.eventing.knative.dev/goodbye-display created
|
||||
@@ -284,19 +268,17 @@ trigger.eventing.knative.dev/goodbye-display created
|
||||
|
||||
Confirm everything is correctly in place by getting your triggers from the cluster using kubectl:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl -n eventing-test get triggers
|
||||
NAME BROKER SUBSCRIBER_URI AGE READY
|
||||
goodbye-display default <http://goodbye-display.eventing-test.svc.cluster.local/> 24s True
|
||||
hello-display default <http://hello-display.eventing-test.svc.cluster.local/> 46s True
|
||||
NAME BROKER SUBSCRIBER_URI AGE READY
|
||||
goodbye-display default http://goodbye-display.eventing-test.svc.cluster.local/ 24s True
|
||||
hello-display default http://hello-display.eventing-test.svc.cluster.local/ 46s True
|
||||
```
|
||||
|
||||
### Create an event producer
|
||||
|
||||
Create a pod you can use to send events. This is a simple pod deployment with curl and SSH access for you to [send events using curl][8]. Because the broker can be accessed only from inside the cluster where Knative eventing is installed, the pod needs to be in the cluster; this is the only way to send events into the cluster. Use the **event-producer.yaml** file with this code:
|
||||
|
||||
|
||||
```
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
@@ -318,7 +300,6 @@ spec:
|
||||
|
||||
Next, deploy the pod by using kubectl:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl -n eventing-test apply -f event-producer.yaml
|
||||
pod/curl created
|
||||
@@ -326,7 +307,6 @@ pod/curl created
|
||||
|
||||
To verify, get the deployment and make sure the pod is up and running:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl get pods -n eventing-test
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
@@ -339,14 +319,12 @@ Since this article has been so configuration-heavy, I imagine you'll be happy to
|
||||
|
||||
Begin by logging into the pod:
|
||||
|
||||
|
||||
```
|
||||
`$ kubectl -n eventing-test attach curl -it`
|
||||
$ kubectl -n eventing-test attach curl -it
|
||||
```
|
||||
|
||||
Once logged in, you'll see output similar to:
|
||||
|
||||
|
||||
```
|
||||
Defaulting container name to curl.
|
||||
Use 'kubectl describe pod/curl -n eventing-test' to see all of the containers in this pod.
|
||||
@@ -356,9 +334,8 @@ If you don't see a command prompt, try pressing enter.
|
||||
|
||||
Now, generate an event using curl. This needs some extra definitions and requires the broker URL generated during the installation. This example sends a greeting to the broker:
|
||||
|
||||
|
||||
```
|
||||
curl -v "<http://broker-ingress.knative-eventing.svc.cluster.local/eventing-test/default>" \
|
||||
curl -v "http://broker-ingress.knative-eventing.svc.cluster.local/eventing-test/default" \
|
||||
-X POST \
|
||||
-H "Ce-Id: say-hello" \
|
||||
-H "Ce-Specversion: 1.0" \
|
||||
@@ -372,31 +349,29 @@ curl -v "<http://broker-ingress.knative-eventing.svc.cluster.local/eventing-test
|
||||
|
||||
When you run the command, this should be the output (and you should receive a [202 Accepted][10] response):
|
||||
|
||||
|
||||
```
|
||||
> POST /eventing-test/default HTTP/1.1
|
||||
> User-Agent: curl/7.35.0
|
||||
> Host: broker-ingress.knative-eventing.svc.cluster.local
|
||||
> Accept: */*
|
||||
> Ce-Id: say-hello
|
||||
> Ce-Specversion: 1.0
|
||||
> Ce-Type: greeting
|
||||
> Ce-Source: not-sendoff
|
||||
> Content-Type: application/json
|
||||
> Content-Length: 24
|
||||
>
|
||||
< HTTP/1.1 202 Accepted
|
||||
< Date: Sun, 24 Jan 2021 22:25:25 GMT
|
||||
< Content-Length: 0
|
||||
> POST /eventing-test/default HTTP/1.1
|
||||
> User-Agent: curl/7.35.0
|
||||
> Host: broker-ingress.knative-eventing.svc.cluster.local
|
||||
> Accept: */*
|
||||
> Ce-Id: say-hello
|
||||
> Ce-Specversion: 1.0
|
||||
> Ce-Type: greeting
|
||||
> Ce-Source: not-sendoff
|
||||
> Content-Type: application/json
|
||||
> Content-Length: 24
|
||||
>
|
||||
< HTTP/1.1 202 Accepted
|
||||
< Date: Sun, 24 Jan 2021 22:25:25 GMT
|
||||
< Content-Length: 0
|
||||
```
|
||||
|
||||
The 202 means the trigger sent it to the **hello-display** consumer (because of the definition.)
|
||||
|
||||
Next, send a second definition to the **goodbye-display** consumer with this new curl command:
|
||||
|
||||
|
||||
```
|
||||
curl -v "<http://broker-ingress.knative-eventing.svc.cluster.local/eventing-test/default>" \
|
||||
curl -v "http://broker-ingress.knative-eventing.svc.cluster.local/eventing-test/default" \
|
||||
-X POST \
|
||||
-H "Ce-Id: say-goodbye" \
|
||||
-H "Ce-Specversion: 1.0" \
|
||||
@@ -410,22 +385,21 @@ This time, it is a `sendoff` and not a greeting based on the previous setup sect
|
||||
|
||||
Your output should look like this, with another 202 returned:
|
||||
|
||||
|
||||
```
|
||||
> POST /eventing-test/default HTTP/1.1
|
||||
> User-Agent: curl/7.35.0
|
||||
> Host: broker-ingress.knative-eventing.svc.cluster.local
|
||||
> Accept: */*
|
||||
> Ce-Id: say-goodbye
|
||||
> Ce-Specversion: 1.0
|
||||
> Ce-Type: not-greeting
|
||||
> Ce-Source: sendoff
|
||||
> Content-Type: application/json
|
||||
> Content-Length: 26
|
||||
>
|
||||
< HTTP/1.1 202 Accepted
|
||||
< Date: Sun, 24 Jan 2021 22:33:00 GMT
|
||||
< Content-Length: 0
|
||||
> POST /eventing-test/default HTTP/1.1
|
||||
> User-Agent: curl/7.35.0
|
||||
> Host: broker-ingress.knative-eventing.svc.cluster.local
|
||||
> Accept: */*
|
||||
> Ce-Id: say-goodbye
|
||||
> Ce-Specversion: 1.0
|
||||
> Ce-Type: not-greeting
|
||||
> Ce-Source: sendoff
|
||||
> Content-Type: application/json
|
||||
> Content-Length: 26
|
||||
>
|
||||
< HTTP/1.1 202 Accepted
|
||||
< Date: Sun, 24 Jan 2021 22:33:00 GMT
|
||||
< Content-Length: 0
|
||||
```
|
||||
|
||||
Congratulations, you sent two events!
|
||||
@@ -438,14 +412,12 @@ Now that the events have been sent, how do you know that the correct consumers r
|
||||
|
||||
Start with the **hello-display** consumer::
|
||||
|
||||
|
||||
```
|
||||
`$ kubectl -n eventing-test logs -l app=hello-display --tail=100`
|
||||
$ kubectl -n eventing-test logs -l app=hello-display --tail=100
|
||||
```
|
||||
|
||||
There isn't much running in this example cluster, so you should see only one event:
|
||||
|
||||
|
||||
```
|
||||
☁️ cloudevents.Event
|
||||
Validation: valid
|
||||
@@ -467,7 +439,6 @@ You've confirmed the **hello-display** consumer received the event! Now check th
|
||||
|
||||
Start by running the same command but with **goodbye-display**:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl -n eventing-test logs -l app=goodbye-display --tail=100
|
||||
☁️ cloudevents.Event
|
||||
@@ -494,9 +465,8 @@ So you sent events to each consumer using curl, but what if you want to send an
|
||||
|
||||
Here is a curl example of a definition for sending an event to both consumers:
|
||||
|
||||
|
||||
```
|
||||
curl -v "<http://broker-ingress.knative-eventing.svc.cluster.local/eventing-test/default>" \
|
||||
curl -v "http://broker-ingress.knative-eventing.svc.cluster.local/eventing-test/default" \
|
||||
-X POST \
|
||||
-H "Ce-Id: say-hello-goodbye" \
|
||||
-H "Ce-Specversion: 1.0" \
|
||||
@@ -512,27 +482,25 @@ Here is sample output of what the events look like after they are sent.
|
||||
|
||||
**Output of the event being sent:**
|
||||
|
||||
|
||||
```
|
||||
> POST /eventing-test/default HTTP/1.1
|
||||
> User-Agent: curl/7.35.0
|
||||
> Host: broker-ingress.knative-eventing.svc.cluster.local
|
||||
> Accept: */*
|
||||
> Ce-Id: say-hello-goodbye
|
||||
> Ce-Specversion: 1.0
|
||||
> Ce-Type: greeting
|
||||
> Ce-Source: sendoff
|
||||
> Content-Type: application/json
|
||||
> Content-Length: 41
|
||||
>
|
||||
< HTTP/1.1 202 Accepted
|
||||
< Date: Sun, 24 Jan 2021 23:04:15 GMT
|
||||
< Content-Length: 0
|
||||
> POST /eventing-test/default HTTP/1.1
|
||||
> User-Agent: curl/7.35.0
|
||||
> Host: broker-ingress.knative-eventing.svc.cluster.local
|
||||
> Accept: */*
|
||||
> Ce-Id: say-hello-goodbye
|
||||
> Ce-Specversion: 1.0
|
||||
> Ce-Type: greeting
|
||||
> Ce-Source: sendoff
|
||||
> Content-Type: application/json
|
||||
> Content-Length: 41
|
||||
>
|
||||
< HTTP/1.1 202 Accepted
|
||||
< Date: Sun, 24 Jan 2021 23:04:15 GMT
|
||||
< Content-Length: 0
|
||||
```
|
||||
|
||||
**Output of hello-display (showing two events):**
|
||||
|
||||
|
||||
```
|
||||
$ kubectl -n eventing-test logs -l app=hello-display --tail=100
|
||||
☁️ cloudevents.Event
|
||||
@@ -567,7 +535,6 @@ Data,
|
||||
|
||||
**Output of goodbye-display (also with two events):**
|
||||
|
||||
|
||||
```
|
||||
$ kubectl -n eventing-test logs -l app=goodbye-display --tail=100
|
||||
☁️ cloudevents.Event
|
||||
@@ -611,15 +578,15 @@ Internal eventing in cloud events is pretty easy to track if it's going to a pre
|
||||
via: https://opensource.com/article/21/2/knative-eventing
|
||||
|
||||
作者:[Jessica Cherry][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/computer_space_graphic_cosmic.png?itok=wu493YbB (Computer laptop in space)
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/computer_space_graphic_cosmic.png
|
||||
[2]: https://opensource.com/article/20/11/knative
|
||||
[3]: https://opensource.com/resources/what-is-kubernetes
|
||||
[4]: https://en.wikipedia.org/wiki/Cloud_native_computing
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
[#]: subject: (Navigate your FreeDOS system)
|
||||
[#]: via: (https://opensource.com/article/21/2/freedos-dir)
|
||||
[#]: author: (Kevin O'Brien https://opensource.com/users/ahuka)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: "Navigate your FreeDOS system"
|
||||
[#]: via: "https://opensource.com/article/21/2/freedos-dir"
|
||||
[#]: author: "Kevin O'Brien https://opensource.com/users/ahuka"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Navigate your FreeDOS system
|
||||
======
|
||||
Master the DIR command to navigate your way around FreeDOS.
|
||||
|
||||
![A map with a route highlighted][1]
|
||||
|
||||
[FreeDOS][2] is an open source implementation of DOS. It's not a remix of Linux, and it is compatible with the operating system that introduced many people to personal computing. This makes it an important resource for running legacy applications, playing retro games, updating firmware on motherboards, and experiencing a little bit of living computer history. In this article, I'll look at some of the essential commands used to navigate a FreeDOS system.
|
||||
@@ -22,7 +23,6 @@ There are many reasons not to work exclusively in your root directory. First of
|
||||
|
||||
The FreeDOS `CD` command changes your current working subdirectory to another subdirectory. Imagine a computer with the following directory structure:
|
||||
|
||||
|
||||
```
|
||||
C:\
|
||||
\LETTERS\
|
||||
@@ -34,48 +34,43 @@ C:\
|
||||
\SCHOOL\
|
||||
```
|
||||
|
||||
You start in the `C:\` directory, so to navigate to your love letter directory, you can use `CD`:
|
||||
|
||||
You start in the `C:\` directory, so to navigate to your love letter directory, you can use `CD` :
|
||||
|
||||
```
|
||||
`C:\>CD \LETTERS\LOVE\`
|
||||
C:\>CD \LETTERS\LOVE\
|
||||
```
|
||||
|
||||
To navigate to your `\LETTERS\BUSINESS` directory, you must specify the path to your business letters from a common fixed point on your filesystem. The most reliable starting location is `C:\`, because it's where _everything_ on your computer is stored.
|
||||
|
||||
To navigate to your `\LETTERS\BUSINESS` directory, you must specify the path to your business letters from a common fixed point on your filesystem. The most reliable starting location is `C:\`, because it's where *everything* on your computer is stored.
|
||||
|
||||
```
|
||||
`C:\LETTERS\LOVE\>CD C:\LETTERS\BUSINESS`
|
||||
C:\LETTERS\LOVE\>CD C:\LETTERS\BUSINESS
|
||||
```
|
||||
|
||||
#### Navigating with dots
|
||||
|
||||
There's a useful shortcut for navigating your FreeDOS system, which takes the form of dots. Two dots (`..`) tell FreeDOS you want to move "back" or "down" in your directory tree. For instance, the `LETTERS` directory in this example system contains one subdirectory called `LOVE` and another called `BUSINESS`. If you're in `LOVE` currently, and you want to step back and change over to `BUSINESS`, you can just use two dots to represent that move:
|
||||
|
||||
There's a useful shortcut for navigating your FreeDOS system, which takes the form of dots. Two dots (`..` ) tell FreeDOS you want to move "back" or "down" in your directory tree. For instance, the `LETTERS` directory in this example system contains one subdirectory called `LOVE` and another called `BUSINESS`. If you're in `LOVE` currently, and you want to step back and change over to `BUSINESS`, you can just use two dots to represent that move:
|
||||
|
||||
```
|
||||
C:\LETTERS\LOVE\>CD ..\BUSINESS
|
||||
C:\LETTERS\BUSINESS\>
|
||||
C:\LETTERS\LOVE\>CD ..\BUSINESS
|
||||
C:\LETTERS\BUSINESS\>
|
||||
```
|
||||
|
||||
To get all the way back to your root directory, just use the right number of dots:
|
||||
|
||||
|
||||
```
|
||||
C:\LETTERS\BUSINESS\: CD ..\\..
|
||||
C:\>
|
||||
C:\LETTERS\BUSINESS\: CD ..\..
|
||||
C:\>
|
||||
```
|
||||
|
||||
#### Navigational shortcuts
|
||||
|
||||
There are some shortcuts for navigating directories, too.
|
||||
There are some shortcuts for navigating directories, too.
|
||||
|
||||
To get back to the root directory from wherever you are:
|
||||
|
||||
|
||||
```
|
||||
C:\LETTERS\BUSINESS\>CD \
|
||||
C:\>
|
||||
C:\LETTERS\BUSINESS\>CD \
|
||||
C:\>
|
||||
```
|
||||
|
||||
### List directory contents with DIR
|
||||
@@ -84,9 +79,8 @@ The `DIR` command displays the contents of a subdirectory, but it can also funct
|
||||
|
||||
`DIR` displays the contents of the current working subdirectory, and with an optional path argument, it displays the contents of some other subdirectory:
|
||||
|
||||
|
||||
```
|
||||
C:\LETTERS\BUSINESS\>DIR
|
||||
C:\LETTERS\BUSINESS\>DIR
|
||||
MTG_CARD TXT 1344 12-29-2020 3:06p
|
||||
NON TXT 381 12-31-2020 8:12p
|
||||
SOMUCHFO TXT 889 12-31-2020 9:36p
|
||||
@@ -97,49 +91,49 @@ TEST BAT 32 01-03-2021 10:34a
|
||||
|
||||
With a special attribute argument, you can use `DIR` to find and filter out certain kinds of files. There are 10 attributes you can specify:
|
||||
|
||||
`H` | Hidden
|
||||
---|---
|
||||
`-H` | Not hidden
|
||||
`S` | System
|
||||
`-S` | Not system
|
||||
`A` | Archivable files
|
||||
`-A` | Already archived files
|
||||
`R` | Read-only files
|
||||
`-R` | Not read-only (i.e., editable and deletable) files
|
||||
`D` | Directories only, no files
|
||||
`-D` | Files only, no directories
|
||||
| - | - |
|
||||
| :- | :- |
|
||||
| H | Hidden |
|
||||
| -H | Not hidden |
|
||||
| S | System |
|
||||
| -S | Not system |
|
||||
| A | Archivable files |
|
||||
| -A | Already archived files |
|
||||
| R | Read-only files |
|
||||
| -R | Not read-only (i.e., editable and deletable) files |
|
||||
| D | Directories only, no files |
|
||||
| -D | Files only, no directories |
|
||||
|
||||
These special designators are denoted with `/A:` followed by the attribute letter. You can enter as many attributes as you like, in order, without leaving a space between them. For instance, to view only hidden directories:
|
||||
|
||||
|
||||
```
|
||||
C:\MEMOS\>DIR /A:HD
|
||||
.OBSCURE <DIR> 01-08-2021 10:10p
|
||||
C:\MEMOS\>DIR /A:HD
|
||||
.OBSCURE <DIR> 01-08-2021 10:10p
|
||||
```
|
||||
|
||||
#### Listing in order
|
||||
|
||||
You can also display the results of your `DIR` command in a specific order. The syntax for this is very similar to using attributes. You leave a space after the `DIR` command or after any other switches, and enter `/O:` followed by a selection. There are 12 possible selections:
|
||||
|
||||
`N` | Alphabetical order by file name
|
||||
---|---
|
||||
`-N` | Reverse alphabetical order by file name
|
||||
`E` | Alphabetical order by file extension
|
||||
`-E` | Reverse alphabetical order by file extension
|
||||
`D` | Order by date and time, earliest first
|
||||
`-D` | Order by date and time, latest first
|
||||
`S` | By size, increasing
|
||||
`-S` | By size, decreasing
|
||||
`C` | By [DoubleSpace][3] compression ratio, lowest to highest (version 6.0 only)
|
||||
`-C` | By DoubleSpace compression ratio, highest to lowest (version 6.0 only)
|
||||
`G` | Group directories before other files
|
||||
`-G` | Group directories after other files
|
||||
| - | - |
|
||||
| :- | :- |
|
||||
| N | Alphabetical order by file name |
|
||||
| -N | Reverse alphabetical order by file name |
|
||||
| E | Alphabetical order by file extension |
|
||||
| -E | Reverse alphabetical order by file extension |
|
||||
| D | Order by date and time, earliest first |
|
||||
| -D | Order by date and time, latest first |
|
||||
| S | By size, increasing |
|
||||
| -S | By size, decreasing |
|
||||
| C | By DoubleSpace compression ratio, lowest to highest (version 6.0 only) |
|
||||
| -C | By DoubleSpace compression ratio, highest to lowest (version 6.0 only) |
|
||||
| G | Group directories before other files |
|
||||
| -G | Group directories after other files |
|
||||
|
||||
To see your directory listing grouped by file extension:
|
||||
|
||||
|
||||
```
|
||||
C:\>DIR /O:E
|
||||
C:\>DIR /O:E
|
||||
TEST BAT 01-10-2021 7:11a
|
||||
TIMER EXE 01-11-2021 6:06a
|
||||
AAA TXT 01-09-2021 4:27p
|
||||
@@ -149,9 +143,8 @@ This returns a list of files in alphabetical order of file extension.
|
||||
|
||||
If you're looking for a file you were working on yesterday, you can order by modification time:
|
||||
|
||||
|
||||
```
|
||||
C:\>DIR /O:-D
|
||||
C:\>DIR /O:-D
|
||||
AAA TXT 01-09-2021 4:27p
|
||||
TEST BAT 01-10-2021 7:11a
|
||||
TIMER EXE 01-11-2021 6:06a
|
||||
@@ -163,12 +156,11 @@ If you need to clean up your hard drive because you're running out of space, you
|
||||
|
||||
You can use multiple arguments in a `DIR` command to achieve fairly complex results. Remember that each argument has to be separated from its neighbors by a blank space on each side:
|
||||
|
||||
|
||||
```
|
||||
`C:\>DIR /A:A /O:D /P`
|
||||
C:\>DIR /A:A /O:D /P
|
||||
```
|
||||
|
||||
This command selects only those files that have not yet been backed up (`/A:A`), orders them by date, beginning with the oldest (`/O:D`), and displays the results on your monitor one page at a time (`/P`). So you can really do some slick stuff with the `DIR` command once you've mastered these arguments and switches.
|
||||
This command selects only those files that have not yet been backed up (`/A:A` ), orders them by date, beginning with the oldest (`/O:D` ), and displays the results on your monitor one page at a time (`/P` ). So you can really do some slick stuff with the `DIR` command once you've mastered these arguments and switches.
|
||||
|
||||
### Terminology
|
||||
|
||||
@@ -180,24 +172,21 @@ If it has a slash in front, it is a switch. So all switches are also arguments,
|
||||
|
||||
FreeDOS can be very different from what you're used to if you're used to Windows or macOS, and it can be just different enough if you're used to Linux. A little practice goes a long way, though, so try some of these on your own. You can always get a help message with the `/?` switch. The best way to get comfortable with these commands is to practice using them.
|
||||
|
||||
* * *
|
||||
|
||||
_Some of the information in this article was previously published in [DOS lesson 12: Expert DIR use][4] (CC BY-SA 4.0)._
|
||||
*Some of the information in this article was previously published in [DOS lesson 12: Expert DIR use][3] (CC BY-SA 4.0).*
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/2/freedos-dir
|
||||
|
||||
作者:[Kevin O'Brien][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/ahuka
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/map_route_location_gps_path.png?itok=RwtS4DsU (A map with a route highlighted)
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/map_route_location_gps_path.png
|
||||
[2]: https://www.freedos.org/
|
||||
[3]: https://en.wikipedia.org/wiki/DriveSpace
|
||||
[4]: https://www.ahuka.com/dos-lessons-for-self-study-purposes/dos-lesson-12-expert-dir-use/
|
||||
[3]: https://www.ahuka.com/dos-lessons-for-self-study-purposes/dos-lesson-12-expert-dir-use/
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
[#]: subject: (5 tips for choosing an Ansible collection that's right for you)
|
||||
[#]: via: (https://opensource.com/article/21/3/ansible-collections)
|
||||
[#]: author: (Tadej Borovšak https://opensource.com/users/tadeboro)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: "5 tips for choosing an Ansible collection that's right for you"
|
||||
[#]: via: "https://opensource.com/article/21/3/ansible-collections"
|
||||
[#]: author: "Tadej Borovšak https://opensource.com/users/tadeboro"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
5 tips for choosing an Ansible collection that's right for you
|
||||
======
|
||||
Try these strategies to find and vet collections of Ansible plugins and
|
||||
modules before you install them.
|
||||
![Woman sitting in front of her computer][1]
|
||||
Try these strategies to find and vet collections of Ansible plugins and modules before you install them.
|
||||
|
||||
![Women in computing and open source][1]
|
||||
|
||||
Image by: Ray Smith
|
||||
|
||||
In August 2020, Ansible issued its first release since the developers split the core functionality from the vast majority of its modules and plugins. A few [basic Ansible modules][2] remain part of core Ansible—modules for templating configuration files, managing services, and installing packages. All the other modules and plugins found their homes in dedicated [Ansible collections][3].
|
||||
|
||||
@@ -25,7 +27,6 @@ With the introduction of Ansible collections, [Ansible Galaxy][7] became the cen
|
||||
|
||||
Ansible comes bundled with the `ansible-galaxy` tool for installing collections. Once you know what Ansible collection you want to install, things are relatively straightforward: Run the installation command listed on the Ansible Galaxy page. Ansible takes care of downloading and installing it. For example:
|
||||
|
||||
|
||||
```
|
||||
$ ansible-galaxy collection install sensu.sensu_go
|
||||
Process install dependency map
|
||||
@@ -44,7 +45,7 @@ The ability to install Ansible collections offered a lot more control over the c
|
||||
|
||||
Now users are solely responsible for the quality of content they use to build Ansible playbooks. But how can you separate high-quality content from the rest? Here are five things to check when evaluating an Ansible collection.
|
||||
|
||||
#### 1\. Documentation
|
||||
#### 1. Documentation
|
||||
|
||||
Once you find a potential candidate on Ansible Galaxy, check its documentation first. In an ideal world, each Ansible collection would have a dedicated documentation site. For example, the [Sensu Go][8] and [F5 Networks][9] Ansible collections have them. Most other Ansible collections come only with a README file, but this will change for the better once the documentation tools mature.
|
||||
|
||||
@@ -52,10 +53,9 @@ The Ansible collection's documentation should contain at least a quickstart tuto
|
||||
|
||||
Another essential part of the documentation is a detailed module, plugin, and role reference guide. Collection authors do not always publish those guides on the internet, but they should always be accessible with the `ansible-doc` tool.
|
||||
|
||||
|
||||
```
|
||||
$ ansible-doc community.sops.sops_encrypt
|
||||
> SOPS_ENCRYPT (/home/tadej/.ansible/collections/ansible>
|
||||
> SOPS_ENCRYPT (/home/tadej/.ansible/collections/ansible>
|
||||
|
||||
Allows to encrypt binary data (Base64 encoded), text
|
||||
data, JSON or YAML data with sops.
|
||||
@@ -63,7 +63,7 @@ $ ansible-doc community.sops.sops_encrypt
|
||||
* This module is maintained by The Ansible Community
|
||||
OPTIONS (= is mandatory):
|
||||
|
||||
\- attributes
|
||||
- attributes
|
||||
The attributes the resulting file or directory should
|
||||
have.
|
||||
To get supported flags look at the man page for
|
||||
@@ -78,18 +78,17 @@ OPTIONS (= is mandatory):
|
||||
...
|
||||
```
|
||||
|
||||
#### 2\. Playbook readability
|
||||
#### 2. Playbook readability
|
||||
|
||||
An Ansible playbook should serve as a human-readable description of the desired state. To achieve that, modules from the Ansible collection under evaluation should have a consistent user interface and descriptive parameter names.
|
||||
|
||||
For example, if Ansible modules interact with a web service, authentication parameters should be separated from the rest. And all modules should use the same authentication parameters if possible.
|
||||
|
||||
|
||||
```
|
||||
\- name: Create a check that runs every 30 seconds
|
||||
- name: Create a check that runs every 30 seconds
|
||||
sensu.sensu_go.check:
|
||||
auth: &auth
|
||||
url: <https://my.sensu.host:8080>
|
||||
auth: &auth
|
||||
url: https://my.sensu.host:8080
|
||||
user: demo
|
||||
password: demo-pass
|
||||
name: check
|
||||
@@ -97,36 +96,34 @@ For example, if Ansible modules interact with a web service, authentication para
|
||||
interval: 30
|
||||
publish: true
|
||||
|
||||
\- name: Create a filter
|
||||
- name: Create a filter
|
||||
sensu.sensu_go.filter:
|
||||
# Reuse the authentication data from before
|
||||
# Reuse the authentication data from before
|
||||
auth: *auth
|
||||
name: filter
|
||||
action: deny
|
||||
expressions:
|
||||
- event.check.interval == 10
|
||||
- event.check.interval == 10
|
||||
- event.check.occurrences == 1
|
||||
```
|
||||
|
||||
#### 3\. Basic functionality
|
||||
#### 3. Basic functionality
|
||||
|
||||
Before you start using third-party Ansible content in production, always check each Ansible module's basic functionality.
|
||||
|
||||
Probably the most critical property to look for is the result. Ansible modules and roles that enforce a state are much easier to use than their action-executing counterparts. This is because you can update your Ansible playbook and rerun it without risking a significant breakage.
|
||||
|
||||
|
||||
```
|
||||
\- name: Command module executes an action -> fails on re-run
|
||||
- name: Command module executes an action -> fails on re-run
|
||||
ansible.builtin.command: useradd demo
|
||||
|
||||
\- name: User module enforces a state -> safe to re-run
|
||||
- name: User module enforces a state -> safe to re-run
|
||||
ansible.builtin.user:
|
||||
name: demo
|
||||
```
|
||||
|
||||
You should also expect support for [check mode][12], which simulates the change without making it. If you combine check mode with state enforcement, you get a configuration drift detector for free.
|
||||
|
||||
|
||||
```
|
||||
$ ansible-playbook --check playbook.yaml
|
||||
|
||||
@@ -142,11 +139,11 @@ host : ok=5 changed=2 unreachable=0 failed=0
|
||||
skipped=3 rescued=0 ignored=0
|
||||
```
|
||||
|
||||
#### 4\. Implementation robustness
|
||||
#### 4. Implementation robustness
|
||||
|
||||
A robustness check is a bit harder to perform if you've never developed an Ansible module or role before. Checking the continuous integration/continuous delivery (CI/CD) configuration files should give you a general idea of what is tested. Finding `ansible-test` and `molecule` commands in the test suite is an excellent sign.
|
||||
|
||||
#### 5\. Maintenance
|
||||
#### 5. Maintenance
|
||||
|
||||
During your evaluation, you should also take a look at the issue tracker and development activity. Finding old issues with no response from maintainers is one sign of a poorly maintained Ansible collection.
|
||||
|
||||
@@ -163,15 +160,15 @@ If you are thinking about creating your own Ansible Collection, you can download
|
||||
via: https://opensource.com/article/21/3/ansible-collections
|
||||
|
||||
作者:[Tadej Borovšak][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/tadeboro
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/OSDC_women_computing_3.png?itok=qw2A18BM (Woman sitting in front of her computer)
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/OSDC_women_computing_3.png
|
||||
[2]: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/
|
||||
[3]: https://docs.ansible.com/ansible/latest/collections/index.html#list-of-collections
|
||||
[4]: https://galaxy.ansible.com/sensu/sensu_go
|
||||
|
||||
@@ -1,36 +1,34 @@
|
||||
[#]: subject: (Build a home thermostat with a Raspberry Pi)
|
||||
[#]: via: (https://opensource.com/article/21/3/thermostat-raspberry-pi)
|
||||
[#]: author: (Joe Truncale https://opensource.com/users/jtruncale)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: "Build a home thermostat with a Raspberry Pi"
|
||||
[#]: via: "https://opensource.com/article/21/3/thermostat-raspberry-pi"
|
||||
[#]: author: "Joe Truncale https://opensource.com/users/jtruncale"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Build a home thermostat with a Raspberry Pi
|
||||
======
|
||||
The ThermOS project is an answer to the many downsides of off-the-shelf
|
||||
smart thermostats.
|
||||
The ThermOS project is an answer to the many downsides of off-the-shelf smart thermostats.
|
||||
|
||||
![Orange home vintage thermostat][1]
|
||||
|
||||
My wife and I moved into a new home in October 2020. As soon as it started getting cold, we realized some shortcomings of the home's older heating system (including one heating zone that was _always_ on). We had Nest thermostats in our previous home, and the current setup was not nearly as convenient. There are multiple thermostats in our house, and some had programmed heating schedules, others had different schedules, some had none at all.
|
||||
Image by: Photo by [Moja Msanii][2] on [Unsplash][3]
|
||||
|
||||
![Old thermostats][2]
|
||||
My wife and I moved into a new home in October 2020. As soon as it started getting cold, we realized some shortcomings of the home's older heating system (including one heating zone that was *always* on). We had Nest thermostats in our previous home, and the current setup was not nearly as convenient. There are multiple thermostats in our house, and some had programmed heating schedules, others had different schedules, some had none at all.
|
||||
|
||||
The home's previous owner left notes explaining how some of the thermostats worked. (Joseph Truncale, [CC BY-SA 4.0][3])
|
||||
![Old thermostats][4]
|
||||
|
||||
The home's previous owner left notes explaining how some of the thermostats worked. (Joseph Truncale, CC BY-SA 4.0)
|
||||
|
||||
It was time for a change, but the house has some constraints:
|
||||
|
||||
* It was built in the late 1960s with a renovation during the '90s.
|
||||
* The heat is hydronic (hot water baseboard).
|
||||
* It has six thermostats for the six heating zones.
|
||||
* There are only two wires that go to each thermostat for heat (red and white).
|
||||
* It was built in the late 1960s with a renovation during the '90s.
|
||||
* The heat is hydronic (hot water baseboard).
|
||||
* It has six thermostats for the six heating zones.
|
||||
* There are only two wires that go to each thermostat for heat (red and white).
|
||||
|
||||
|
||||
|
||||
![Furnace valves][4]
|
||||
|
||||
Taco (pronounced TAY-KO) zone valves at the furnace. (Joseph Truncale, [CC BY-SA 4.0][3])
|
||||
![Furnace valves][5]
|
||||
|
||||
### To buy or to build?
|
||||
|
||||
@@ -38,36 +36,29 @@ I wanted "smart" thermostat control for all of the heat zones (schedules, automa
|
||||
|
||||
**Option 1: A Nest or Ecobee**
|
||||
|
||||
* It's expensive: No smart thermostat can handle multiple zones, so I would need one for each zone (~$200*6 = $1,200).
|
||||
* It's difficult: I would have to rerun the thermostat wire to get the infamous [C wire][5], which enables continuous power to the thermostat. The wires are 20 to 100 feet each, in-wall, and _might_ be stapled to the studs.
|
||||
* It's expensive: No smart thermostat can handle multiple zones, so I would need one for each zone (~$200*6 = $1,200).
|
||||
* It's difficult: I would have to rerun the thermostat wire to get the infamous [C wire][6], which enables continuous power to the thermostat. The wires are 20 to 100 feet each, in-wall, and might be stapled to the studs.
|
||||
|
||||
**Option 2: A battery-powered thermostat** such as the [Sensi WiFi thermostat][7]
|
||||
|
||||
* The batteries last only a month or two.
|
||||
* It's not HomeKit-compatible in battery-only mode.
|
||||
|
||||
**Option 2: A battery-powered thermostat** such as the [Sensi WiFi thermostat][6]
|
||||
**Option 3: A commercial-off-the-shelf thermostat**, but only one exists (kind of): [Honeywell's TrueZONE][8]
|
||||
|
||||
* The batteries last only a month or two.
|
||||
* It's not HomeKit-compatible in battery-only mode.
|
||||
* It's old and poorly supported (it was released in 2008).
|
||||
* It's expensive—more than $300 for just the controller, and you need a [RedLINK gateway][9] for a shoddy app to work.
|
||||
|
||||
|
||||
|
||||
**Option 3: A commercial-off-the-shelf thermostat**, but only one exists (kind of): [Honeywell's TrueZONE][7]
|
||||
|
||||
* It's old and poorly supported (it was released in 2008).
|
||||
* It's expensive—more than $300 for just the controller, and you need a [RedLINK gateway][8] for a shoddy app to work.
|
||||
|
||||
|
||||
|
||||
And the winner is…
|
||||
And the winner is…
|
||||
|
||||
**Option 4: Build my own!**
|
||||
I decided to build my own multizone smart thermostat, which I named [ThermOS][9].
|
||||
|
||||
* It's centralized at the furnace (you need one device, not six).
|
||||
* It uses the existing in-wall thermostat wires.
|
||||
* It's HomeKit compatible, complete with automation, scheduling, home/away, etc.
|
||||
* Anddddd it's… fun? Yeah, fun… I think.
|
||||
|
||||
I decided to build my own multizone smart thermostat, which I named [ThermOS][10].
|
||||
|
||||
* It's centralized at the furnace (you need one device, not six).
|
||||
* It uses the existing in-wall thermostat wires.
|
||||
* It's HomeKit compatible, complete with automation, scheduling, home/away, etc.
|
||||
* Anddddd it's… fun? Yeah, fun… I think.
|
||||
|
||||
### The ThermOS hardware
|
||||
|
||||
@@ -75,79 +66,62 @@ I knew that I wanted to use a Raspberry Pi. Since they've gotten so inexpensive,
|
||||
|
||||
Here's a full list of the parts I used:
|
||||
|
||||
Name | Quantity | Price
|
||||
---|---|---
|
||||
Raspberry Pi 4 Model B 2GB | 1 | $29.99
|
||||
Raspberry Pi 4 official 15W power supply | 1 | $6.99
|
||||
Inland 400 tie-point breadboard | 1 | $2.99
|
||||
Inland 8 channel 5V relay module for Arduino | 1 | $8.99
|
||||
Inland DuPont jumper wire 20cm (3 pack) | 1 | $4.99
|
||||
DS18B20 temperature sensor (genuine) from Mouser.com | 6 | $6.00
|
||||
3-pin screw terminal blocks (40 pack) | 1 | $7.99
|
||||
RPi GPIO terminal block breakout board module for Raspberry Pi | 1 | $17.99
|
||||
Alligator clip test leads (10 pack) | 1 | $5.89
|
||||
Southwire 18/2 thermostat wire (50ft) | 1 | $10.89
|
||||
Shrinkwrap | 1 | $4.99
|
||||
Solderable breadboard (5 pack) | 1 | $11.99
|
||||
PCB mounting brackets (50 pack) | 1 | $7.99
|
||||
Plastic housing/enclosure | 1 | $27.92
|
||||
| Name | Quantity | Price |
|
||||
| :- | :- | :- |
|
||||
| Raspberry Pi 4 Model B 2GB | 1 | $29.99 |
|
||||
| Raspberry Pi 4 official 15W power supply | 1 | $6.99 |
|
||||
| Inland 400 tie-point breadboard | 1 | $2.99 |
|
||||
| Inland 8 channel 5V relay module for Arduino | 1 | $8.99 |
|
||||
| Inland DuPont jumper wire 20cm (3 pack) | 1 | $4.99 |
|
||||
| DS18B20 temperature sensor (genuine) from Mouser.com | 6 | $6.00 |
|
||||
| 3-pin screw terminal blocks (40 pack) | 1 | $7.99 |
|
||||
| RPi GPIO terminal block breakout board module for Raspberry Pi | 1 | $17.99 |
|
||||
| Alligator clip test leads (10 pack) | 1 | $5.89 |
|
||||
| Southwire 18/2 thermostat wire (50ft) | 1 | $10.89 |
|
||||
| Shrinkwrap | 1 | $4.99 |
|
||||
| Solderable breadboard (5 pack) | 1 | $11.99 |
|
||||
| PCB mounting brackets (50 pack) | 1 | $7.99 |
|
||||
| Plastic housing/enclosure | 1 | $27.92 |
|
||||
|
||||
I began drawing out the hardware diagram on [draw.io][10] and realized I lacked some crucial knowledge about the furnace. I opened the side panel and found the step-down transformer that takes the 120V electrical line and makes it 24V for the heating system. If your heating system is anything like mine, you'll see a lot of jumper wires between the Taco zone valves. Terminal 3 on the Taco is jumped across all of my zone valves. This is because it doesn't matter how many valves are on/open—it just controls the circulator pump. If any combination of one to five valves is open, it should be on; if no valves are open, it should be off… simple!
|
||||
I began drawing out the hardware diagram on [draw.io][11] and realized I lacked some crucial knowledge about the furnace. I opened the side panel and found the step-down transformer that takes the 120V electrical line and makes it 24V for the heating system. If your heating system is anything like mine, you'll see a lot of jumper wires between the Taco zone valves. Terminal 3 on the Taco is jumped across all of my zone valves. This is because it doesn't matter how many valves are on/open—it just controls the circulator pump. If any combination of one to five valves is open, it should be on; if no valves are open, it should be off… simple!
|
||||
|
||||
![Furnace wiring architecture][11]
|
||||
|
||||
ThermOS architecture using one zone. (Joseph Truncale, [CC BY-SA 4.0][3])
|
||||
![Furnace wiring architecture][12]
|
||||
|
||||
At its core, a thermostat is just a type of switch. Once the thermistor (temp sensor) inside the thermostat detects a lower temperature, the switch closes and completes the 24V circuit. Instead of having a thermostat in every room, this project keeps all of them right next to the furnace so that all six-zone valves can be controlled by a relay module using six of the eight relays. The Raspberry Pi acts as the brains of the thermostat and controls each relay independently.
|
||||
|
||||
![Manually setting relays using Raspberry Pi and Python][12]
|
||||
|
||||
Manually setting the relays using the Raspberry Pi and Python. (Joseph Truncale, [CC BY-SA 4.0][3])
|
||||
![Manually setting relays using Raspberry Pi and Python][13]
|
||||
|
||||
The next problem was how to get temperature readings from each room. I could have a wireless temperature sensor in each room running on an Arduino or Raspberry Pi, but that can get expensive and complicated. Instead, I wanted to reuse the existing thermostat wire in the walls but purely for temperature sensors.
|
||||
|
||||
The "1-wire" [DS18B20][13] temperature sensor appeared to fit the bill:
|
||||
The "1-wire" [DS18B20][14] temperature sensor appeared to fit the bill:
|
||||
|
||||
* It has an accuracy of +/- 0.5°C or 0.9°F.
|
||||
* It uses the "1-wire" protocol for data.
|
||||
* Most importantly, the DS18B20 can use "[parasitic power][14]" mode where it needs just two wires for power and data. Just a heads up… almost all of the DS18B20s out there are [counterfeit][15]. I purchased a few (hoping they were genuine), but they wouldn't work when I tried to use parasitic power. I then bought real ones from [Mouser.com][16], and they worked like a charm!
|
||||
* It has an accuracy of +/- 0.5°C or 0.9°F.
|
||||
* It uses the "1-wire" protocol for data.
|
||||
* Most importantly, the DS18B20 can use "[parasitic power][15]" mode where it needs just two wires for power and data. Just a heads up… almost all of the DS18B20s out there are [counterfeit][16]. I purchased a few (hoping they were genuine), but they wouldn't work when I tried to use parasitic power. I then bought real ones from [Mouser.com][17], and they worked like a charm!
|
||||
|
||||
![Temperature sensors][18]
|
||||
|
||||
Starting with a breadboard and all the components locally, I started writing code to interact with all of it. Once I proved out the concept, I added the existing in-wall thermostat wire into the mix. I got consistent readings with that setup, so I set out to make them a bit more polished. With help from my [dad][19], the self-proclaimed "just good enough" solderer, we soldered leads to the three-pin screw terminals (to avoid overheating the sensor) and then attached the sensor into the terminals. Now the sensors can be attached with wire nuts to the existing in-wall wiring.
|
||||
|
||||
![Temperature sensors][17]
|
||||
|
||||
Three DS18B20s connected using parasitic power on the same GPIO bus. (Joseph Truncale, [CC BY-SA 4.0][3])
|
||||
|
||||
Starting with a breadboard and all the components locally, I started writing code to interact with all of it. Once I proved out the concept, I added the existing in-wall thermostat wire into the mix. I got consistent readings with that setup, so I set out to make them a bit more polished. With help from my [dad][18], the self-proclaimed "just good enough" solderer, we soldered leads to the three-pin screw terminals (to avoid overheating the sensor) and then attached the sensor into the terminals. Now the sensors can be attached with wire nuts to the existing in-wall wiring.
|
||||
|
||||
![Attaching temperature sensors][19]
|
||||
|
||||
The DS18B20s are attached to the old thermostat location using the existing wires. (Joseph Truncale, [CC BY-SA 4.0][3])
|
||||
![Attaching temperature sensors][20]
|
||||
|
||||
I'm still in the process of "prettifying" my temperature sensor wall mounts, but I've gone through a few 3D printing revisions, and I think I'm almost there.
|
||||
|
||||
![Wall mounts][20]
|
||||
|
||||
I started with a Nest-style mount and made my way to a flush-mount style. (Joseph Truncale, [CC BY-SA 4.0][3])
|
||||
![Wall mounts][21]
|
||||
|
||||
### The ThermOS software
|
||||
|
||||
As usual, writing the logic wasn't the hard part. However, deciding on the application architecture and framework was a confusing, multi-day process. I started out evaluating open source projects like [PiHome][21], but it relied on specific hardware _and_ was written in PHP. I'm a Python fan and decided to start from scratch and write my own REST API.
|
||||
As usual, writing the logic wasn't the hard part. However, deciding on the application architecture and framework was a confusing, multi-day process. I started out evaluating open source projects like [PiHome][22], but it relied on specific hardware *and* was written in PHP. I'm a Python fan and decided to start from scratch and write my own REST API.
|
||||
|
||||
Since HomeKit integration was so important, I figured I would eventually write a [HomeBridge][22] plugin to integrate it. I didn't realize that there was an entire Python HomeKit framework called [HAP-Python][23] that implements the accessory protocol. It helped me get a proof of concept running and controlled through my iPhone's Home app within 30 minutes.
|
||||
Since HomeKit integration was so important, I figured I would eventually write a [HomeBridge][23] plugin to integrate it. I didn't realize that there was an entire Python HomeKit framework called [HAP-Python][24] that implements the accessory protocol. It helped me get a proof of concept running and controlled through my iPhone's Home app within 30 minutes.
|
||||
|
||||
![ThermOS HomeKit integration][24]
|
||||
![ThermOS HomeKit integration][25]
|
||||
|
||||
Initial version of Apple HomeKit integration, with help from the HAP-Python framework. (Joseph Truncale, [CC BY-SA 4.0][3])
|
||||
|
||||
![ThermOS software architecture][25]
|
||||
|
||||
ThermOS software architecture (Joseph Truncale, [CC BY-SA 4.0][3])
|
||||
![ThermOS software architecture][26]
|
||||
|
||||
The rest of the "temp" logic is relatively straightforward, but I do want to highlight a piece that I initially missed. My code was running for a few days, and I was working on the hardware, when I noticed that my relays were turning on and off every few seconds. This "short-cycling" isn't necessarily harmful, but it certainly isn't efficient. To avoid that, I added some thresholding to make sure the heat toggles only when it's +/- 0.5C°.
|
||||
|
||||
Here is the threshold logic (you can see the [rubber-duck debugging][26] in the comments):
|
||||
|
||||
Here is the threshold logic (you can see the [rubber-duck debugging][27] in the comments):
|
||||
|
||||
```
|
||||
# check that we want heat
|
||||
@@ -155,7 +129,7 @@ if self.target_state.value == 1:
|
||||
# if heat relay is already on, check if above threshold
|
||||
# if above, turn off .. if still below keep on
|
||||
if GPIO.input(self.relay_pin):
|
||||
if self.current_temp.value - self.target_temp.value >= 0.5:
|
||||
if self.current_temp.value - self.target_temp.value >= 0.5:
|
||||
status = 'HEAT ON - TEMP IS ABOVE TOP THRESHOLD, TURNING OFF'
|
||||
GPIO.output(self.relay_pin, GPIO.LOW)
|
||||
else:
|
||||
@@ -163,96 +137,87 @@ if self.target_state.value == 1:
|
||||
GPIO.output(self.relay_pin, GPIO.HIGH)
|
||||
# if heat relay is not already on, check if below threshold
|
||||
elif not GPIO.input(self.relay_pin):
|
||||
if self.current_temp.value - self.target_temp.value <= -0.5:
|
||||
if self.current_temp.value - self.target_temp.value <= -0.5:
|
||||
status = 'HEAT OFF - TEMP IS BELOW BOTTOM THRESHOLD, TURNING ON'
|
||||
GPIO.output(self.relay_pin, GPIO.HIGH)
|
||||
else:
|
||||
status = 'HEAT OFF - KEEPING OFF'
|
||||
```
|
||||
|
||||
![Thresholding][27]
|
||||
|
||||
Thresholding allows longer stretches of time where the heat is off. (Joseph Truncale, [CC BY-SA 4.0][3])
|
||||
![Thresholding][28]
|
||||
|
||||
And I achieved my ultimate goal—to be able to control all of it from my phone.
|
||||
|
||||
![ThermOS as a HomeKit Hub][28]
|
||||
|
||||
ThermOS as a HomeKit Hub (Joseph Truncale, [CC BY-SA 4.0][3])
|
||||
![ThermOS as a HomeKit Hub][29]
|
||||
|
||||
### Putting my ThermOS in a lunchbox
|
||||
|
||||
My proof of concept was pretty messy.
|
||||
|
||||
![Initial ThermOS setup][29]
|
||||
![Initial ThermOS setup][30]
|
||||
|
||||
ThermOS controlling a single zone (before packaging it) (Joseph Truncale, [CC BY-SA 4.0][3])
|
||||
|
||||
With the software and general hardware design in place, I started figuring out how to package all of the components in a more permanent and polished form. One of my main concerns for a permanent installation was to use a breadboard with DuPont jumper wires. I ordered some [solderable breadboards][30] and a [screw terminal breakout board][31] (thanks [@arduima][32] for the Raspberry Pi GPIO pins).
|
||||
With the software and general hardware design in place, I started figuring out how to package all of the components in a more permanent and polished form. One of my main concerns for a permanent installation was to use a breadboard with DuPont jumper wires. I ordered some [solderable breadboards][31] and a [screw terminal breakout board][32] (thanks [@arduima][33] for the Raspberry Pi GPIO pins).
|
||||
|
||||
Here's what the solderable breadboard with mounts and enclosure looked like in progress.
|
||||
|
||||
![ThermOS hardware being packaged][33]
|
||||
|
||||
Putting the ThermOS in a lunchbox. (Joseph Truncale, [CC BY-SA 4.0][3])
|
||||
![ThermOS hardware][34]
|
||||
|
||||
And here it is, mounted in the boiler room.
|
||||
|
||||
![ThermOS mounted][34]
|
||||
|
||||
ThermOS mounted (Joseph Truncale, [CC BY-SA 4.0][3])
|
||||
![ThermOS mounted][35]
|
||||
|
||||
Now I just need to organize and label the wires, and then I can start swapping the remainder of the thermostats over to ThermOS. And I'll be on to my next project: ThermOS for my central air conditioning.
|
||||
|
||||
* * *
|
||||
Image by: (Joseph Truncale, CC BY-SA 4.0)
|
||||
|
||||
_This originally appeared on [Medium][35] and is republished with permission._
|
||||
*This originally appeared on [Medium][36] and is republished with permission.*
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/3/thermostat-raspberry-pi
|
||||
|
||||
作者:[Joe Truncale][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/jtruncale
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/home-thermostat.jpg?itok=wuV1XL7t (Orange home vintage thermostat)
|
||||
[2]: https://opensource.com/sites/default/files/uploads/oldthermostats.jpeg (Old thermostats)
|
||||
[3]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[4]: https://opensource.com/sites/default/files/uploads/furnacevalves.jpeg (Furnace valves)
|
||||
[5]: https://smartthermostatguide.com/thermostat-c-wire-explained/
|
||||
[6]: https://www.amazon.com/Emerson-Thermostat-Version-Energy-Certified/dp/B01NB1OB0I
|
||||
[7]: https://www.honeywellhome.com/us/en/products/air/forced-air-zone-panels/truezone-hz432-panel-hz432-u/
|
||||
[8]: https://www.amazon.com/Honeywell-Redlink-Enabled-Internet-THM6000R7001/dp/B0783HK9ZZ
|
||||
[9]: https://github.com/truncj/thermos
|
||||
[10]: http://draw.io/
|
||||
[11]: https://opensource.com/sites/default/files/uploads/furnacewiring.png (Furnace wiring architecture)
|
||||
[12]: https://opensource.com/sites/default/files/uploads/settingrelays.gif (Manually setting relays using Raspberry Pi and Python)
|
||||
[13]: https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf
|
||||
[14]: https://learn.openenergymonitor.org/electricity-monitoring/temperature/DS18B20-temperature-sensing
|
||||
[15]: https://github.com/cpetrich/counterfeit_DS18B20
|
||||
[16]: https://www.mouser.com/
|
||||
[17]: https://opensource.com/sites/default/files/uploads/tempsensors.png (Temperature sensors)
|
||||
[18]: https://twitter.com/jofredrick
|
||||
[19]: https://opensource.com/sites/default/files/uploads/attachingsensors.jpeg (Attaching temperature sensors)
|
||||
[20]: https://opensource.com/sites/default/files/uploads/wallmount.jpeg (Wall mounts)
|
||||
[21]: https://github.com/pihome-shc/pihome
|
||||
[22]: https://github.com/homebridge/homebridge
|
||||
[23]: https://github.com/ikalchev/HAP-python
|
||||
[24]: https://opensource.com/sites/default/files/uploads/iphoneintegration.gif (ThermOS HomeKit integration)
|
||||
[25]: https://opensource.com/sites/default/files/uploads/thermosarchitecture.png (ThermOS software architecture)
|
||||
[26]: https://en.wikipedia.org/wiki/Rubber_duck_debugging
|
||||
[27]: https://opensource.com/sites/default/files/uploads/thresholding.png (Thresholding)
|
||||
[28]: https://opensource.com/sites/default/files/uploads/thermoshomekit.png (ThermOS as a HomeKit Hub)
|
||||
[29]: https://opensource.com/sites/default/files/uploads/unpackaged.jpeg (Initial ThermOS setup)
|
||||
[30]: https://www.amazon.com/gp/product/B07ZV8FWM4/r
|
||||
[31]: https://www.amazon.com/gp/product/B084C69VSQ/
|
||||
[32]: https://twitter.com/dimitri_koshkin
|
||||
[33]: https://opensource.com/sites/default/files/uploads/breadboard.png (ThermOS hardware being packaged)
|
||||
[34]: https://opensource.com/sites/default/files/uploads/mounted.png (ThermOS mounted)
|
||||
[35]: https://joetruncale.medium.com/thermos-d089e1c4974b
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/home-thermostat.jpg
|
||||
[2]: https://unsplash.com/@mojamsanii?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[3]: https://unsplash.com/s/photos/thermostat?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[4]: https://opensource.com/sites/default/files/uploads/oldthermostats.jpeg
|
||||
[5]: https://opensource.com/sites/default/files/uploads/furnacevalves.jpeg
|
||||
[6]: https://smartthermostatguide.com/thermostat-c-wire-explained/
|
||||
[7]: https://www.amazon.com/Emerson-Thermostat-Version-Energy-Certified/dp/B01NB1OB0I
|
||||
[8]: https://www.honeywellhome.com/us/en/products/air/forced-air-zone-panels/truezone-hz432-panel-hz432-u/
|
||||
[9]: https://www.amazon.com/Honeywell-Redlink-Enabled-Internet-THM6000R7001/dp/B0783HK9ZZ
|
||||
[10]: https://github.com/truncj/thermos
|
||||
[11]: http://draw.io/
|
||||
[12]: https://opensource.com/sites/default/files/uploads/furnacewiring.png
|
||||
[13]: https://opensource.com/sites/default/files/uploads/settingrelays.gif
|
||||
[14]: https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf
|
||||
[15]: https://learn.openenergymonitor.org/electricity-monitoring/temperature/DS18B20-temperature-sensing
|
||||
[16]: https://github.com/cpetrich/counterfeit_DS18B20
|
||||
[17]: https://www.mouser.com/
|
||||
[18]: https://opensource.com/sites/default/files/uploads/tempsensors.png
|
||||
[19]: https://twitter.com/jofredrick
|
||||
[20]: https://opensource.com/sites/default/files/uploads/attachingsensors.jpeg
|
||||
[21]: https://opensource.com/sites/default/files/uploads/wallmount.jpeg
|
||||
[22]: https://github.com/pihome-shc/pihome
|
||||
[23]: https://github.com/homebridge/homebridge
|
||||
[24]: https://github.com/ikalchev/HAP-python
|
||||
[25]: https://opensource.com/sites/default/files/uploads/iphoneintegration.gif
|
||||
[26]: https://opensource.com/sites/default/files/uploads/thermosarchitecture.png
|
||||
[27]: https://en.wikipedia.org/wiki/Rubber_duck_debugging
|
||||
[28]: https://opensource.com/sites/default/files/uploads/thresholding.png
|
||||
[29]: https://opensource.com/sites/default/files/uploads/thermoshomekit.png
|
||||
[30]: https://opensource.com/sites/default/files/uploads/unpackaged.jpeg
|
||||
[31]: https://www.amazon.com/gp/product/B07ZV8FWM4/r
|
||||
[32]: https://www.amazon.com/gp/product/B084C69VSQ/
|
||||
[33]: https://twitter.com/dimitri_koshkin
|
||||
[34]: https://opensource.com/sites/default/files/uploads/breadboard.png
|
||||
[35]: https://opensource.com/sites/default/files/uploads/mounted.png
|
||||
[36]: https://joetruncale.medium.com/thermos-d089e1c4974b
|
||||
|
||||
@@ -1,37 +1,35 @@
|
||||
[#]: subject: (Learn Java with object orientation by building a classic Breakout game)
|
||||
[#]: via: (https://opensource.com/article/21/3/java-object-orientation)
|
||||
[#]: author: (Vaneska Sousa https://opensource.com/users/vaneska)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: "Learn Java by building a classic arcade game"
|
||||
[#]: via: "https://opensource.com/article/21/3/java-object-orientation"
|
||||
[#]: author: "Vaneska Sousa https://opensource.com/users/vaneska"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Learn Java with object orientation by building a classic Breakout game
|
||||
Learn Java by building a classic arcade game
|
||||
======
|
||||
Practice how to structure a project and write Java code while having fun
|
||||
building a fun game.
|
||||
Practice how to structure a project and write Java code while having fun building a fun game.
|
||||
|
||||
![Learning and studying technology is the key to success][1]
|
||||
|
||||
As a second-semester student in systems and digital media at the Federal University of Ceará in Brazil, I was given the assignment to remake the classic Atari 2600 [Breakout game][2] from 1978. I am still in my infancy in learning software development, and this was a challenging experience. It was also a gainful one because I learned a lot, especially about applying object-oriented concepts.
|
||||
Image by: [WOCinTech Chat][2], [CC BY 2.0][3]
|
||||
|
||||
![Breakout game][3]
|
||||
As a second-semester student in systems and digital media at the Federal University of Ceará in Brazil, I was given the assignment to remake the classic Atari 2600 [Breakout game][4] from 1978. I am still in my infancy in learning software development, and this was a challenging experience. It was also a gainful one because I learned a lot, especially about applying object-oriented concepts.
|
||||
|
||||
(Vaneska Karen, [CC BY-SA 4.0][4])
|
||||
![Breakout game][5]
|
||||
|
||||
I'll explain how I accomplished this challenge, and if you follow the step-by-step instructions, at the end of this article, you will have the first pieces of your own classic Breakout game.
|
||||
|
||||
### Choosing Java and TotalCross
|
||||
|
||||
Several of my courses use [Processing][5], a software engine that uses [Java][6]. Java is a great language for learning programming concepts, in part because it's a strongly typed language.
|
||||
Several of my courses use [Processing][6], a software engine that uses [Java][7]. Java is a great language for learning programming concepts, in part because it's a strongly typed language.
|
||||
|
||||
Despite being free to choose any language or framework for my Breakout project, I chose to continue in Java to apply what I've learned in my coursework. I also wanted to use a framework so that I did not need to do everything from scratch. I considered using Godot, but that would mean I would hardly need to program at all.
|
||||
|
||||
Instead, I chose [TotalCross][7]. It is an open source software development kit (SDK) and framework with a simple game engine that generates code for [Linux Arm][8] devices (like the Raspberry Pi) and smartphones. Also, because I work for TotalCross, I have access to developers with much more experience than I have and know the platform very well. It seemed to be the safest way and, despite some strife, I don't regret it one bit. It was very cool to develop the whole project and see it running on the phone and the [Raspberry Pi][9].
|
||||
Instead, I chose [TotalCross][8]. It is an open source software development kit (SDK) and framework with a simple game engine that generates code for [Linux Arm][9] devices (like the Raspberry Pi) and smartphones. Also, because I work for TotalCross, I have access to developers with much more experience than I have and know the platform very well. It seemed to be the safest way and, despite some strife, I don't regret it one bit. It was very cool to develop the whole project and see it running on the phone and the [Raspberry Pi][10].
|
||||
|
||||
![Breakout remake][10]
|
||||
|
||||
Breakout remake built with Java and TotalCross running on Raspberry Pi 3 Model B. (Vaneska Karen, [CC BY-SA 4.0][4])
|
||||
![Breakout remake][11]
|
||||
|
||||
### Define the project mechanics and structure
|
||||
|
||||
@@ -39,63 +37,52 @@ When starting to develop any application, and especially a game, you need to con
|
||||
|
||||
#### Game mechanics
|
||||
|
||||
1. The platform moves left or right, according to the user's command. When it reaches an end, it hits the "wall" (edge).
|
||||
2. When the ball hits the platform, it returns in the opposite direction it came from.
|
||||
3. Each time the ball hits a "brick" (blue, green, yellow, orange, or red), the brick disappears.
|
||||
4. When all the bricks in level 01 have been destroyed, new ones appear (in the same position as the previous one), and the ball's speed increases.
|
||||
5. When all the bricks in level 02 have been destroyed, the game continues without obstacles on the screen.
|
||||
6. The game ends when the ball falls.
|
||||
|
||||
|
||||
1. The platform moves left or right, according to the user's command. When it reaches an end, it hits the "wall" (edge).
|
||||
2. When the ball hits the platform, it returns in the opposite direction it came from.
|
||||
3. Each time the ball hits a "brick" (blue, green, yellow, orange, or red), the brick disappears.
|
||||
4. When all the bricks in level 01 have been destroyed, new ones appear (in the same position as the previous one), and the ball's speed increases.
|
||||
5. When all the bricks in level 02 have been destroyed, the game continues without obstacles on the screen.
|
||||
6. The game ends when the ball falls.
|
||||
|
||||
#### Project structure
|
||||
|
||||
* `RunBreakoutApplication.java` is the class responsible for calling the class that inherits the `GameEngine` and runs the simulator.
|
||||
* `Breakout.java` is the main class, which inherits from the `GameEngine` class and "assembles" the game, where it will call objects, define positions, etc.
|
||||
* The `sprites` package is where all the classes responsible for the sprites (e.g., the image and behavior of the blocks, platform, and ball) go.
|
||||
* The `util` packages contain classes used to facilitate project maintenance, such as constants, image initialization, and colors.
|
||||
|
||||
|
||||
* RunBreakoutApplication.java is the class responsible for calling the class that inherits the `GameEngine` and runs the simulator.
|
||||
* Breakout.java is the main class, which inherits from the `GameEngine` class and "assembles" the game, where it will call objects, define positions, etc.
|
||||
* The `sprites` package is where all the classes responsible for the sprites (e.g., the image and behavior of the blocks, platform, and ball) go.
|
||||
* The `util` packages contain classes used to facilitate project maintenance, such as constants, image initialization, and colors.
|
||||
|
||||
### Get hands-on with code
|
||||
|
||||
First, install the [TotalCross plugin from VSCode][11]. If you are using another [integrated development environment][12] (IDE), check TotalCross's documentation for installation instructions.
|
||||
|
||||
If you're using the plugin, just press `Ctrl`+`P`, type `totalcross`, and click `Create new project`. Fill in the requested information:
|
||||
|
||||
* `Folder name:` gameTC
|
||||
* `ArtifactId:` com.totalcross
|
||||
* `Project name:` Breakout
|
||||
* `TotalCross version:` 6.1.1 (or the most recent one)
|
||||
* `Build platforms:` -Android and -Linux_arm (select the platforms you want)
|
||||
First, install the [TotalCross plugin from VSCode][12]. If you are using another [integrated development environment][13] (IDE), check TotalCross's documentation for installation instructions.
|
||||
|
||||
If you're using the plugin, just press `Ctrl` +`P`, type `totalcross`, and click `Create new project`. Fill in the requested information:
|
||||
|
||||
* Folder name: gameTC
|
||||
* ArtifactId: com.totalcross
|
||||
* Project name: Breakout
|
||||
* TotalCross version: 6.1.1 (or the most recent one)
|
||||
* Build platforms: -Android and -Linux_arm (select the platforms you want)
|
||||
|
||||
When filling in the fields above and generating the project, if you are in the `RunBreakoutApplication.java` class, right-clicking on it and clicking "run" will open the simulator, and "Hello World!" will appear on your screen if you have created your Java project with TotalCross properly.
|
||||
|
||||
![HelloWorld project structure][13]
|
||||
![HelloWorld project structure][14]
|
||||
|
||||
(Vaneska Karen, [CC BY-SA 4.0][4])
|
||||
If you have a problem, check the [documentation][15] or ask the [TotalCross community][16] on Telegram for help.
|
||||
|
||||
If you have a problem, check the [documentation][14] or ask the [TotalCross community][15] on Telegram for help.
|
||||
|
||||
After the project is configured, the next step is to add the project's images in `Resources` > `Sprites`. Create two packages named `util` and `sprites` to work on later.
|
||||
After the project is configured, the next step is to add the project's images in `Resources` > `Sprites`. Create two packages named `util` and `sprites` to work on later.
|
||||
|
||||
The structure of your project will be:
|
||||
|
||||
![Project structure][16]
|
||||
|
||||
(Vaneska Karen, [CC BY-SA 4.0][4])
|
||||
![Project structure][17]
|
||||
|
||||
### Go behind the scenes
|
||||
|
||||
To make it easier to maintain the code and change the images to the colors you want to use, it's a good practice to [centralize everything by creating classes][17]. Place all of the classes for this function inside the `util` package.
|
||||
To make it easier to maintain the code and change the images to the colors you want to use, it's a good practice to [centralize everything by creating classes][18]. Place all of the classes for this function inside the `util` package.
|
||||
|
||||
#### Constants.java
|
||||
|
||||
First, create the `constants.java` class, which is where placement patterns (such as the edge between the screen and where the platform starts), speed, number of blocks, etc., reside. This is good for playing, changing numbers, and understanding where things change and why. It is a great exercise for those just starting with Java.
|
||||
|
||||
|
||||
```
|
||||
package com.totacross.util;
|
||||
|
||||
@@ -105,15 +92,15 @@ import totalcross.util.UnitsConverter;
|
||||
|
||||
public class Constants {
|
||||
//Position
|
||||
public static final int BOTTOM_EDGE = UnitsConverter.toPixels(430 + [Control][18].DP);
|
||||
public static final int DP_23 = UnitsConverter.toPixels(23 + [Control][18].DP);
|
||||
public static final int DP_50 = UnitsConverter.toPixels(50 + [Control][18].DP);
|
||||
public static final int DP_100 = UnitsConverter.toPixels(100 + [Control][18].DP);
|
||||
public static final int BOTTOM_EDGE = UnitsConverter.toPixels(430 + Control.DP);
|
||||
public static final int DP_23 = UnitsConverter.toPixels(23 + Control.DP);
|
||||
public static final int DP_50 = UnitsConverter.toPixels(50 + Control.DP);
|
||||
public static final int DP_100 = UnitsConverter.toPixels(100 + Control.DP);
|
||||
|
||||
//Sprites
|
||||
public static final int EDGE_RACKET = UnitsConverter.toPixels(20 + [Control][18].DP);
|
||||
public static final int WIDTH_BALL = UnitsConverter.toPixels(15 + [Control][18].DP);
|
||||
public static final int HEIGHT_BALL = UnitsConverter.toPixels(15 + [Control][18].DP);
|
||||
public static final int EDGE_RACKET = UnitsConverter.toPixels(20 + Control.DP);
|
||||
public static final int WIDTH_BALL = UnitsConverter.toPixels(15 + Control.DP);
|
||||
public static final int HEIGHT_BALL = UnitsConverter.toPixels(15 + Control.DP);
|
||||
|
||||
//Bricks
|
||||
public static final int NUM_BRICKS = 10;
|
||||
@@ -136,7 +123,6 @@ If you want to know more about the pixel density (DP) unit, I recommend reading
|
||||
|
||||
As the name suggests, this class is where you define the colors used in the game. I recommend naming things according to the color's purpose, such as background, font color, etc. This will make it easier to update your project's color palette in a single class.
|
||||
|
||||
|
||||
```
|
||||
package com.totacross.util;
|
||||
|
||||
@@ -152,7 +138,6 @@ public class Colors {
|
||||
|
||||
The `images.java` class is undoubtedly the most frequently used.
|
||||
|
||||
|
||||
```
|
||||
package com.totacross.util;
|
||||
|
||||
@@ -160,26 +145,27 @@ import static com.totacross.util.Constants.*;
|
||||
import totalcross.ui.dialog.MessageBox;
|
||||
import totalcross.ui.image.Image;
|
||||
|
||||
|
||||
public class Images {
|
||||
|
||||
public static [Image][20] paddle, ball;
|
||||
public static [Image][20] red, orange, dark_orange, yellow, green, blue;
|
||||
public static Image paddle, ball;
|
||||
public static Image red, orange, dark_orange, yellow, green, blue;
|
||||
|
||||
public static void loadImages() {
|
||||
try {
|
||||
// general
|
||||
paddle = new [Image][20]("sprites/paddle.png");
|
||||
ball = new [Image][20]("sprites/ball.png").getScaledInstance(WIDTH_BALL, HEIGHT_BALL);
|
||||
paddle = new Image("sprites/paddle.png");
|
||||
ball = new Image("sprites/ball.png").getScaledInstance(WIDTH_BALL, HEIGHT_BALL);
|
||||
|
||||
// Bricks
|
||||
red = new [Image][20]("sprites/red_brick.png").getScaledInstance(WIDTH_BRICKS, HEIGHT_BRICKS);
|
||||
orange = new [Image][20]("sprites/orange_brick.png").getScaledInstance(WIDTH_BRICKS, HEIGHT_BRICKS);
|
||||
dark_orange = new [Image][20]("sprites/orange2_brick.png").getScaledInstance(WIDTH_BRICKS, HEIGHT_BRICKS);
|
||||
yellow = new [Image][20]("sprites/yellow_brick.png").getScaledInstance(WIDTH_BRICKS, HEIGHT_BRICKS);
|
||||
green = new [Image][20]("sprites/green_brick.png").getScaledInstance(WIDTH_BRICKS, HEIGHT_BRICKS);
|
||||
blue = new [Image][20]("sprites/blue_brick.png").getScaledInstance(WIDTH_BRICKS, HEIGHT_BRICKS);
|
||||
red = new Image("sprites/red_brick.png").getScaledInstance(WIDTH_BRICKS, HEIGHT_BRICKS);
|
||||
orange = new Image("sprites/orange_brick.png").getScaledInstance(WIDTH_BRICKS, HEIGHT_BRICKS);
|
||||
dark_orange = new Image("sprites/orange2_brick.png").getScaledInstance(WIDTH_BRICKS, HEIGHT_BRICKS);
|
||||
yellow = new Image("sprites/yellow_brick.png").getScaledInstance(WIDTH_BRICKS, HEIGHT_BRICKS);
|
||||
green = new Image("sprites/green_brick.png").getScaledInstance(WIDTH_BRICKS, HEIGHT_BRICKS);
|
||||
blue = new Image("sprites/blue_brick.png").getScaledInstance(WIDTH_BRICKS, HEIGHT_BRICKS);
|
||||
|
||||
} catch ([Exception][21] e) {
|
||||
} catch (Exception e) {
|
||||
MessageBox.showException(e, true);
|
||||
}
|
||||
}
|
||||
@@ -192,9 +178,7 @@ The `getScaledInstance()` method will manipulate the image to match the values p
|
||||
|
||||
At this point, your project should look like this:
|
||||
|
||||
![Project structure][22]
|
||||
|
||||
(Vaneska Karen, [CC BY-SA 4.0][4])
|
||||
![Project structure][20]
|
||||
|
||||
### Create your first sprite
|
||||
|
||||
@@ -202,11 +186,10 @@ Now that the project is structured properly, you're ready to create your first c
|
||||
|
||||
#### Paddle.java
|
||||
|
||||
The `paddle.java` class must inherit from `sprite`, which is the class responsible for objects in games. This is a fundamental concept in game engine development, so when inheriting from sprites, the TotalCross framework will already be concerned with delimiting movement within the screen, detecting collisions between sprites, and other important functions. You can check all the details in [Javadoc][23].
|
||||
The `paddle.java` class must inherit from `sprite`, which is the class responsible for objects in games. This is a fundamental concept in game engine development, so when inheriting from sprites, the TotalCross framework will already be concerned with delimiting movement within the screen, detecting collisions between sprites, and other important functions. You can check all the details in [Javadoc][21].
|
||||
|
||||
In Breakout, the paddle moves on the X-axis at a speed determined by the user's command (by touch screen or mouse movement). The `paddle.java` class is responsible for defining this movement and the sprite's image (the "face"):
|
||||
|
||||
|
||||
```
|
||||
package com.totacross.sprites;
|
||||
|
||||
@@ -218,7 +201,7 @@ import totalcross.ui.image.ImageException;
|
||||
public class Paddle extends Sprite {
|
||||
private static final int SPEED = 4;
|
||||
|
||||
public Paddle() throws [IllegalArgumentException][24], [IllegalStateException][25], ImageException {
|
||||
public Paddle() throws IllegalArgumentException, IllegalStateException, ImageException {
|
||||
super(Images.paddle, -1, true, null);
|
||||
}
|
||||
|
||||
@@ -235,7 +218,7 @@ public class Paddle extends Sprite {
|
||||
}
|
||||
```
|
||||
|
||||
You indicate the image (`Images.paddle`) within the constructor, and the `move` method (a TotalCross feature) receives the speed defined at the beginning of the class. Experiment with other values and observe what happens with the movement.
|
||||
You indicate the image (`Images.paddle` ) within the constructor, and the `move` method (a TotalCross feature) receives the speed defined at the beginning of the class. Experiment with other values and observe what happens with the movement.
|
||||
|
||||
When the paddle is moving to the left, the center of the paddle at any moment is defined as itself minus the speed, and when it's moving to the right, it's itself plus the speed. Ultimately, you define the position of the sprite on the screen.
|
||||
|
||||
@@ -247,17 +230,14 @@ When building your game engine, you need to focus on some standard points. For t
|
||||
|
||||
Basically, you will delete the automatically generated `initUI()` method and, instead of inheriting from `MainWindow`, you will inherit it from `GameEngine`. A "red" will appear in the name of your class, so just click on the lamp or the suggestion symbol for your IDE and click `Add unimplemented methods`. This will automatically generate the `onGameInit()` method, which is responsible for the moment when the game starts, i.e., the moment the `breakout` class is called.
|
||||
|
||||
Inside the constructor, you must add the style type (`MaterialUI`) and the refresh time on the screen (`70`), and signal that the game has an interface (`gameHasUI = true;`).
|
||||
Inside the constructor, you must add the style type (`MaterialUI` ) and the refresh time on the screen (`70` ), and signal that the game has an interface (`gameHasUI = true;` ).
|
||||
|
||||
Last but not least, you have to start the game through `this.start()` on `onGameInit()` and focus on some other methods:
|
||||
|
||||
* `onGameInit()` is the first method called. In it, you must initialize the sprites and images (`Images.loadImages`), and tell the game that it can start.
|
||||
* `onGameStart()`is called when the game starts. It sets the platform's initial position (in the center of the screen on the X-axis and below the center with a border on the Y-axis).
|
||||
* `onPaint()` is where you say what will be drawn for each frame. First, it paints the background black (to not leave traces of the sprites), then it displays the sprites with `.show()`.
|
||||
* The `onPenDrag` and `onPenDown` methods identify when the user moves the paddle (by dragging a finger on a touch screen or moving the mouse while pressing the left button). These methods change the paddle movement through the `setPos()` method, which triggers the `move` method in the `Paddle.java` class. Note that the last parameter of the `racket.setPos` method is `true` to precisely limit the paddle's movement within the screen so that it never disappears from the user's field of view.
|
||||
|
||||
|
||||
|
||||
* onGameInit() is the first method called. In it, you must initialize the sprites and images (Images.loadImages), and tell the game that it can start.
|
||||
* onGameStart()is called when the game starts. It sets the platform's initial position (in the center of the screen on the X-axis and below the center with a border on the Y-axis).
|
||||
* onPaint() is where you say what will be drawn for each frame. First, it paints the background black (to not leave traces of the sprites), then it displays the sprites with `.show()`.
|
||||
* The `onPenDrag` and `onPenDown` methods identify when the user `move`s the paddle (by dragging a finger on a touch screen or moving the mouse while pressing the left button). These methods change the paddle movement through the `setPos()` method, which triggers the move method in the `Paddle.java` class. Note that the last parameter of the `racket.setPos` method is `true` to precisely limit the paddle's movement within the screen so that it never disappears from the user's field of view.
|
||||
|
||||
```
|
||||
package com.totacross;
|
||||
@@ -295,7 +275,7 @@ public class Breakout extends GameEngine {
|
||||
try {
|
||||
racket = new Paddle();
|
||||
|
||||
} catch ([Exception][21] e) {
|
||||
} catch (Exception e) {
|
||||
MessageBox.showException(e, true);
|
||||
MainWindow.exit(0);
|
||||
}
|
||||
@@ -307,7 +287,7 @@ public class Breakout extends GameEngine {
|
||||
|
||||
//to draw the interface
|
||||
@Override
|
||||
public void onPaint([Graphics][26] g) {
|
||||
public void onPaint(Graphics g) {
|
||||
super.onPaint(g);
|
||||
if (gameIsRunning) {
|
||||
g.backColor = Colors.PRIMARY;
|
||||
@@ -339,71 +319,64 @@ public class Breakout extends GameEngine {
|
||||
|
||||
To run the game, just click `RunBreakoutApplication.java` with the right mouse button, then click `run` to see how it looks.
|
||||
|
||||
![Breakout game remake on phone][27]
|
||||
|
||||
(Vaneska Karen, [CC BY-SA 4.0][4])
|
||||
![Breakout game remake][22]
|
||||
|
||||
If you want to run it on a Raspberry Pi, change the parameters in the `RunBreakoutApplication.java` class to:
|
||||
|
||||
|
||||
```
|
||||
` TotalCrossApplication.run(Breakout.class, "/scr", "848x480");`
|
||||
TotalCrossApplication.run(Breakout.class, "/scr", "848x480");
|
||||
```
|
||||
|
||||
This sets the screen size to match the Raspberry Pi.
|
||||
|
||||
![Breakout on Raspberry Pi][28]
|
||||
|
||||
(Vaneska Karen, [CC BY-SA 4.0][4])
|
||||
![Breakout on Raspberry Pi][23]
|
||||
|
||||
The first sprite and game mechanics are ready!
|
||||
|
||||
### Next steps
|
||||
|
||||
In the next article, I'll show how to add the ball sprite and make collisions. If you need help, call me in the [community group][15] on Telegram or post in the TotalCross [forum][29], where I'm available to help.
|
||||
In the next article, I'll show how to add the ball sprite and make collisions. If you need help, call me in the [community group][24] on Telegram or post in the TotalCross [forum][25], where I'm available to help.
|
||||
|
||||
If you put this article into practice, share your experience in the comments. All feedback is important! If you wish, favorite [TotalCross on GitHub][30], as it improves the project's relevance on the platform.
|
||||
If you put this article into practice, share your experience in the comments. All feedback is important! If you wish, favorite [TotalCross on GitHub][26], as it improves the project's relevance on the platform.
|
||||
|
||||
Image by: (Vaneska Karen, CC BY-SA 4.0)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/3/java-object-orientation
|
||||
|
||||
作者:[Vaneska Sousa][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/vaneska
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/studying-books-java-couch-education.png?itok=C9gasCXr (Learning and studying technology is the key to success)
|
||||
[2]: https://www.youtube.com/watch?v=Cr6z3AyhRr8
|
||||
[3]: https://opensource.com/sites/default/files/uploads/originalbreakout.gif (Breakout game)
|
||||
[4]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[5]: https://processing.org/
|
||||
[6]: https://opensource.com/resources/java
|
||||
[7]: https://opensource.com/article/20/7/totalcross-cross-platform-development
|
||||
[8]: https://www.arm.linux.org.uk/docs/whatis.php
|
||||
[9]: https://opensource.com/resources/raspberry-pi
|
||||
[10]: https://opensource.com/sites/default/files/uploads/breakoutremake.gif (Breakout remake)
|
||||
[11]: https://marketplace.visualstudio.com/items?itemName=totalcross.vscode-totalcross
|
||||
[12]: https://www.redhat.com/en/topics/middleware/what-is-ide
|
||||
[13]: https://opensource.com/sites/default/files/uploads/helloworld.png (HelloWorld project structure)
|
||||
[14]: https://learn.totalcross.com/
|
||||
[15]: https://t.me/guiforembedded
|
||||
[16]: https://opensource.com/sites/default/files/uploads/projectstructure.png (Project structure)
|
||||
[17]: https://learn.totalcross.com/documentation/guides/app-architecture/colors-fonts-and-images
|
||||
[18]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+control
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/studying-books-java-couch-education.png
|
||||
[2]: https://www.wocintechchat.com/
|
||||
[3]: https://creativecommons.org/licenses/by/2.0/
|
||||
[4]: https://www.youtube.com/watch?v=Cr6z3AyhRr8
|
||||
[5]: https://opensource.com/sites/default/files/uploads/originalbreakout.gif
|
||||
[6]: https://processing.org/
|
||||
[7]: https://opensource.com/resources/java
|
||||
[8]: https://opensource.com/article/20/7/totalcross-cross-platform-development
|
||||
[9]: https://www.arm.linux.org.uk/docs/whatis.php
|
||||
[10]: https://opensource.com/resources/raspberry-pi
|
||||
[11]: https://opensource.com/sites/default/files/uploads/breakoutremake.gif
|
||||
[12]: https://marketplace.visualstudio.com/items?itemName=totalcross.vscode-totalcross
|
||||
[13]: https://www.redhat.com/en/topics/middleware/what-is-ide
|
||||
[14]: https://opensource.com/sites/default/files/uploads/helloworld.png
|
||||
[15]: https://learn.totalcross.com/
|
||||
[16]: https://t.me/guiforembedded
|
||||
[17]: https://opensource.com/sites/default/files/uploads/projectstructure.png
|
||||
[18]: https://learn.totalcross.com/documentation/guides/app-architecture/colors-fonts-and-images
|
||||
[19]: https://material.io/design/layout/pixel-density.html
|
||||
[20]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+image
|
||||
[21]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+exception
|
||||
[22]: https://opensource.com/sites/default/files/uploads/projectstructure2.png (Project structure)
|
||||
[23]: https://en.wikipedia.org/wiki/Javadoc
|
||||
[24]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+illegalargumentexception
|
||||
[25]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+illegalstateexception
|
||||
[26]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+graphics
|
||||
[27]: https://opensource.com/sites/default/files/uploads/runbreakout.gif (Breakout game remake on phone)
|
||||
[28]: https://opensource.com/sites/default/files/uploads/runbreakout2.gif (Breakout on Raspberry Pi)
|
||||
[29]: http://forum.totalcross.com
|
||||
[30]: https://github.com/totalcross/totalcross
|
||||
[20]: https://opensource.com/sites/default/files/uploads/projectstructure2.png
|
||||
[21]: https://en.wikipedia.org/wiki/Javadoc
|
||||
[22]: https://opensource.com/sites/default/files/uploads/runbreakout.gif
|
||||
[23]: https://opensource.com/sites/default/files/uploads/runbreakout2.gif
|
||||
[24]: https://t.me/guiforembedded
|
||||
[25]: http://forum.totalcross.com
|
||||
[26]: https://github.com/totalcross/totalcross
|
||||
@@ -1,50 +1,44 @@
|
||||
[#]: subject: (Host your website with dynamic content and a database on a Raspberry Pi)
|
||||
[#]: via: (https://opensource.com/article/21/3/web-hosting-raspberry-pi)
|
||||
[#]: author: (Marty Kalin https://opensource.com/users/mkalindepauledu)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: "Host your website with dynamic content and a database on a Raspberry Pi"
|
||||
[#]: via: "https://opensource.com/article/21/3/web-hosting-raspberry-pi"
|
||||
[#]: author: "Marty Kalin https://opensource.com/users/mkalindepauledu"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Host your website with dynamic content and a database on a Raspberry Pi
|
||||
======
|
||||
You can use free software to support a web application on a very
|
||||
lightweight computer.
|
||||
You can use free software to support a web application on a very lightweight computer.
|
||||
|
||||
![Digital creative of a browser on the internet][1]
|
||||
|
||||
Raspberry Pi's single-board machines have set the mark for cheap, real-world computing. With its model 4, the Raspberry Pi can host web applications with a production-grade web server, a transactional database system, and dynamic content through scripting. This article explains the installation and configuration details with a full code example. Welcome to web applications hosted on a very lightweight computer.
|
||||
|
||||
### The snowfall application
|
||||
|
||||
Imagine a downhill ski area large enough to have microclimates, which can mean dramatically different snowfalls across the area. The area is divided into regions, each of which has devices that record snowfall in centimeters; the recorded information then guides decisions on snowmaking, grooming, and other maintenance operations. The devices communicate, say, every 20 minutes with a server that updates a database that supports reports. Nowadays, the server-side software for such an application can be free _and_ production-grade.
|
||||
Imagine a downhill ski area large enough to have microclimates, which can mean dramatically different snowfalls across the area. The area is divided into regions, each of which has devices that record snowfall in centimeters; the recorded information then guides decisions on snowmaking, grooming, and other maintenance operations. The devices communicate, say, every 20 minutes with a server that updates a database that supports reports. Nowadays, the server-side software for such an application can be free *and* production-grade.
|
||||
|
||||
This snowfall application uses the following technologies:
|
||||
|
||||
* A [Raspberry Pi 4][2] running Debian
|
||||
* Nginx web server: The free version hosts over 400 million websites. This web server is easy to install, configure, and use.
|
||||
* [SQLite relational database system][3], which is file-based: A database, which can hold many tables, is a file on the local system. SQLite is lightweight but also [ACID-compliant][4]; it is suited for low to moderate volume. SQLite is likely the most widely used database system in the world, and the source code for SQLite is in the public domain. The current version is 3. A more powerful (but still free) option is PostgreSQL.
|
||||
* Python: The Python programming language can interact with databases such as SQLite and web servers such as Nginx. Python (version 3) comes with Linux and macOS systems.
|
||||
|
||||
|
||||
* A [Raspberry Pi 4][2] running Debian
|
||||
* Nginx web server: The free version hosts over 400 million websites. This web server is easy to install, configure, and use.
|
||||
* [SQLite relational database system][3], which is file-based: A database, which can hold many tables, is a file on the local system. SQLite is lightweight but also [ACID-compliant][4]; it is suited for low to moderate volume. SQLite is likely the most widely used database system in the world, and the source code for SQLite is in the public domain. The current version is 3. A more powerful (but still free) option is PostgreSQL.
|
||||
* Python: The Python programming language can interact with databases such as SQLite and web servers such as Nginx. Python (version 3) comes with Linux and macOS systems.
|
||||
|
||||
Python includes a software driver for communicating with SQLite. There are options for connecting Python scripts with Nginx and other web servers. One option is [uWSGI][5] (Web Server Gateway Interface), which updates the ancient CGI (Common Gateway Interface) from the 1990s.
|
||||
|
||||
Several factors speak for uWSGI:
|
||||
|
||||
* uWSGI is flexible. It can be used as either a lightweight concurrent web server or the backend application server connected to a web server such as Nginx.
|
||||
* Its setup is minimal.
|
||||
* The snowfall application involves a low to moderate volume of hits on the web server and database system. In general, CGI technologies are not fast by modern standards, but CGI performs well enough for department-level web applications such as this one.
|
||||
|
||||
|
||||
* uWSGI is flexible. It can be used as either a lightweight concurrent web server or the backend application server connected to a web server such as Nginx.
|
||||
* Its setup is minimal.
|
||||
* The snowfall application involves a low to moderate volume of hits on the web server and database system. In general, CGI technologies are not fast by modern standards, but CGI performs well enough for department-level web applications such as this one.
|
||||
|
||||
Various acronyms describe the uWSGI option. Here's a sketch of the three principal ones:
|
||||
|
||||
* **WSGI** is a Python specification for an interface between a web server on one side, and an application or an application framework (e.g., Django) on the other side. This specification defines an API whose implementation is left open.
|
||||
* **uWSGI** implements the WSGI interface by providing an application server, which connects applications to a web server. A uWSGI application server's main job is to translate HTTP requests into a format that a web application can consume and, afterward, to format the application's response into an HTTP message.
|
||||
* **uwsgi** is a binary protocol implemented by a uWSGI application server to communicate with a full-featured web server such as Nginx; it also includes utilities such as a lightweight web server. The Nginx web server "speaks" uwsgi out of the box.
|
||||
|
||||
|
||||
* WSGI is a Python specification for an interface between a web server on one side, and an application or an application framework (e.g., Django) on the other side. This specification defines an API whose implementation is left open.
|
||||
* uWSGI implements the WSGI interface by providing an application server, which connects applications to a web server. A uWSGI application server's main job is to translate HTTP requests into a format that a web application can consume and, afterward, to format the application's response into an HTTP message.
|
||||
* uwsgi is a binary protocol implemented by a uWSGI application server to communicate with a full-featured web server such as Nginx; it also includes utilities such as a lightweight web server. The Nginx web server "speaks" uwsgi out of the box.
|
||||
|
||||
For convenience, I will use "uwsgi" as shorthand for the binary protocol, the application server, and the very lightweight web server.
|
||||
|
||||
@@ -52,33 +46,29 @@ For convenience, I will use "uwsgi" as shorthand for the binary protocol, the ap
|
||||
|
||||
On a Debian-based system, you can install SQLite the usual way (with `%` representing the command-line prompt):
|
||||
|
||||
|
||||
```
|
||||
`% sudo apt-get install sqlite3`
|
||||
% sudo apt-get install sqlite3
|
||||
```
|
||||
|
||||
This database system is a collection of C libraries and utilities, all of which come to about 500KB in size. There is no database server to start, stop, or otherwise maintain.
|
||||
|
||||
Once SQLite is installed, create a database at the command-line prompt:
|
||||
|
||||
|
||||
```
|
||||
`% sqlite3 snowfall.db`
|
||||
% sqlite3 snowfall.db
|
||||
```
|
||||
|
||||
If this succeeds, the command creates the file `snowfall.db` in the current working directory. The database name is arbitrary (e.g., no extension is required), and the command opens the SQLite client utility with `>sqlite` as the prompt:
|
||||
|
||||
|
||||
```
|
||||
Enter ".help" for usage hints.
|
||||
sqlite>
|
||||
sqlite>
|
||||
```
|
||||
|
||||
Create the snowfall table in the snowfall database with the following command. The table name, like the database name, is arbitrary:
|
||||
|
||||
|
||||
```
|
||||
sqlite> CREATE TABLE snowfall (id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
sqlite> CREATE TABLE snowfall (id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
region TEXT NOT NULL,
|
||||
device TEXT NOT NULL,
|
||||
amount DECIMAL NOT NULL,
|
||||
@@ -87,9 +77,8 @@ sqlite> CREATE TABLE snowfall (id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
|
||||
SQLite commands are case-insensitive, but it is traditional to use uppercase for SQL terms and lowercase for user terms. Check that the table was created:
|
||||
|
||||
|
||||
```
|
||||
`sqlite> .schema`
|
||||
sqlite> .schema
|
||||
```
|
||||
|
||||
The command echoes the `CREATE TABLE` statement.
|
||||
@@ -100,10 +89,9 @@ The database is now ready for business, although the single-table snowfall is em
|
||||
|
||||
Recall that uwsgi can be used in two ways: either as a lightweight web server or as an application server connected to a production-grade web server such as Nginx. The second use is the goal, but the first is suited for developing and testing the programmer's request-handling code. Here's the architecture with Nginx in play as the web server:
|
||||
|
||||
|
||||
```
|
||||
HTTP uwsgi
|
||||
client<\---->Nginx<\----->appServer<\--->request-handling code<\--->SQLite
|
||||
HTTP uwsgi
|
||||
client<---->Nginx<----->appServer<--->request-handling code<--->SQLite
|
||||
```
|
||||
|
||||
The client could be a browser, a utility such as [curl][6], or a hand-crafted program fluent in HTTP. Communications between the client and Nginx occur through HTTP, but then uwsgi takes over as a binary-transport protocol between Nginx and the application server, which interacts with request-handling code such as `requestHandler.py` (described below). This architecture delivers a clean division of labor. Nginx alone manages the client, and only the request-handling code interacts with the database. In turn, the application server separates the web server from the programmer-written code, which has a high-level API to read and write HTTP messages delivered over uwsgi.
|
||||
@@ -116,7 +104,6 @@ Below is the source code file `requestHandler.py` for the snowfall application.
|
||||
|
||||
#### The request-handling program
|
||||
|
||||
|
||||
```
|
||||
import sqlite3
|
||||
import cgi
|
||||
@@ -127,7 +114,7 @@ PATH_2_DB = '/home/marty/wsgi/snowfall.db'
|
||||
def application(env, start_line):
|
||||
if env['REQUEST_METHOD'] == 'POST': ## add new DB record
|
||||
return handle_post(env, start_line)
|
||||
elif env['REQUEST_METHOD'] == 'GET': ## create HTML-fragment report
|
||||
elif env['REQUEST_METHOD'] == 'GET': ## create HTML-fragment report
|
||||
return handle_get(start_line)
|
||||
else: ## no other option for now
|
||||
start_line('405 METHOD NOT ALLOWED', [('Content-Type', 'text/plain')])
|
||||
@@ -136,7 +123,7 @@ def application(env, start_line):
|
||||
|
||||
def handle_post(env, start_line):
|
||||
form = get_field_storage(env) ## body of an HTTP POST request
|
||||
|
||||
|
||||
## Extract fields from POST form.
|
||||
region = form.getvalue('region')
|
||||
device = form.getvalue('device')
|
||||
@@ -162,19 +149,19 @@ def handle_get(start_line):
|
||||
cursor = conn.cursor() ## get a cursor
|
||||
cursor.execute("select * from snowfall")
|
||||
|
||||
response_body = "<h3>Snowfall report</h3><ul>"
|
||||
response_body = "<h3>Snowfall report</h3><ul>"
|
||||
rows = cursor.fetchall()
|
||||
for row in rows:
|
||||
response_body += "<li>" + str(row[0]) + '|' ## primary key
|
||||
response_body += "<li>" + str(row[0]) + '|' ## primary key
|
||||
response_body += row[1] + '|' ## region
|
||||
response_body += row[2] + '|' ## device
|
||||
response_body += str(row[3]) + '|' ## amount
|
||||
response_body += str(row[4]) + "</li>" ## timestamp
|
||||
response_body += "</ul>"
|
||||
response_body += str(row[4]) + "</li>" ## timestamp
|
||||
response_body += "</ul>"
|
||||
|
||||
conn.commit() ## commit
|
||||
conn.close() ## cleanup
|
||||
|
||||
|
||||
start_line('200 OK', [('Content-Type', 'text/html')])
|
||||
return [response_body.encode()]
|
||||
|
||||
@@ -184,7 +171,7 @@ def add_record(reg, dev, amt, tstamp):
|
||||
cursor = conn.cursor() ## get a cursor
|
||||
|
||||
sql = "INSERT INTO snowfall(region,device,amount,tstamp) values (?,?,?,?)"
|
||||
cursor.execute(sql, (reg, dev, amt, tstamp)) ## execute INSERT
|
||||
cursor.execute(sql, (reg, dev, amt, tstamp)) ## execute INSERT
|
||||
|
||||
conn.commit() ## commit
|
||||
conn.close() ## cleanup
|
||||
@@ -203,16 +190,14 @@ def get_field_storage(env):
|
||||
|
||||
A constant at the start of the source file defines the path to the database file:
|
||||
|
||||
|
||||
```
|
||||
`PATH_2_DB = '/home/marty/wsgi/snowfall.db'`
|
||||
PATH_2_DB = '/home/marty/wsgi/snowfall.db'
|
||||
```
|
||||
|
||||
Make sure to update the path for your Raspberry Pi.
|
||||
|
||||
As noted earlier, uwsgi includes a lightweight web server that can host this request-handling application. To begin, install uwsgi with these two commands (`##` introduces my comments):
|
||||
|
||||
|
||||
```
|
||||
% sudo apt-get install build-essential python-dev ## C header files, etc.
|
||||
% pip install uwsgi ## pip = Python package manager
|
||||
@@ -220,19 +205,17 @@ As noted earlier, uwsgi includes a lightweight web server that can host this req
|
||||
|
||||
Next, launch a bare-bones snowfall application using uwsgi as the web server:
|
||||
|
||||
|
||||
```
|
||||
`% uwsgi --http 127.0.0.1:9999 --wsgi-file requestHandler.py `
|
||||
% uwsgi --http 127.0.0.1:9999 --wsgi-file requestHandler.py
|
||||
```
|
||||
|
||||
The flag `--http` runs uwsgi in web-server mode, with 9999 as the web server's listening port on localhost (127.0.0.1). By default, uwsgi dispatches HTTP requests to a programmer-defined function named `application`. For review, here's the full function from the top of the `requestHandler.py` code:
|
||||
|
||||
|
||||
```
|
||||
def application(env, start_line):
|
||||
if env['REQUEST_METHOD'] == 'POST': ## add new DB record
|
||||
return handle_post(env, start_line)
|
||||
elif env['REQUEST_METHOD'] == 'GET': ## create HTML-fragment report
|
||||
elif env['REQUEST_METHOD'] == 'GET': ## create HTML-fragment report
|
||||
return handle_get(start_line)
|
||||
else: ## no other option for now
|
||||
start_line('405 METHOD NOT ALLOWED', [('Content-Type', 'text/plain')])
|
||||
@@ -242,25 +225,21 @@ def application(env, start_line):
|
||||
|
||||
The snowfall application accepts only two request types:
|
||||
|
||||
* A POST request, if up to snuff, creates a new entry in the snowfall table. The request should include the ski area region, the device in the region, the snowfall amount in centimeters, and a Unix-style timestamp. A POST request is dispatched to the `handle_post` function (which I'll clarify shortly).
|
||||
* A GET request returns an HTML fragment (an unordered list) with the records currently in the snowfall table.
|
||||
|
||||
|
||||
* A POST request, if up to snuff, creates a new entry in the snowfall table. The request should include the ski area region, the device in the region, the snowfall amount in centimeters, and a Unix-style timestamp. A POST request is dispatched to the `handle_post` function (which I'll clarify shortly).
|
||||
* A GET request returns an HTML fragment (an unordered list) with the records currently in the snowfall table.
|
||||
|
||||
Requests with an HTTP verb other than POST and GET will generate an error message.
|
||||
|
||||
You can use a utility such as curl to generate HTTP requests for testing. Here are three sample POST requests to start populating the database:
|
||||
|
||||
|
||||
```
|
||||
% curl -X POST -d "region=R1&device=D9&amount=1.42&tstamp=1604722088.0158753" localhost:9999/
|
||||
% curl -X POST -d "region=R7&device=D4&amount=2.11&tstamp=1604722296.8862638" localhost:9999/
|
||||
% curl -X POST -d "region=R5&device=D1&amount=1.12&tstamp=1604942236.1013834" localhost:9999/
|
||||
% curl -X POST -d "region=R1&device=D9&amount=1.42&tstamp=1604722088.0158753" localhost:9999/
|
||||
% curl -X POST -d "region=R7&device=D4&amount=2.11&tstamp=1604722296.8862638" localhost:9999/
|
||||
% curl -X POST -d "region=R5&device=D1&amount=1.12&tstamp=1604942236.1013834" localhost:9999/
|
||||
```
|
||||
|
||||
These commands add three records to the snowfall table. A subsequent GET request from curl or a browser displays an HTML fragment that lists the rows in the snowfall table. Here's the equivalent as non-HTML text:
|
||||
|
||||
|
||||
```
|
||||
Snowfall report
|
||||
|
||||
@@ -273,20 +252,18 @@ A professional report would convert the numeric timestamps into human-readable o
|
||||
|
||||
The uwsgi utility accepts various flags, which can be given either through a configuration file or in the launch command. For example, here's a richer launch of uwsgi as a web server:
|
||||
|
||||
|
||||
```
|
||||
`% uwsgi --master --processes 2 --http 127.0.0.1:9999 --wsgi-file requestHandler.py`
|
||||
% uwsgi --master --processes 2 --http 127.0.0.1:9999 --wsgi-file requestHandler.py
|
||||
```
|
||||
|
||||
This version creates a master (supervisory) process and two worker processes, which can handle the HTTP requests concurrently.
|
||||
|
||||
In the snowfall application, the functions `handle_post` and `handle_get` process POST and GET requests, respectively. Here's the `handle_post` function in full:
|
||||
|
||||
|
||||
```
|
||||
def handle_post(env, start_line):
|
||||
form = get_field_storage(env) ## body of an HTTP POST request
|
||||
|
||||
|
||||
## Extract fields from POST form.
|
||||
region = form.getvalue('region')
|
||||
device = form.getvalue('device')
|
||||
@@ -308,18 +285,17 @@ def handle_post(env, start_line):
|
||||
return [response_body.encode()]
|
||||
```
|
||||
|
||||
The two arguments to the `handle_post` function (`env` and `start_line`) represent the system environment and a communications channel, respectively. The `start_line` channel sends the HTTP start line (in this case, either `400 Bad Request` or `201 OK`) and any HTTP headers (in this case, just `Content-Type: text/plain`) of an HTTP response.
|
||||
The two arguments to the `handle_post` function (`env` and `start_line` ) represent the system environment and a communications channel, respectively. The `start_line` channel sends the HTTP start line (in this case, either `400 Bad Request` or `201 OK` ) and any HTTP headers (in this case, just `Content-Type: text/plain` ) of an HTTP response.
|
||||
|
||||
The `handle_post` function tries to extract the relevant data from the HTTP POST request and, if it's successful, calls the function `add_record` to add another row to the snowfall table:
|
||||
|
||||
|
||||
```
|
||||
def add_record(reg, dev, amt, tstamp):
|
||||
conn = sqlite3.connect(PATH_2_DB) ## connect to DB
|
||||
cursor = conn.cursor() ## get a cursor
|
||||
|
||||
sql = "INSERT INTO snowfall(region,device,amount,tstamp) VALUES (?,?,?,?)"
|
||||
cursor.execute(sql, (reg, dev, amt, tstamp)) ## execute INSERT
|
||||
cursor.execute(sql, (reg, dev, amt, tstamp)) ## execute INSERT
|
||||
|
||||
conn.commit() ## commit
|
||||
conn.close() ## cleanup
|
||||
@@ -329,26 +305,25 @@ SQLite automatically wraps single SQL statements (such as `INSERT` above) in a t
|
||||
|
||||
The `handle_get` function also touches the database, but only to read the records in the snowfall table:
|
||||
|
||||
|
||||
```
|
||||
def handle_get(start_line):
|
||||
conn = sqlite3.connect(PATH_2_DB) ## connect to DB
|
||||
cursor = conn.cursor() ## get a cursor
|
||||
cursor.execute("SELECT * FROM snowfall")
|
||||
|
||||
response_body = "<h3>Snowfall report</h3><ul>"
|
||||
response_body = "<h3>Snowfall report</h3><ul>"
|
||||
rows = cursor.fetchall()
|
||||
for row in rows:
|
||||
response_body += "<li>" + str(row[0]) + '|' ## primary key
|
||||
response_body += "<li>" + str(row[0]) + '|' ## primary key
|
||||
response_body += row[1] + '|' ## region
|
||||
response_body += row[2] + '|' ## device
|
||||
response_body += str(row[3]) + '|' ## amount
|
||||
response_body += str(row[4]) + "</li>" ## timestamp
|
||||
response_body += "</ul>"
|
||||
response_body += str(row[4]) + "</li>" ## timestamp
|
||||
response_body += "</ul>"
|
||||
|
||||
conn.commit() ## commit
|
||||
conn.close() ## cleanup
|
||||
|
||||
|
||||
start_line('200 OK', [('Content-Type', 'text/html')])
|
||||
return [response_body.encode()]
|
||||
```
|
||||
@@ -359,28 +334,25 @@ A user-friendly version of the snowfall application would support additional (an
|
||||
|
||||
The Nginx web server can be installed on a Debian-based system with one command:
|
||||
|
||||
|
||||
```
|
||||
`% sudo apt-get install nginx`
|
||||
% sudo apt-get install nginx
|
||||
```
|
||||
|
||||
As a web server, Nginx provides the expected services, such as wire-level security, HTTPS, user authentication, load balancing, media streaming, response compression, file uploading, etc. The Nginx engine is high-performance and stable, and this server can support dynamic content through a variety of programming languages. Using uwsgi as a very lightweight web server is an attractive option but switching to Nginx is a move up to industrial-strength web hosting with high-volume capability. Nginx and uwsgi are both implemented in C.
|
||||
|
||||
With Nginx in play, uwsgi takes on a communication protocol's restricted roles and an application server; it no longer acts as an HTTP web server. Here's the revised architecture:
|
||||
|
||||
|
||||
```
|
||||
HTTP uwsgi
|
||||
requester<\---->Nginx<\----->app server<\--->requestHandler.py
|
||||
HTTP uwsgi
|
||||
requester<---->Nginx<----->app server<--->requestHandler.py
|
||||
```
|
||||
|
||||
As noted earlier, Nginx includes uwsgi support and now acts as a reverse-proxy server that forwards designated HTTP requests to the uwsgi application server, which in turn interacts with the Python script `requestHandler.py`. Responses from the Python script move in the reverse direction so that Nginx sends the HTTP response back to the requesting client.
|
||||
|
||||
Two changes bring this new architecture to life. The first launches uwsgi as an application server:
|
||||
|
||||
|
||||
```
|
||||
`% uwsgi --socket 127.0.0.1:8001 --wsgi-file requestHandler.py`
|
||||
% uwsgi --socket 127.0.0.1:8001 --wsgi-file requestHandler.py
|
||||
```
|
||||
|
||||
Socket 8001 is the Nginx default for uwsgi communications. For robustness, you could use the full path to the Python script so that the command above does not have to be executed in the directory that houses the Python script. In a production environment, uwsgi would start and stop automatically; for now, however, the emphasis remains on how the architectural pieces fit together.
|
||||
@@ -389,7 +361,6 @@ The second change involves Nginx configuration, which can be tricky on Debian-ba
|
||||
|
||||
However the configuration is distributed, the key section for having Nginx talk to the uwsgi application server begins with `http` and has one or more `server` subsections, which in turn have `location` subsections. Here's an example from the Nginx documentation:
|
||||
|
||||
|
||||
```
|
||||
...
|
||||
http {
|
||||
@@ -397,7 +368,7 @@ http {
|
||||
...
|
||||
server { # simple reverse-proxy
|
||||
listen 80;
|
||||
server_name domain2.com [www.domain2.com][8];
|
||||
server_name domain2.com www.domain2.com;
|
||||
access_log logs/domain2.access.log main;
|
||||
|
||||
# serve static files
|
||||
@@ -408,7 +379,7 @@ http {
|
||||
|
||||
# pass requests for dynamic content to rails/turbogears/zope, et al
|
||||
location / {
|
||||
proxy_pass <http://127.0.0.1:8080>;
|
||||
proxy_pass http://127.0.0.1:8080;
|
||||
}
|
||||
}
|
||||
...
|
||||
@@ -417,7 +388,6 @@ http {
|
||||
|
||||
The `location` subsections are the ones of interest. For the snowfall application, here's the added `location` entry with its two configuration lines:
|
||||
|
||||
|
||||
```
|
||||
...
|
||||
server {
|
||||
@@ -441,9 +411,8 @@ server {
|
||||
|
||||
To keep things simple for now, make `/snowfall` the only `location` in the configuration. With this configuration in place, Nginx listens on port 80 and dispatches HTTP requests ending with the `/snowfall` path to the uwsgi application server:
|
||||
|
||||
|
||||
```
|
||||
% curl -X POST -d "..." localhost/snowfall ## new POST
|
||||
% curl -X POST -d "..." localhost/snowfall ## new POST
|
||||
% curl -X GET localhost/snowfall ## new GET
|
||||
```
|
||||
|
||||
@@ -453,16 +422,14 @@ If the configured location were simply `/` instead of `/snowfall`, then any HTTP
|
||||
|
||||
Once you've changed the Nginx configuration with the added `location` subsection, you can start the web server:
|
||||
|
||||
|
||||
```
|
||||
`% sudo systemctl start nginx`
|
||||
% sudo systemctl start nginx
|
||||
```
|
||||
|
||||
There are other commands similar to `stop` and `restart` Nginx. In a production environment, you could automate these actions so that Nginx starts on a system boot and stops on a system shutdown.
|
||||
|
||||
With uwsgi and Nginx both running, you can use a browser to test whether the architectural components cooperate as expected. For example, if you enter the URL `localhost/` in the browser's input window, then the Nginx welcome page should appear with (HTML) content similar to this:
|
||||
|
||||
|
||||
```
|
||||
Welcome to nginx!
|
||||
...
|
||||
@@ -471,7 +438,6 @@ Thank you for using nginx.
|
||||
|
||||
By contrast, the URL `localhost/snowfall` should display the rows currently in the snowfall table:
|
||||
|
||||
|
||||
```
|
||||
Snowfall report
|
||||
|
||||
@@ -491,19 +457,18 @@ The software components in the web application work well together and require ve
|
||||
via: https://opensource.com/article/21/3/web-hosting-raspberry-pi
|
||||
|
||||
作者:[Marty Kalin][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/mkalindepauledu
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/browser_web_internet_website.png?itok=g5B_Bw62 (Digital creative of a browser on the internet)
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/browser_web_internet_website.png
|
||||
[2]: https://www.raspberrypi.org/products/raspberry-pi-4-model-b/
|
||||
[3]: https://opensource.com/article/21/2/sqlite3-cheat-sheet
|
||||
[4]: https://en.wikipedia.org/wiki/ACID
|
||||
[5]: https://uwsgi-docs.readthedocs.io/en/latest/
|
||||
[6]: https://opensource.com/article/20/5/curl-cheat-sheet
|
||||
[7]: https://condor.depaul.edu/mkalin
|
||||
[8]: http://www.domain2.com
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
[#]: subject: (Manage containers on Raspberry Pi with this open source tool)
|
||||
[#]: via: (https://opensource.com/article/21/3/bastille-raspberry-pi)
|
||||
[#]: author: (Peter Czanik https://opensource.com/users/czanik)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: "Use FreeBSD jails on Raspberry Pi"
|
||||
[#]: via: "https://opensource.com/article/21/3/bastille-raspberry-pi"
|
||||
[#]: author: "Peter Czanik https://opensource.com/users/czanik"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Manage containers on Raspberry Pi with this open source tool
|
||||
Use FreeBSD jails on Raspberry Pi
|
||||
======
|
||||
Create and maintain your containers (aka jails) at scale on FreeBSD with
|
||||
Bastille.
|
||||
Create and maintain your containers (aka jails) at scale on FreeBSD with Bastille.
|
||||
|
||||
![Parts, modules, containers for software][1]
|
||||
|
||||
Image by: Opensource.com
|
||||
|
||||
Containers became widely popular because of Docker on Linux, but there are [much earlier implementations][2], including the [jail][3] system on FreeBSD. A container is called a "jail" in FreeBSD terminology. The jail system was first released in FreeBSD 4.0 way back in 2000, and it has continuously improved since. While 20 years ago it was used mostly on large servers, now you can run it on your Raspberry Pi.
|
||||
|
||||
### Jails vs. containers on Linux
|
||||
@@ -31,19 +33,17 @@ Docker brought popularity, accessibility, and ease of use to containers. There a
|
||||
|
||||
Installing [BSD on Raspberry Pi][8] is pretty similar to installing Linux. You download a compressed image from the FreeBSD website and `dd` it to an SD card. You can also use a dedicated image writer tool; there are many available for all operating systems (OS). Download and write an image from the command line with:
|
||||
|
||||
|
||||
```
|
||||
wget <https://download.freebsd.org/ftp/releases/arm64/aarch64/ISO-IMAGES/13.0/FreeBSD-13.0-BETA1-arm64-aarch64-RPI.img.xz>
|
||||
wget https://download.freebsd.org/ftp/releases/arm64/aarch64/ISO-IMAGES/13.0/FreeBSD-13.0-BETA1-arm64-aarch64-RPI.img.xz
|
||||
xzcat FreeBSD-13.0-BETA1-arm64-aarch64-RPI.img.xz | dd of=/dev/XXX
|
||||
```
|
||||
|
||||
That writes the latest beta image available for 64-bit Raspberry Pi boards; check the [download page][9] if you use another Raspberry Pi board or want to use another build. Replace `XXX` with your SD card's device name, which depends on your OS and how the card connects to your machine. I purposefully did not use a device name so that you won't overwrite anything if you just copy and paste the instructions mindlessly. I did that and was lucky to have a recent backup of my laptop, but it was _not_ a pleasant experience.
|
||||
That writes the latest beta image available for 64-bit Raspberry Pi boards; check the [download page][9] if you use another Raspberry Pi board or want to use another build. Replace `XXX` with your SD card's device name, which depends on your OS and how the card connects to your machine. I purposefully did not use a device name so that you won't overwrite anything if you just copy and paste the instructions mindlessly. I did that and was lucky to have a recent backup of my laptop, but it was *not* a pleasant experience.
|
||||
|
||||
Once you've written the SD card, put it in your Raspberry Pi and boot it. The first boot takes a bit longer than usual; I suspect the partition sizes are being adjusted to the SD card's size. After a while, you will receive the familiar login prompt on a good old text-based screen. The username is **root**, and the password is the same as the user name. The SSH server is enabled by default, but don't worry; the root user cannot log in. It is still a good idea to change the password to something else. The network is automatically configured by DHCP for the Ethernet connection (I did not test WiFi).
|
||||
|
||||
The easiest way to configure Bastille on the system is to SSH into Raspberry Pi and copy and paste the commands and configuration in this article. You have a couple of options, depending on how much you care about industry best practices or are willing to treat it as a test system. You can either enable root login in the SSHD configuration (scary, but this is what I did at first) or create a regular user that can log in remotely. In the latter case, make sure that the user is part of the "wheel" group so that it can use `su -` to become root and use Bastille:
|
||||
|
||||
|
||||
```
|
||||
root@generic:~ # adduser
|
||||
Username: czanik
|
||||
@@ -79,9 +79,8 @@ Goodbye!
|
||||
|
||||
The fifth line adds the user to the wheel group. Note that you might have a different list of shells on your system, and Bash is not part of the base system. Install Bash before adding the user:
|
||||
|
||||
|
||||
```
|
||||
`pkg install bash`
|
||||
pkg install bash
|
||||
```
|
||||
|
||||
PKG needs to bootstrap itself on the first run, so invoking the command takes a bit longer this time.
|
||||
@@ -90,34 +89,30 @@ PKG needs to bootstrap itself on the first run, so invoking the command takes a
|
||||
|
||||
Managing jails with the tools in the FreeBSD base system is possible—but not really convenient. Using a tool like Bastille can simplify it considerably. It is not part of the base system, so install it:
|
||||
|
||||
|
||||
```
|
||||
`pkg install bastille`
|
||||
pkg install bastille
|
||||
```
|
||||
|
||||
As you can see from the command's output, Bastille has no external dependencies. It is a shell script that relies on commands in the FreeBSD base system (with an exception I'll note later when explaining templates).
|
||||
|
||||
If you want to start your containers on boot, enable Bastille:
|
||||
|
||||
|
||||
```
|
||||
`sysrc bastille_enable="YES"`
|
||||
sysrc bastille_enable="YES"
|
||||
```
|
||||
|
||||
Start with a simple use case. Many people use containers to install different development tools in different containers to avoid conflicts or simplify their environments. For example, no sane person wants to install Python 2 on a brand-new system—but you might need to run an ancient script every once in a while. So, create a jail for Python 2.
|
||||
|
||||
Before creating your first jail, you need to bootstrap a FreeBSD release and configure networking. Just make sure that you bootstrap the same or an older release than the host is running. For example:
|
||||
|
||||
|
||||
```
|
||||
`bastille bootstrap 12.2-RELEASE`
|
||||
bastille bootstrap 12.2-RELEASE
|
||||
```
|
||||
|
||||
It downloads and extracts this release under the `/usr/local/bastille` directory structure.
|
||||
|
||||
Networking can be configured in many different ways using Bastille. One option that works everywhere—on your local machine and in the cloud—is using cloned interfaces. This allows jails to use an internal network that does not interfere with the external network. Configure and start this internal network:
|
||||
|
||||
|
||||
```
|
||||
sysrc cloned_interfaces+=lo1
|
||||
sysrc ifconfig_lo1_name="bastille0"
|
||||
@@ -126,7 +121,6 @@ service netif cloneup
|
||||
|
||||
With this network setup, services in your jails are not accessible from the outside network, nor can they reach outside. You need forward ports from your host's external interface to the jails and to enable network access translation (NAT). Bastille integrates with BSD's [PF firewall][10] for this task. The following `pf.conf` configures the PF firewall such that Bastille can add port forwarding rules to the firewall dynamically:
|
||||
|
||||
|
||||
```
|
||||
ext_if="ue0"
|
||||
|
||||
@@ -134,8 +128,8 @@ set block-policy return
|
||||
scrub in on $ext_if all fragment reassemble
|
||||
set skip on lo
|
||||
|
||||
table <jails> persist
|
||||
nat on $ext_if from <jails> to any -> ($ext_if)
|
||||
table <jails> persist
|
||||
nat on $ext_if from <jails> to any -> ($ext_if)
|
||||
|
||||
rdr-anchor "rdr/*"
|
||||
|
||||
@@ -147,7 +141,6 @@ pass in inet proto tcp from any to any port ssh flags S/SA modulate state
|
||||
|
||||
You also need to enable and start PF for these rules to take effect. Note that if you work through an SSH connection, starting PF will terminate your connection, and you will need to log in again:
|
||||
|
||||
|
||||
```
|
||||
sysrc pf_enable="YES"
|
||||
service pf restart
|
||||
@@ -157,14 +150,12 @@ service pf restart
|
||||
|
||||
To create a jail, Bastille needs a few parameters. First, it needs a name for the jail you're creating. It is an important parameter, as you will always refer to a jail by its name. I chose the name of the most famous Hungarian jail for the most elite criminals, but in real life, jail names often refer to the jail's function, like `syslogserver`. You also need to set the FreeBSD release you're using and an internet protocol (IP) address. I used a random `10.0.0.0/8` IP address range, but if your internal network already uses addresses from that, then using the `192.168.0.0/16` is probably a better idea:
|
||||
|
||||
|
||||
```
|
||||
`bastille create csillag 12.2-RELEASE 10.17.89.51`
|
||||
bastille create csillag 12.2-RELEASE 10.17.89.51
|
||||
```
|
||||
|
||||
Your new jail should be up and running within a few seconds. It is a complete FreeBSD base system without any extra packages. So install some packages, like my favorite text editor, inside the jail:
|
||||
|
||||
|
||||
```
|
||||
root@generic:~ # bastille pkg csillag install joe
|
||||
[csillag]:
|
||||
@@ -190,22 +181,20 @@ Checking integrity... done (0 conflicting)
|
||||
|
||||
You can install multiple packages at the same time. Install Python 2, Bash, and Git:
|
||||
|
||||
|
||||
```
|
||||
`bastille pkg csillag install bash python2 git`
|
||||
bastille pkg csillag install bash python2 git
|
||||
```
|
||||
|
||||
Now you can start working in your new, freshly created jail. There are no network services installed in it, but you can reach it through its console:
|
||||
|
||||
|
||||
```
|
||||
root@generic:~ # bastille console csillag
|
||||
[csillag]:
|
||||
root@csillag:~ # python2
|
||||
Python 2.7.18 (default, Feb 2 2021, 01:53:44)
|
||||
[GCC FreeBSD Clang 10.0.1 ([git@github.com][11]:llvm/llvm-project.git llvmorg-10.0.1- on freebsd12
|
||||
[GCC FreeBSD Clang 10.0.1 (git@github.com:llvm/llvm-project.git llvmorg-10.0.1- on freebsd12
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>>
|
||||
>>>
|
||||
root@csillag:~ # logout
|
||||
|
||||
root@generic:~ #
|
||||
@@ -217,21 +206,18 @@ The previous example manually installed some packages inside a jail. Setting up
|
||||
|
||||
To use templates, you need to install Git on the host:
|
||||
|
||||
|
||||
```
|
||||
`pkg install git`
|
||||
pkg install git
|
||||
```
|
||||
|
||||
For example, to bootstrap the `syslog-ng` template, use:
|
||||
|
||||
|
||||
```
|
||||
`bastille bootstrap https://gitlab.com/BastilleBSD-Templates/syslog-ng`
|
||||
bastille bootstrap https://gitlab.com/BastilleBSD-Templates/syslog-ng
|
||||
```
|
||||
|
||||
Create a new jail, apply the template, and redirect an external port to it:
|
||||
|
||||
|
||||
```
|
||||
bastille create alcatraz 12.2-RELEASE 10.17.89.50
|
||||
bastille template alcatraz BastilleBSD-Templates/syslog-ng
|
||||
@@ -240,7 +226,6 @@ bastille rdr alcatraz tcp 514 514
|
||||
|
||||
To test the new service within the jail, use telnet to connect port 514 of your host and enter some random text. Use the `tail` command within your jail to see what you just entered:
|
||||
|
||||
|
||||
```
|
||||
root@generic:~ # tail /usr/local/bastille/jails/alcatraz/root/var/log/messages
|
||||
Feb 6 03:57:27 alcatraz sendmail[3594]: gethostbyaddr(10.17.89.50) failed: 1
|
||||
@@ -249,26 +234,26 @@ Feb 6 04:07:18 192.168.1.126 this is a test
|
||||
Feb 6 04:07:20 alcatraz syslog-ng[1186]: Syslog connection closed; fd='23', client='AF_INET(192.168.1.126:50104)', local='AF_INET(0.0.0.0:514)'
|
||||
```
|
||||
|
||||
Since I'm a [syslog-ng][12] evangelist, I used the syslog-ng template in my example, but there are many more available. Check the full list of [Bastille templates][13] to learn about them.
|
||||
Since I'm a [syslog-ng][11] evangelist, I used the syslog-ng template in my example, but there are many more available. Check the full list of [Bastille templates][12] to learn about them.
|
||||
|
||||
### What's next?
|
||||
|
||||
I hope that this article inspires you to try FreeBSD and Bastille on your Raspberry Pi. It was just enough information to get you started; to learn about all of Bastille's cool features—like auditing your jails for vulnerabilities and updating software within them—in the [documentation][14].
|
||||
I hope that this article inspires you to try FreeBSD and Bastille on your Raspberry Pi. It was just enough information to get you started; to learn about all of Bastille's cool features—like auditing your jails for vulnerabilities and updating software within them—in the [documentation][13].
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/3/bastille-raspberry-pi
|
||||
|
||||
作者:[Peter Czanik][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/containers_modules_networking_hardware_parts.png?itok=rPpVj92- (Parts, modules, containers for software)
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/containers_modules_networking_hardware_parts.png
|
||||
[2]: https://opensource.com/article/18/1/history-low-level-container-runtimes
|
||||
[3]: https://docs.freebsd.org/en/books/handbook/jails/
|
||||
[4]: https://opensource.com/article/18/11/behind-scenes-linux-containers
|
||||
@@ -278,7 +263,6 @@ via: https://opensource.com/article/21/3/bastille-raspberry-pi
|
||||
[8]: https://opensource.com/article/19/3/netbsd-raspberry-pi
|
||||
[9]: https://www.freebsd.org/where/
|
||||
[10]: https://en.wikipedia.org/wiki/PF_(firewall)
|
||||
[11]: mailto:git@github.com
|
||||
[12]: https://www.syslog-ng.com/
|
||||
[13]: https://gitlab.com/BastilleBSD-Templates/
|
||||
[14]: https://bastille.readthedocs.io/en/latest/
|
||||
[11]: https://www.syslog-ng.com/
|
||||
[12]: https://gitlab.com/BastilleBSD-Templates/
|
||||
[13]: https://bastille.readthedocs.io/en/latest/
|
||||
@@ -1,18 +1,20 @@
|
||||
[#]: subject: (Get started with edge computing by programming embedded systems)
|
||||
[#]: via: (https://opensource.com/article/21/3/rtos-embedded-development)
|
||||
[#]: author: (Alan Smithee https://opensource.com/users/alansmithee)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: "Get started with edge computing by programming embedded systems"
|
||||
[#]: via: "https://opensource.com/article/21/3/rtos-embedded-development"
|
||||
[#]: author: "Alan Smithee https://opensource.com/users/alansmithee"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Get started with edge computing by programming embedded systems
|
||||
======
|
||||
The AT device package for controlling wireless modems is one of RTOS's
|
||||
most popular extensions.
|
||||
The AT device package for controlling wireless modems is one of RTOS's most popular extensions.
|
||||
|
||||
![Looking at a map][1]
|
||||
|
||||
Image by: opensource.com
|
||||
|
||||
RTOS is an open source [operating system for embedded devices][2] developed by RT-Thread. It provides a standardized, friendly foundation for developers to program a variety of devices and includes a large number of useful libraries and toolkits to make the process easier.
|
||||
|
||||
Like Linux, RTOS uses a modular approach, which makes it easy to extend. Packages enable developers to use RTOS for any device they want to target. One of RTOS's most popular extensions is the AT device package, which includes porting files and sample code for different AT devices (i.e., modems).
|
||||
@@ -37,77 +39,71 @@ The at_device package is distributed under an LGPLv2.1 license, and it's easy to
|
||||
|
||||
To use AT devices with RTOS, you must enable the AT component library and AT socket functionality. This requires:
|
||||
|
||||
* RT_Thread 4.0.2+
|
||||
* RT_Thread AT component 1.3.0+
|
||||
* RT_Thread SAL component
|
||||
* RT-Thread netdev component
|
||||
|
||||
|
||||
* RT_Thread 4.0.2+
|
||||
* RT_Thread AT component 1.3.0+
|
||||
* RT_Thread SAL component
|
||||
* RT-Thread netdev component
|
||||
|
||||
The AT device package has been updated for multiple versions. Different versions require different configuration options, so they must fit into the corresponding system versions. Most of the currently available AT device package versions are:
|
||||
|
||||
* V1.2.0: For RT-Thread versions less than V3.1.3, AT component version equals V1.0.0
|
||||
* V1.3.0: For RT-Thread versions less than V3.1.3, AT component version equals V1.1.0
|
||||
* V1.4.0: For RT-Thread versions less than V3.1.3 or equal to V4.0.0, AT component version equals V1.2.0
|
||||
* V1.5.0: For RT-Thread versions less than V3.1.3 or equal to V4.0.0, AT component version equals V1.2.0
|
||||
* V1.6.0: For RT-Thread versions equal to V3.1.3 or V4.0.1, AT component version equals V1.2.0
|
||||
* V2.0.0/V2.0.1: For RT-Thread versions higher than V4.0.1 or higher than 3.1.3, AT component version equals V1.3.0
|
||||
* Latest version: For RT-Thread versions higher than V4.0.1 or higher than 3.1.3, AT component version equals V1.3.0
|
||||
|
||||
|
||||
* V1.2.0: For RT-Thread versions less than V3.1.3, AT component version equals V1.0.0
|
||||
* V1.3.0: For RT-Thread versions less than V3.1.3, AT component version equals V1.1.0
|
||||
* V1.4.0: For RT-Thread versions less than V3.1.3 or equal to V4.0.0, AT component version equals V1.2.0
|
||||
* V1.5.0: For RT-Thread versions less than V3.1.3 or equal to V4.0.0, AT component version equals V1.2.0
|
||||
* V1.6.0: For RT-Thread versions equal to V3.1.3 or V4.0.1, AT component version equals V1.2.0
|
||||
* V2.0.0/V2.0.1: For RT-Thread versions higher than V4.0.1 or higher than 3.1.3, AT component version equals V1.3.0
|
||||
* Latest version: For RT-Thread versions higher than V4.0.1 or higher than 3.1.3, AT component version equals V1.3.0
|
||||
|
||||
Getting the right version is mostly an automatic process done in menuconfig. It provides the best version of the at_device package based on your current system environment.
|
||||
|
||||
As mentioned, different versions require different configuration options. For instance, version 1.x supports enabling one AT device at a time:
|
||||
|
||||
|
||||
```
|
||||
RT-Thread online packages --->
|
||||
IoT - internet of things --->
|
||||
RT-Thread online packages --->
|
||||
IoT - internet of things --->
|
||||
-*- AT DEVICE: RT-Thread AT component porting or samples for different device
|
||||
[ ] Enable at device init by thread
|
||||
AT socket device modules (Not selected, please select) --->
|
||||
Version (V1.6.0) --->
|
||||
AT socket device modules (Not selected, please select) --->
|
||||
Version (V1.6.0) --->
|
||||
```
|
||||
|
||||
The option to enable the AT device init by thread dictates whether the configuration creates a separate thread to initialize the device network.
|
||||
|
||||
Version 2.x supports enabling multiple AT devices at the same time:
|
||||
|
||||
|
||||
```
|
||||
RT-Thread online packages --->
|
||||
IoT - internet of things --->
|
||||
RT-Thread online packages --->
|
||||
IoT - internet of things --->
|
||||
-*- AT DEVICE: RT-Thread AT component porting or samples for different device
|
||||
[*] Quectel M26/MC20 --->
|
||||
[*] Quectel M26/MC20 --->
|
||||
[*] Enable initialize by thread
|
||||
[*] Enable sample
|
||||
(-1) Power pin
|
||||
(-1) Power status pin
|
||||
(uart3) AT client device name
|
||||
(512) The maximum length of receive line buffer
|
||||
[ ] Quectel EC20 --->
|
||||
[ ] Espressif ESP32 --->
|
||||
[*] Espressif ESP8266 --->
|
||||
[ ] Quectel EC20 --->
|
||||
[ ] Espressif ESP32 --->
|
||||
[*] Espressif ESP8266 --->
|
||||
[*] Enable initialize by thread
|
||||
[*] Enable sample
|
||||
(realthread) WIFI ssid
|
||||
(12345678) WIFI password
|
||||
(uart2) AT client device name
|
||||
(512) The maximum length of receive line buffer
|
||||
[ ] Realthread RW007 --->
|
||||
[ ] SIMCom SIM800C --->
|
||||
[ ] SIMCom SIM76XX --->
|
||||
[ ] Notion MW31 --->
|
||||
[ ] WinnerMicro W60X --->
|
||||
[ ] AiThink A9/A9G --->
|
||||
[ ] Quectel BC26 --->
|
||||
[ ] Luat air720 --->
|
||||
[ ] GOSUNCN ME3616 --->
|
||||
[ ] ChinaMobile M6315 --->
|
||||
[ ] Quectel BC28 --->
|
||||
[ ] Quectel ec200x --->
|
||||
Version (latest) --->
|
||||
[ ] Realthread RW007 --->
|
||||
[ ] SIMCom SIM800C --->
|
||||
[ ] SIMCom SIM76XX --->
|
||||
[ ] Notion MW31 --->
|
||||
[ ] WinnerMicro W60X --->
|
||||
[ ] AiThink A9/A9G --->
|
||||
[ ] Quectel BC26 --->
|
||||
[ ] Luat air720 --->
|
||||
[ ] GOSUNCN ME3616 --->
|
||||
[ ] ChinaMobile M6315 --->
|
||||
[ ] Quectel BC28 --->
|
||||
[ ] Quectel ec200x --->
|
||||
Version (latest) --->
|
||||
```
|
||||
|
||||
This version includes many other options, including one to enable sample code, which might be particularly useful to new developers or any developer using an unfamiliar device.
|
||||
@@ -116,24 +112,21 @@ You can also control options to choose which pin you want to use to supply power
|
||||
|
||||
In short, there is no shortage of control options.
|
||||
|
||||
* V2.X.X version supports enabling multiple AT devices simultaneously, and the enabled device information can be viewed with the `ifocnfig` command in [finsh shell][6].
|
||||
* V2.X.X version requires the device to register before it's used; the registration can be done in the samples directory file or customized in the application layer.
|
||||
* Pin options such as **Power pin** and **Power status pin** are configured according to the device's hardware connection. They can be configured as `-1` if the hardware power-on function is not used.
|
||||
* One AT device should correspond to one serial name, and the **AT client device name** for each device should be different.
|
||||
|
||||
|
||||
* V2.X.X version supports enabling multiple AT devices simultaneously, and the enabled device information can be viewed with the `ifocnfig` command in [finsh shell][6].
|
||||
* V2.X.X version requires the device to register before it's used; the registration can be done in the samples directory file or customized in the application layer.
|
||||
* Pin options such as Power pin and Power status pin are configured according to the device's hardware connection. They can be configured as `-1` if the hardware power-on function is not used.
|
||||
* One AT device should correspond to one serial name, and the AT client device name for each device should be different.
|
||||
|
||||
### AT components configuration options
|
||||
|
||||
When the AT device package is selected and device support is enabled, client functionality for the AT component is selected by default. That means more options—this time for the AT component:
|
||||
|
||||
|
||||
```
|
||||
RT-Thread Components --->
|
||||
Network --->
|
||||
AT commands --->
|
||||
RT-Thread Components --->
|
||||
Network --->
|
||||
AT commands --->
|
||||
[ ] Enable debug log output
|
||||
[ ] Enable AT commands server
|
||||
[ ] Enable AT commands server
|
||||
-*- Enable AT commands client
|
||||
(1) The maximum number of supported clients
|
||||
-*- Enable BSD Socket API support by AT commnads
|
||||
@@ -144,11 +137,9 @@ RT-Thread Components --->
|
||||
|
||||
The configuration options related to the AT device package are:
|
||||
|
||||
* **The maximum number of supported clients**: Selecting multiple devices in the AT device package requires this option to be configured as the corresponding value.
|
||||
* **Enable BSD Socket API support by AT commands**: This option will be selected by default when selecting the AT device package.
|
||||
* **The maximum length of AT Commands buffe:** The maximum length of the data the AT commands can send.
|
||||
|
||||
|
||||
* The maximum number of supported clients: Selecting multiple devices in the AT device package requires this option to be configured as the corresponding value.
|
||||
* Enable BSD Socket API support by AT commands: This option will be selected by default when selecting the AT device package.
|
||||
* The maximum length of AT Commands buffe: The maximum length of the data the AT commands can send.
|
||||
|
||||
### Anything is possible
|
||||
|
||||
@@ -159,15 +150,15 @@ When you start programming embedded systems, you quickly realize that you can cr
|
||||
via: https://opensource.com/article/21/3/rtos-embedded-development
|
||||
|
||||
作者:[Alan Smithee][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/alansmithee
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/tips_map_guide_ebook_help_troubleshooting_lightbulb_520.png?itok=L0BQHgjr (Looking at a map)
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/tips_map_guide_ebook_help_troubleshooting_lightbulb_520.png
|
||||
[2]: https://opensource.com/article/20/6/open-source-rtos
|
||||
[3]: https://en.wikipedia.org/wiki/Berkeley_sockets
|
||||
[4]: https://github.com/RT-Thread/rtthread-manual-doc/blob/master/at/at.md
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
[#]: subject: (Get started with an open source customer data platform)
|
||||
[#]: via: (https://opensource.com/article/21/3/rudderstack-customer-data-platform)
|
||||
[#]: author: (Amey Varangaonkar https://opensource.com/users/ameypv)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: "Get started with an open source customer data platform"
|
||||
[#]: via: "https://opensource.com/article/21/3/rudderstack-customer-data-platform"
|
||||
[#]: author: "Amey Varangaonkar https://opensource.com/users/ameypv"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Get started with an open source customer data platform
|
||||
======
|
||||
As an open source alternative to Segment, RudderStack collects and
|
||||
routes event stream (or clickstream) data and automatically builds your
|
||||
customer data lake on your data warehouse.
|
||||
As an open source alternative to Segment, RudderStack collects and routes event stream (or clickstream) data and automatically builds your customer data lake on your data warehouse.
|
||||
|
||||
![Person standing in front of a giant computer screen with numbers, data][1]
|
||||
|
||||
Image by: Opensource.com
|
||||
|
||||
[RudderStack][2] is an open source, warehouse-first customer data pipeline. It collects and routes event stream (or clickstream) data and automatically builds your customer data lake on your data warehouse.
|
||||
|
||||
RudderStack is commonly known as the open source alternative to the customer data platform (CDP), [Segment][3]. It provides a more secure, flexible, and cost-effective solution in comparison. You get all the CDP functionality with added security and full ownership of your customer data.
|
||||
@@ -24,60 +25,51 @@ Warehouse-first tools like RudderStack are architected to build functional data
|
||||
|
||||
Before you get started, you will need the RudderStack workspace token from your RudderStack dashboard. To get it:
|
||||
|
||||
1. Go to the [RudderStack dashboard][4].
|
||||
|
||||
2. Log in using your credentials (or sign up for an account, if you don't already have one).
|
||||
|
||||
![RudderStack login screen][5]
|
||||
|
||||
(RudderStack, [CC BY-SA 4.0][6])
|
||||
|
||||
3. Once you've logged in, you should see the workspace token on your RudderStack dashboard.
|
||||
|
||||
![RudderStack workspace token][7]
|
||||
|
||||
(RudderStack, [CC BY-SA 4.0][6])
|
||||
1. Go to the [RudderStack dashboard][4].
|
||||
2. Log in using your credentials (or sign up for an account, if you don't already have one).
|
||||
|
||||
![RudderStack login screen][7]
|
||||
|
||||
3. Once you've logged in, you should see the workspace token on your RudderStack dashboard.
|
||||
|
||||
![RudderStack workspace token][8]
|
||||
|
||||
### Installing RudderStack
|
||||
|
||||
Setting up a RudderStack open source instance is straightforward. You have two installation options:
|
||||
|
||||
1. On your Kubernetes cluster, using RudderStack's Helm charts
|
||||
2. On your Docker container, using the `docker-compose` command
|
||||
1. On your Kubernetes cluster, using RudderStack's Helm charts
|
||||
2. On your Docker container, using the `docker-compose` command
|
||||
|
||||
|
||||
|
||||
This tutorial explains how to use both options but assumes that you already have [Git installed on your system][8].
|
||||
This tutorial explains how to use both options but assumes that you already have [Git installed on your system][9].
|
||||
|
||||
#### Deploying with Kubernetes
|
||||
|
||||
You can deploy RudderStack on your Kubernetes cluster using the [Helm][9] package manager.
|
||||
You can deploy RudderStack on your Kubernetes cluster using the [Helm][10] package manager.
|
||||
|
||||
_If you plan to use RudderStack in production, we strongly recommend using this method._ This is because the Docker images are updated with bug fixes more frequently than the GitHub repository (which follows a monthly release cycle).
|
||||
*If you plan to use RudderStack in production, we strongly recommend using this method.* This is because the Docker images are updated with bug fixes more frequently than the GitHub repository (which follows a monthly release cycle).
|
||||
|
||||
Before you can deploy RudderStack on Kubernetes, make sure you have the following prerequisites in place:
|
||||
|
||||
* [Install and connect kubectl][10] to your Kubernetes cluster.
|
||||
* [Install Helm][11] on your system, either through the Helm installer scripts or its package manager.
|
||||
* Finally, get the workspace token from the RudderStack dashboard by following the steps in the [Getting the RudderStack workspace token][12] section.
|
||||
|
||||
|
||||
* [Install and connect kubectl][11] to your Kubernetes cluster.
|
||||
* [Install Helm][12] on your system, either through the Helm installer scripts or its package manager.
|
||||
* Finally, get the workspace token from the RudderStack dashboard by following the steps in the Getting the RudderStack workspace token section.
|
||||
|
||||
Once you've completed all the prerequisites, deploy RudderStack on your default Kubernetes cluster:
|
||||
|
||||
1. Find the Helm chart required to deploy RudderStack in this [repo][13].
|
||||
2. Install the Helm chart with a release name of your choice (`my-release`, in this example) from the root directory of the repo in the previous step: [code] $ helm install \
|
||||
my-release ./ --set \
|
||||
rudderWorkspaceToken="<your workspace token from RudderStack dashboard>"
|
||||
```
|
||||
1. Find the Helm chart required to deploy RudderStack in this [repo][13].
|
||||
2. Install the Helm chart with a release name of your choice (my-release, in this example) from the root directory of the repo in the previous step:
|
||||
```
|
||||
$ helm install \
|
||||
my-release ./ --set \
|
||||
rudderWorkspaceToken="<your workspace token from RudderStack dashboard>"
|
||||
```
|
||||
|
||||
This deploys RudderStack on your default Kubernetes cluster configured with kubectl using the workspace token you obtained from the RudderStack dashboard.
|
||||
|
||||
For more details on the configurable parameters in the RudderStack Helm chart or updating the versions of the images used, consult the [documentation][14].
|
||||
|
||||
### Deploying with Docker
|
||||
#### Deploying with Docker
|
||||
|
||||
Docker is the easiest and fastest way to set up your open source RudderStack instance.
|
||||
|
||||
@@ -85,12 +77,12 @@ First, get the workspace token from the RudderStack dashboard by following the s
|
||||
|
||||
Once you have the RudderStack workspace token:
|
||||
|
||||
1. Download the [**rudder-docker.yml**][15] docker-compose file required for the installation.
|
||||
2. Replace `<your_workspace_token>` in this file with your RudderStack workspace token.
|
||||
3. Set up RudderStack on your Docker container by running: [code]`docker-compose -f rudder-docker.yml up`
|
||||
```
|
||||
|
||||
|
||||
1. Download the [rudder-docker.yml][15] docker-compose file required for the installation.
|
||||
2. Replace `<your_workspace_token>` in this file with your RudderStack workspace token.
|
||||
3. Set up RudderStack on your Docker container by running:
|
||||
```
|
||||
docker-compose -f rudder-docker.yml up
|
||||
```
|
||||
|
||||
Now RudderStack should be up and running on your Docker instance.
|
||||
|
||||
@@ -98,128 +90,115 @@ Now RudderStack should be up and running on your Docker instance.
|
||||
|
||||
You can verify your RudderStack installation by sending test events using the bundled shell script:
|
||||
|
||||
1. Clone the GitHub repository: [code]`git clone https://github.com/rudderlabs/rudder-server.git`
|
||||
```
|
||||
2. In this tutorial, you will verify RudderStack by sending test events to Google Analytics. Make sure you have a Google Analytics account and keep the tracking ID handy. Also, note that the Google Analytics account needs to have a `Web` property.
|
||||
1. Clone the GitHub repository:
|
||||
```
|
||||
git clone https://github.com/rudderlabs/rudder-server.git
|
||||
```
|
||||
2. In this tutorial, you will verify RudderStack by sending test events to Google Analytics. Make sure you have a Google Analytics account and keep the tracking ID handy. Also, note that the Google Analytics account needs to have a `Web` property.
|
||||
3. In the [RudderStack hosted control plane][16]:
|
||||
* Add a source on the RudderStack dashboard by following the [Adding a source and destination in RudderStack][17] guide. You can use either of RudderStack's event stream software development kits (SDKs) for sending events from your app. This example sets up the [JavaScript SDK][18] as a source on the dashboard. Note: You aren't actually installing the RudderStack JavaScript SDK on your site in this step; you are just creating the source in RudderStack.
|
||||
* Configure a Google Analytics destination on the RudderStack dashboard using the instructions in the guide mentioned previously. Use the Google Analytics tracking ID you kept from step 2 of this section:
|
||||
|
||||
3. In the [RudderStack hosted control plane][4]:
|
||||
|
||||
* Add a source on the RudderStack dashboard by following the [Adding a source and destination in RudderStack][16] guide. You can use either of RudderStack's event stream software development kits (SDKs) for sending events from your app. This example sets up the [JavaScript SDK][17] as a source on the dashboard. **Note:** You aren't actually installing the RudderStack JavaScript SDK on your site in this step; you are just creating the source in RudderStack.
|
||||
|
||||
* Configure a Google Analytics destination on the RudderStack dashboard using the instructions in the guide mentioned previously. Use the Google Analytics tracking ID you kept from step 2 of this section:
|
||||
|
||||
![Google Analytics tracking ID][18]
|
||||
|
||||
(RudderStack, [CC BY-SA 4.0][6])
|
||||
|
||||
4. As mentioned before, RudderStack bundles a shell script that generates test events. Get the **Source write key** from the RudderStack dashboard:
|
||||
|
||||
![RudderStack source write key][19]
|
||||
|
||||
(RudderStack, [CC BY-SA 4.0][6])
|
||||
|
||||
5. Next, run: [code]`./scripts/generate-event <YOUR_WRITE_KEY> https://hosted.rudderlabs.com/v1/batch`
|
||||
```
|
||||
|
||||
6. Finally, log into your Google Analytics account and verify that the events were delivered. In your Google Analytics account, navigate to **RealTime** -> **Events**. The RealTime view is important because some dashboards can take one to two days to refresh.
|
||||
![Google Analytics tracking ID][27]
|
||||
|
||||
4. As mentioned before, RudderStack bundles a shell script that generates test events. Get the **Source write key** from the RudderStack dashboard:
|
||||
|
||||
![RudderStack source write key][28]
|
||||
|
||||
5. Next, run:
|
||||
```
|
||||
./scripts/generate-event <YOUR_WRITE_KEY> https://hosted.rudderlabs.com/v1/batch
|
||||
```
|
||||
6. Finally, log into your Google Analytics account and verify that the events were delivered. In your Google Analytics account, navigate to *RealTime** -> **Events**. The RealTime view is important because some dashboards can take one to two days to refresh.
|
||||
|
||||
### Optional: Setting up the open source control plane
|
||||
|
||||
RudderStack's core architecture contains two major components: the data plane and the control plane. The data plane, [rudder-server][20], delivers your event data, and the RudderStack hosted control plane manages the configuration of your sources and destinations.
|
||||
RudderStack's core architecture contains two major components: the data plane and the control plane. The data plane, [rudder-server][29], delivers your event data, and the RudderStack hosted control plane manages the configuration of your sources and destinations.
|
||||
|
||||
However, if you want to manage the source and destination configurations locally, you can set an open source control plane in your environment using the RudderStack Config Generator. (You must have [Node.js][21] installed on your system to use it.)
|
||||
However, if you want to manage the source and destination configurations locally, you can set an open source control plane in your environment using the RudderStack Config Generator. (You must have [Node.js][30] installed on your system to use it.)
|
||||
|
||||
Here are the steps to set up the control plane:
|
||||
|
||||
1. Install and set up RudderStack on the platform of your choice by following the instructions above.
|
||||
2. Run the following commands in this order:
|
||||
* `cd utils/config-gen`
|
||||
* `npm install`
|
||||
* `npm start`
|
||||
|
||||
|
||||
1. Install and set up RudderStack on the platform of your choice by following the instructions above.
|
||||
2. Run the following commands in this order:
|
||||
```
|
||||
cd utils/config-gen
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
You should now be able to access the open source control plane at `http://localhost:3000` by default. If your setup is successful, you will see the user interface.
|
||||
|
||||
![RudderStack open source control plane][22]
|
||||
![RudderStack open source control plane][31]
|
||||
|
||||
(RudderStack, [CC BY-SA 4.0][6])
|
||||
|
||||
To export the existing workspace configuration from the RudderStack-hosted control plane and have RudderStack use it, consult the [docs][23].
|
||||
To export the existing workspace configuration from the RudderStack-hosted control plane and have RudderStack use it, consult the [docs][32].
|
||||
|
||||
### RudderStack and open source
|
||||
|
||||
The core of RudderStack is in the [rudder-server][20] repository. It is open source, licensed under [AGPL-3.0][24]. A majority of the destination integrations live in the [rudder-transformer][25] repository. They are open source as well, licensed under the [MIT License][26]. The SDKs and instrumentation repositories, several tool and utility repositories, and even some [dbt][27] model repositories for use-cases like customer journey analysis and sessionization for the data residing in your data warehouse are open source, licensed under the MIT License, and available in the [GitHub repository][28].
|
||||
The core of RudderStack is in the [rudder-server][33] repository. It is open source, licensed under [AGPL-3.0][34]. A majority of the destination integrations live in the [rudder-transformer][35] repository. They are open source as well, licensed under the [MIT License][36]. The SDKs and instrumentation repositories, several tool and utility repositories, and even some [dbt][37] model repositories for use-cases like customer journey analysis and sessionization for the data residing in your data warehouse are open source, licensed under the MIT License, and available in the [GitHub repository][38].
|
||||
|
||||
You can use RudderStack's open source offering, rudder-server, on your platform of choice. There are setup guides for [Docker][29], [Kubernetes][30], [native installation][31], and [developer machines][32].
|
||||
You can use RudderStack's open source offering, rudder-server, on your platform of choice. There are setup guides for [Docker][39], [Kubernetes][40], [native installation][41], and [developer machines][42].
|
||||
|
||||
RudderStack open source offers:
|
||||
|
||||
1. RudderStack event stream
|
||||
2. 15+ SDKs and source integrations to ingest event data
|
||||
3. 80+ destination and warehouse integrations
|
||||
4. Slack community support
|
||||
|
||||
|
||||
1. RudderStack event stream
|
||||
2. 15+ SDKs and source integrations to ingest event data
|
||||
3. 80+ destination and warehouse integrations
|
||||
4. Slack community support
|
||||
|
||||
#### RudderStack Cloud
|
||||
|
||||
RudderStack also offers a managed option, [RudderStack Cloud][33]. It is fast, reliable, and highly scalable with a multi-node architecture and sophisticated error-handling mechanism. You can hit peak event volume without worrying about downtime, loss of events, or latency.
|
||||
RudderStack also offers a managed option, [RudderStack Cloud][43]. It is fast, reliable, and highly scalable with a multi-node architecture and sophisticated error-handling mechanism. You can hit peak event volume without worrying about downtime, loss of events, or latency.
|
||||
|
||||
Explore our open source repos on [GitHub][28], subscribe to [our blog][34], and follow us on social media: [Twitter][35], [LinkedIn][36], [dev.to][37], [Medium][38], and [YouTube][39]!
|
||||
Image By: (RudderStack, CC BY-SA 4.0)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/3/rudderstack-customer-data-platform
|
||||
|
||||
作者:[Amey Varangaonkar][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/ameypv
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/data_metrics_analytics_desktop_laptop.png?itok=9QXd7AUr (Person standing in front of a giant computer screen with numbers, data)
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/data_metrics_analytics_desktop_laptop.png
|
||||
[2]: https://rudderstack.com/
|
||||
[3]: https://segment.com/
|
||||
[4]: https://app.rudderstack.com/
|
||||
[5]: https://opensource.com/sites/default/files/uploads/rudderstack_login.png (RudderStack login screen)
|
||||
[6]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[7]: https://opensource.com/sites/default/files/uploads/rudderstack_workspace-token.png (RudderStack workspace token)
|
||||
[8]: https://opensource.com/life/16/7/stumbling-git
|
||||
[9]: https://helm.sh/
|
||||
[10]: https://kubernetes.io/docs/tasks/tools/install-kubectl/
|
||||
[11]: https://helm.sh/docs/intro/install/
|
||||
[12]: tmp.AhGpFIyrbZ#token
|
||||
[7]: https://opensource.com/sites/default/files/uploads/rudderstack_login.png
|
||||
[8]: https://opensource.com/sites/default/files/uploads/rudderstack_workspace-token.png
|
||||
[9]: https://opensource.com/life/16/7/stumbling-git
|
||||
[10]: https://helm.sh/
|
||||
[11]: https://kubernetes.io/docs/tasks/tools/install-kubectl/
|
||||
[12]: https://helm.sh/docs/intro/install/
|
||||
[13]: https://github.com/rudderlabs/rudderstack-helm
|
||||
[14]: https://docs.rudderstack.com/installing-and-setting-up-rudderstack/kubernetes
|
||||
[15]: https://raw.githubusercontent.com/rudderlabs/rudder-server/master/rudder-docker.yml
|
||||
[16]: https://docs.rudderstack.com/get-started/adding-source-and-destination-rudderstack
|
||||
[17]: https://docs.rudderstack.com/rudderstack-sdk-integration-guides/rudderstack-javascript-sdk
|
||||
[18]: https://opensource.com/sites/default/files/uploads/googleanalyticstrackingid.png (Google Analytics tracking ID)
|
||||
[19]: https://opensource.com/sites/default/files/uploads/rudderstack_sourcewritekey.png (RudderStack source write key)
|
||||
[20]: https://github.com/rudderlabs/rudder-server
|
||||
[21]: https://nodejs.org/en/download/
|
||||
[22]: https://opensource.com/sites/default/files/uploads/rudderstack_controlplane.png (RudderStack open source control plane)
|
||||
[23]: https://docs.rudderstack.com/how-to-guides/rudderstack-config-generator
|
||||
[24]: https://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||
[25]: https://github.com/rudderlabs/rudder-transformer
|
||||
[26]: https://opensource.org/licenses/MIT
|
||||
[27]: https://www.getdbt.com/
|
||||
[28]: https://github.com/rudderlabs
|
||||
[29]: https://docs.rudderstack.com/get-started/installing-and-setting-up-rudderstack/docker
|
||||
[30]: https://docs.rudderstack.com/get-started/installing-and-setting-up-rudderstack/kubernetes
|
||||
[31]: https://docs.rudderstack.com/get-started/installing-and-setting-up-rudderstack/native-installation
|
||||
[32]: https://docs.rudderstack.com/get-started/installing-and-setting-up-rudderstack/developer-machine-setup
|
||||
[33]: https://resources.rudderstack.com/rudderstack-cloud
|
||||
[34]: https://rudderstack.com/blog/
|
||||
[35]: https://twitter.com/RudderStack
|
||||
[36]: https://www.linkedin.com/company/rudderlabs/
|
||||
[37]: https://dev.to/rudderstack
|
||||
[38]: https://rudderstack.medium.com/
|
||||
[39]: https://www.youtube.com/channel/UCgV-B77bV_-LOmKYHw8jvBw
|
||||
[16]: https://app.rudderstack.com/
|
||||
[17]: https://docs.rudderstack.com/get-started/adding-source-and-destination-rudderstack
|
||||
[18]: https://docs.rudderstack.com/rudderstack-sdk-integration-guides/rudderstack-javascript-sdk
|
||||
[20]: https://docs.rudderstack.com/get-started/adding-source-and-destination-rudderstack
|
||||
[21]: https://docs.rudderstack.com/rudderstack-sdk-integration-guides/rudderstack-javascript-sdk
|
||||
[24]: https://docs.rudderstack.com/get-started/adding-source-and-destination-rudderstack
|
||||
[25]: https://docs.rudderstack.com/rudderstack-sdk-integration-guides/rudderstack-javascript-sdk
|
||||
[27]: https://opensource.com/sites/default/files/uploads/googleanalyticstrackingid.png
|
||||
[28]: https://opensource.com/sites/default/files/uploads/rudderstack_sourcewritekey.png
|
||||
[29]: https://github.com/rudderlabs/rudder-server
|
||||
[30]: https://nodejs.org/en/download/
|
||||
[31]: https://opensource.com/sites/default/files/uploads/rudderstack_controlplane.png
|
||||
[32]: https://docs.rudderstack.com/how-to-guides/rudderstack-config-generator
|
||||
[33]: https://github.com/rudderlabs/rudder-server
|
||||
[34]: https://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||
[35]: https://github.com/rudderlabs/rudder-transformer
|
||||
[36]: https://opensource.org/licenses/MIT
|
||||
[37]: https://www.getdbt.com/
|
||||
[38]: https://github.com/rudderlabs
|
||||
[39]: https://docs.rudderstack.com/get-started/installing-and-setting-up-rudderstack/docker
|
||||
[40]: https://docs.rudderstack.com/get-started/installing-and-setting-up-rudderstack/kubernetes
|
||||
[41]: https://docs.rudderstack.com/get-started/installing-and-setting-up-rudderstack/native-installation
|
||||
[42]: https://docs.rudderstack.com/get-started/installing-and-setting-up-rudderstack/developer-machine-setup
|
||||
[43]: https://resources.rudderstack.com/rudderstack-cloud
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
[#]: subject: (Use the Alpine email client in your Linux terminal)
|
||||
[#]: via: (https://opensource.com/article/21/5/alpine-linux-email)
|
||||
[#]: author: (David Both https://opensource.com/users/dboth)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: "Use the Alpine email client in your Linux terminal"
|
||||
[#]: via: "https://opensource.com/article/21/5/alpine-linux-email"
|
||||
[#]: author: "David Both https://opensource.com/users/dboth"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Use the Alpine email client in your Linux terminal
|
||||
======
|
||||
Configure Alpine to handle your email the way you like it.
|
||||
|
||||
![Chat via email][1]
|
||||
|
||||
Email is an important communications medium and will remain so for the foreseeable future. I have used many different email clients over the last 30 years, and [Thunderbird][2] is what I have used the most in recent years. It is an excellent and functional desktop application that provides all the features that most people need—including me.
|
||||
@@ -22,7 +23,7 @@ This desire to go retro with my email client started back in 2017 when I wrote a
|
||||
|
||||
I recently decided to exclusively use Alpine for email. The main attraction is the ease of use offered by keeping my hands on the keyboard (and reducing the number of times I need to reach for the mouse). It is also about scratching my sysadmin itch to do something different and use an excellent text mode interface in the process.
|
||||
|
||||
## Getting started
|
||||
### Getting started
|
||||
|
||||
I already had Alpine set up from my previous use, so it was just a matter of starting to use it again.
|
||||
|
||||
@@ -32,18 +33,17 @@ I previously set up Alpine on my mail server—I used secure shell (SSH) to log
|
||||
|
||||
But now I want to run Alpine on my workstation or laptop. It's relatively simple to configure Alpine on the same host as the email server. Using it on a remote computer requires a good bit more.
|
||||
|
||||
## Install Alpine
|
||||
### Install Alpine
|
||||
|
||||
Installing Alpine on Fedora is simple because it is available from the Fedora repository. Just use DNF as root:
|
||||
|
||||
|
||||
```
|
||||
`# dnf -y install alpine`
|
||||
# dnf -y install alpine
|
||||
```
|
||||
|
||||
This command installs Alpine and any prerequisite packages that are not already installed. Alpine's primary dependencies are Sendmail, Hunspell, OpenLDAP, OpenSSL, krb5-libs, ncurses, and a couple of others. In my case, Alpine was the only package installed.
|
||||
|
||||
## Launch Alpine
|
||||
### Launch Alpine
|
||||
|
||||
To launch Alpine, open a terminal session, type **alpine** on the command line, and press **Enter**.
|
||||
|
||||
@@ -51,7 +51,6 @@ The first time you start Alpine, it displays a message that it is creating the u
|
||||
|
||||
For now, just press lowercase **e** to exit from the greeting message. You should now see Alpine's Main menu (I deleted several blank lines of the output to save space):
|
||||
|
||||
|
||||
```
|
||||
+----------------------------------------------------+
|
||||
| ALPINE 2.24 MAIN MENU Folder: INBOX No Messages |
|
||||
@@ -77,25 +76,24 @@ For now, just press lowercase **e** to exit from the greeting message. You shoul
|
||||
| For Copyright information press "?" |
|
||||
| |
|
||||
| ? Help P PrevCmd R RelNotes |
|
||||
| O OTHER CMDS > [ListFldrs] N NextCmd K KBLock |
|
||||
| O OTHER CMDS > [ListFldrs] N NextCmd K KBLock |
|
||||
+----------------------------------------------------+
|
||||
```
|
||||
|
||||
_Figure 1: Alpine's Main menu_
|
||||
*Figure 1: Alpine's Main menu*
|
||||
|
||||
Alpine creates the `~mail` directory localhost during initial use. When you configure the IMAP server, Alpine creates the default `~/mail`, `~/mail/sent-mail`, and `saved-messages` folders in your home directory on the IMAP server. You can change the defaults, but I recommend against it. When using IMAP, emails are not stored locally unless you copy them to local folders. All emails are stored in the Inbox on the SMTP server until they are saved to a folder on the IMAP server. The SMTP and IMAP servers might use the same or different hosts.
|
||||
|
||||
Alpine also assumes that the Inbox is located at `/var/spool/mail/user_name` on the email SMTP server. This article explains how to configure both IMAP and SMTP servers. The email administrator for your organization—that might be you—will add your account to the IMAP server and provide you with the initial password.
|
||||
|
||||
## The Alpine interface
|
||||
### The Alpine interface
|
||||
|
||||
The Alpine user interface (UI) is a text-mode, menu-driven UI, also known as a TUI. This type of interface is also sometimes called captive user interface (CUI), which does not provide a command-line interface that can be used in scripts, for example. You must exit from the program to perform other tasks.
|
||||
|
||||
By contrast, the [mailx][5] program is an email program that can be used with either a TUI, from the command line, or in scripts. For example, you can use the following command to send the results of the free command directly to the sysadmin's email account:
|
||||
|
||||
|
||||
```
|
||||
`$ free | mailx -s "Free memory" sysadmin@example.com`
|
||||
$ free | mailx -s "Free memory" sysadmin@example.com
|
||||
```
|
||||
|
||||
But enough of that little side trip; there is work to do. Let's start with an explanation.
|
||||
@@ -106,20 +104,19 @@ On the Main menu, you can use the **Up** and **Down** arrow keys to highlight a
|
||||
|
||||
Use the **Page Down** and **Page Up** keys to scroll through the commands if you can't see them all. The secondary menu at the bottom of the page usually lists all the commands available on the current menu; you will also see a message similar to this:
|
||||
|
||||
|
||||
```
|
||||
`[START of Information About Setup Command]`
|
||||
[START of Information About Setup Command]
|
||||
```
|
||||
|
||||
Should you find yourself at a place you don't want to be, such as creating a new email, responding to one, or making changes to settings, and decide you don't want to do that, **Ctrl+C** allows you to cancel the current task. In most cases, you will be asked to confirm that you want to cancel by pressing the **C** key. Note that **^C** in the secondary menu represents **Ctrl+C**. Many commands use the **Ctrl** key, so you will see **^** quite frequently on some menus.
|
||||
|
||||
Finally, to quit Alpine, you can press **Q**; when it asks, "Really quit Alpine?" respond with **Y** to exit. Like many commands, **Q** is not available from all menus.
|
||||
|
||||
## Help
|
||||
### Help
|
||||
|
||||
Help is available from all of the menus I have tried. You can access detailed help for each menu item by highlighting the item you need information for and pressing the **?** key to obtain context-sensitive help.
|
||||
|
||||
## Configuration
|
||||
### Configuration
|
||||
|
||||
When I started using Alpine regularly, I made the minimum changes to the configuration needed to send and receive emails. As I gained more experience with Alpine, I changed other configuration items to make things work easier or more to my liking.
|
||||
|
||||
@@ -127,100 +124,97 @@ First, I will explain the basic configurations required to make Alpine work, the
|
||||
|
||||
If you have been exploring a bit on your own—which is a good thing—return to the Main menu. To get to Alpine's Configuration menu from the Main menu, type **S** for Setup. You will see a menu like this:
|
||||
|
||||
|
||||
```
|
||||
ALPINE 2.24 SETUP Folder: INBOX No Messages
|
||||
ALPINE 2.24 SETUP Folder: INBOX No Messages
|
||||
|
||||
This is the Setup screen for Alpine. Choose from the following commands:
|
||||
This is the Setup screen for Alpine. Choose from the following commands:
|
||||
|
||||
(E) Exit Setup:
|
||||
This puts you back at the Main Menu.
|
||||
(E) Exit Setup:
|
||||
This puts you back at the Main Menu.
|
||||
|
||||
(P) Printer:
|
||||
Allows you to set a default printer and to define custom
|
||||
print commands.
|
||||
(P) Printer:
|
||||
Allows you to set a default printer and to define custom
|
||||
print commands.
|
||||
|
||||
(N) Newpassword:
|
||||
Change your password.
|
||||
(N) Newpassword:
|
||||
Change your password.
|
||||
|
||||
(C) Config:
|
||||
Allows you to set or unset many features of Alpine.
|
||||
You may also set the values of many options with this command.
|
||||
(C) Config:
|
||||
Allows you to set or unset many features of Alpine.
|
||||
You may also set the values of many options with this command.
|
||||
|
||||
(S) Signature:
|
||||
Enter or edit a custom signature which will
|
||||
be included with each new message you send.
|
||||
(S) Signature:
|
||||
Enter or edit a custom signature which will
|
||||
be included with each new message you send.
|
||||
|
||||
(A) AddressBooks:
|
||||
Define a non-default address book.
|
||||
(A) AddressBooks:
|
||||
Define a non-default address book.
|
||||
|
||||
(L) collectionLists:
|
||||
You may define groups of folders to help you better organize your mail.
|
||||
(L) collectionLists:
|
||||
You may define groups of folders to help you better organize your mail.
|
||||
|
||||
(R) Rules:
|
||||
This has up to six sub-categories: Roles, Index Colors, Filters,
|
||||
[START of Information About Setup Command ]
|
||||
(R) Rules:
|
||||
This has up to six sub-categories: Roles, Index Colors, Filters,
|
||||
[START of Information About Setup Command ]
|
||||
? Help E Exit Setup N Newpassword S Signature L collectionList D Directory
|
||||
O OTHER CMDS P Printer C Config A AddressBooks R Rules K Kolor
|
||||
```
|
||||
|
||||
_Figure 2: Alpine Setup menu_
|
||||
*Figure 2: Alpine Setup menu*
|
||||
|
||||
The Setup menu groups the very large number of setup items into related categories to, hopefully, make the ones you want easier to locate. Use **Page Down** and **Page Up** to scroll through the commands if you can't see them all.
|
||||
|
||||
I'll start with the settings necessary to get email—Alpine's entire purpose—up and running.
|
||||
|
||||
## Config
|
||||
### Config
|
||||
|
||||
The Config section contains 15 pages (on my large screen) of option- and feature-configuration items. These settings can be used to set up your SMTP and IMAP connections to the email server and define the way many aspects of Alpine work. In these examples, I'll use the `example.com` domain name (which is the virtual network I use for testing and experimenting). Alpine's configuration is stored in the `~/.pinerc` file, created the first time you start Alpine.
|
||||
|
||||
The first page of the Setup Configuration menu contains most of the settings required to configure Alpine to send and receive email:
|
||||
|
||||
|
||||
```
|
||||
ALPINE 2.24 SETUP CONFIGURATION Folder: INBOX No Messages
|
||||
|
||||
Personal Name = <No Value Set: using "Test User">
|
||||
User Domain = <No Value Set>
|
||||
SMTP Server (for sending) = <No Value Set>
|
||||
NNTP Server (for news) = <No Value Set>
|
||||
Inbox Path = <No Value Set: using "inbox">
|
||||
Incoming Archive Folders = <No Value Set>
|
||||
Pruned Folders = <No Value Set>
|
||||
Default Fcc (File carbon copy) = <No Value Set: using "sent-mail">
|
||||
Default Saved Message Folder = <No Value Set: using "saved-messages">
|
||||
Postponed Folder = <No Value Set: using "postponed-msgs">
|
||||
Read Message Folder = <No Value Set>
|
||||
Form Letter Folder = <No Value Set>
|
||||
Trash Folder = <No Value Set: using "Trash">
|
||||
Literal Signature = <No Value Set>
|
||||
Signature File = <No Value Set: using ".signature">
|
||||
Personal Name = <No Value Set: using "Test User">
|
||||
User Domain = <No Value Set>
|
||||
SMTP Server (for sending) = <No Value Set>
|
||||
NNTP Server (for news) = <No Value Set>
|
||||
Inbox Path = <No Value Set: using "inbox">
|
||||
Incoming Archive Folders = <No Value Set>
|
||||
Pruned Folders = <No Value Set>
|
||||
Default Fcc (File carbon copy) = <No Value Set: using "sent-mail">
|
||||
Default Saved Message Folder = <No Value Set: using "saved-messages">
|
||||
Postponed Folder = <No Value Set: using "postponed-msgs">
|
||||
Read Message Folder = <No Value Set>
|
||||
Form Letter Folder = <No Value Set>
|
||||
Trash Folder = <No Value Set: using "Trash">
|
||||
Literal Signature = <No Value Set>
|
||||
Signature File = <No Value Set: using ".signature">
|
||||
Feature List =
|
||||
Set Feature Name
|
||||
\--- ----------------------
|
||||
--- ----------------------
|
||||
[ Composer Preferences ]
|
||||
[X] Allow Changing From (default)
|
||||
[ ] Alternate Compose Menu
|
||||
[ ] Alternate Role (#) Menu
|
||||
[ ] Compose Cancel Confirm Uses Yes
|
||||
[ ] Compose Rejects Unqualified Addresses
|
||||
[ ] Compose Send Offers First Filter
|
||||
[ ] Ctrl-K Cuts From Cursor
|
||||
[ ] Delete Key Maps to Ctrl-D
|
||||
[ ] Do Not Save to Deadletter on Cancel
|
||||
[ ] Alternate Compose Menu
|
||||
[ ] Alternate Role (#) Menu
|
||||
[ ] Compose Cancel Confirm Uses Yes
|
||||
[ ] Compose Rejects Unqualified Addresses
|
||||
[ ] Compose Send Offers First Filter
|
||||
[ ] Ctrl-K Cuts From Cursor
|
||||
[ ] Delete Key Maps to Ctrl-D
|
||||
[ ] Do Not Save to Deadletter on Cancel
|
||||
[Already at start of screen]
|
||||
? Help E Exit Setup P Prev - PrevPage A Add Value % Print
|
||||
? Help E Exit Setup P Prev - PrevPage A Add Value % Print
|
||||
O OTHER CMDS C [Change Val] N Next Spc NextPage D Delete Val W WhereIs
|
||||
```
|
||||
|
||||
_Figure 3: First page of Alpine's Setup Configuration menu_
|
||||
*Figure 3: First page of Alpine's Setup Configuration menu*
|
||||
|
||||
This is where you define the parameters required to communicate with the email server. To change a setting, use the **Arrow** keys to move the selection bar to the desired configuration item and press **Enter**. You can see in Figure 3 that none of the basic configuration items have any values set.
|
||||
|
||||
The **Personal Name** item uses the [Gecos field][6] of the Unix `/etc/passwd` entry for the logged-in user to obtain the default name. This is just a name Alpine uses for display and has no role in receiving or sending email. I usually call this the "pretty name." In this case, the default name is fine, so I will leave it as it is.
|
||||
|
||||
There are some configuration items that you must set. Start with the **User Domain**, which is the current computer's domain name. Mine is a virtual machine I use for testing and examples in my books. Use the command line to get the fully qualified domain name (FQDN) and the hostname. In Figure 4, you can see that the domain name is `example.com`:
|
||||
|
||||
There are some configuration items that you must set. Start with the **User Domain**, which is the current computer's domain name. Mine is a virtual machine I use for testing and examples in my books. Use the command line to get the fully qualified domain name (FQDN) and the hostname. In Figure 4, you can see that the domain name is `example.com` :
|
||||
|
||||
```
|
||||
$ hostnamectl
|
||||
@@ -236,117 +230,161 @@ Kernel: Linux 5.10.23-200.fc33.x86_64
|
||||
Architecture: x86-64
|
||||
```
|
||||
|
||||
_Figure 4: Obtaining the hostname and domain name_
|
||||
|
||||
Once you have the FQDN, select the **User Domain** entry and press **Enter** to see the entry field at the bottom of the Alpine screen (as shown in Figure 5). Type your domain name and press **Enter** (using _your_ network's domain and server names):
|
||||
*Figure 4: Obtaining the hostname and domain name*
|
||||
|
||||
Once you have the FQDN, select the **User Domain** entry and press **Enter** to see the entry field at the bottom of the Alpine screen (as shown in Figure 5). Type your domain name and press **Enter** (using *your* network's domain and server names):
|
||||
|
||||
```
|
||||
ALPINE 2.24 SETUP CONFIGURATION Folder: INBOX No Messages
|
||||
|
||||
Personal Name = <No Value Set: using "Test User">
|
||||
User Domain = <No Value Set>
|
||||
SMTP Server (for sending) = <No Value Set>
|
||||
NNTP Server (for news) = <No Value Set>
|
||||
Inbox Path = <No Value Set: using "inbox">
|
||||
Incoming Archive Folders = <No Value Set>
|
||||
Pruned Folders = <No Value Set>
|
||||
Default Fcc (File carbon copy) = <No Value Set: using "sent-mail">
|
||||
Default Saved Message Folder = <No Value Set: using "saved-messages">
|
||||
Postponed Folder = <No Value Set: using "postponed-msgs">
|
||||
Read Message Folder = <No Value Set>
|
||||
Form Letter Folder = <No Value Set>
|
||||
Trash Folder = <No Value Set: using "Trash">
|
||||
Literal Signature = <No Value Set>
|
||||
Signature File = <No Value Set: using ".signature">
|
||||
Personal Name = <No Value Set: using "Test User">
|
||||
User Domain = <No Value Set>
|
||||
SMTP Server (for sending) = <No Value Set>
|
||||
NNTP Server (for news) = <No Value Set>
|
||||
Inbox Path = <No Value Set: using "inbox">
|
||||
Incoming Archive Folders = <No Value Set>
|
||||
Pruned Folders = <No Value Set>
|
||||
Default Fcc (File carbon copy) = <No Value Set: using "sent-mail">
|
||||
Default Saved Message Folder = <No Value Set: using "saved-messages">
|
||||
Postponed Folder = <No Value Set: using "postponed-msgs">
|
||||
Read Message Folder = <No Value Set>
|
||||
Form Letter Folder = <No Value Set>
|
||||
Trash Folder = <No Value Set: using "Trash">
|
||||
Literal Signature = <No Value Set>
|
||||
Signature File = <No Value Set: using ".signature">
|
||||
Feature List =
|
||||
Set Feature Name
|
||||
\--- ----------------------
|
||||
--- ----------------------
|
||||
[ Composer Preferences ]
|
||||
[X] Allow Changing From (default)
|
||||
[ ] Alternate Compose Menu
|
||||
[ ] Alternate Role (#) Menu
|
||||
[ ] Compose Cancel Confirm Uses Yes
|
||||
[ ] Compose Rejects Unqualified Addresses
|
||||
[ ] Compose Send Offers First Filter
|
||||
[ ] Ctrl-K Cuts From Cursor
|
||||
[ ] Delete Key Maps to Ctrl-D
|
||||
[ ] Do Not Save to Deadletter on Cancel
|
||||
Enter the text to be added : example.com
|
||||
^G Help
|
||||
[ ] Alternate Compose Menu
|
||||
[ ] Alternate Role (#) Menu
|
||||
[ ] Compose Cancel Confirm Uses Yes
|
||||
[ ] Compose Rejects Unqualified Addresses
|
||||
[ ] Compose Send Offers First Filter
|
||||
[ ] Ctrl-K Cuts From Cursor
|
||||
[ ] Delete Key Maps to Ctrl-D
|
||||
[ ] Do Not Save to Deadletter on Cancel
|
||||
Enter the text to be added : example.com
|
||||
^G Help
|
||||
^C Cancel Ret Accept
|
||||
```
|
||||
|
||||
_Figure 5: Type the domain name into the text entry field._
|
||||
*Figure 5: Type the domain name into the text entry field.*
|
||||
|
||||
### Required config
|
||||
#### Required config
|
||||
|
||||
These are the basic configuration items you need to send and receive email:
|
||||
|
||||
* **Personal Name**
|
||||
* Your name
|
||||
* This is the pretty name Alpine uses for the From and Return fields in emails.
|
||||
* **User Domain**
|
||||
* `example.com:25/user=SMTP_Authentication_UserName`
|
||||
* This is the email domain for your email client. This might be different from the User Domain name. This line also contains the SMTP port number and the user name for SMTP authentication.
|
||||
* **SMTP server**
|
||||
* SMTP
|
||||
* This is the name of the outbound SMTP email server. It combines with the User Domain name to create the FQDN for the email server.
|
||||
* **Inbox Path**
|
||||
* `{IMAP_server)}Inbox`
|
||||
* This is the name of the IMAP server enclosed in curly braces (`{}`) and the name of the Inbox. Note that this directory location is different from the inbound IMAP email. The usual location for the inbox on the server is `/var/spool/mail/user_name`.
|
||||
* **Default Fcc** (file carbon copy)
|
||||
* `{IMAP_server)}mail/sent`
|
||||
* This is the mailbox (folder) where sent mail is stored. The default mail directory on the server is usually `~/mail`, but `mail/` must be specified in this and the next two entries, or the folders will be placed in the home directory instead.
|
||||
* **Default Saved Message Folder**
|
||||
* `{IMAP_server)}mail/saved-messages`
|
||||
* This is the default folder when saving a message to a folder if you don't use `^t` to specify a different one.
|
||||
* **Trash Folder**
|
||||
* `{IMAP_server)}mail/Trash`
|
||||
* **Literal Signature**
|
||||
* A signature string
|
||||
* I don't use this, but it's an easy place to specify a simple signature.
|
||||
* **Signature File**
|
||||
* `~/MySignature.sig`
|
||||
* This points to the file that contains your signature file.
|
||||
* Personal Name
|
||||
* Your name
|
||||
* This is the pretty name Alpine uses for the From and Return fields in emails.
|
||||
* User Domain
|
||||
* example.com:25/user=SMTP_Authentication_UserName
|
||||
* This is the email domain for your email client. This might be different from the User Domain name. This line also contains the SMTP port number and the user name for SMTP authentication.
|
||||
* * SMTP server
|
||||
SMTP
|
||||
* This is the name of the outbound SMTP email server. It combines with the User Domain name to create the FQDN for the email server.
|
||||
* Inbox Path
|
||||
* {IMAP_server)}Inbox
|
||||
* This is the name of the IMAP server enclosed in curly braces ({}) and the name of the Inbox. Note that this directory location is different from the inbound IMAP email. The usual location for the inbox on the server is `/var/spool/mail/user_name`.
|
||||
* Default Fcc (file carbon copy)
|
||||
* {IMAP_server)}mail/sent
|
||||
* This is the mailbox (folder) where sent mail is stored. The default mail directory on the server is usually `~/mail`, but `mail/` must be specified in this and the next two entries, or the folders will be placed in the home directory instead.
|
||||
* Default Saved Message Folder
|
||||
* {IMAP_server)}mail/saved-messages
|
||||
* This is the default folder when saving a message to a folder if you don't use `^t` to specify a different one.
|
||||
* Trash Folder
|
||||
* {IMAP_server)}mail/Trash
|
||||
* Literal Signature
|
||||
* A signature string
|
||||
* I don't use this, but it's an easy place to specify a simple signature.
|
||||
* Signature File
|
||||
* ~/MySignature.sig
|
||||
* This points to the file that contains your signature file.
|
||||
|
||||
|
||||
|
||||
### Optional config
|
||||
#### Optional config
|
||||
|
||||
Here are the features I changed to make Alpine work more to my liking. They are not about getting Alpine to send and receive email, but about making Alpine work the way you want it to. Unless otherwise noted, I turned all of these features on. Features that are turned on by default have the string `(default)` next to them in the Alpine display. Because they are already turned on, I will not describe them.
|
||||
|
||||
* **Alternate Role (`#`) Menu:** This allows multiple identities using different email addresses on the same client and server. The server must be configured to allow multiple addresses to be delivered to your primary email account.
|
||||
* **Compose Rejects Unqualified Addresses:** Alpine will not accept an address that is not fully qualified. That is, it must be in the form `<username@example.com>`.
|
||||
* **Enable Sigdashes:** This enables Alpine to automatically add dashes (`--`) in the row just above the signature. This is a common way of delineating the start of the signature.
|
||||
* **Prevent User Lookup in Password File:** This prevents the lookup of the full user name from the Gecos field of the passwd file.
|
||||
* **Spell Check Before Sending:** Although you can invoke the spell checker at any time while composing an email, this forces a spell check when you use the `^X` keystroke to send an email.
|
||||
* **Include Header in Reply:** This includes a message's headers when you reply.
|
||||
* **Include Text in Reply:** This includes the text of the original message in your reply.
|
||||
* **Signature at Bottom:** Many people prefer to have their signature at the very bottom of the email. This setting changes the default, which puts the signature at the end of the reply and before the message being replied to.
|
||||
* **Preserve Original Fields:** This preserves the original addresses in the **To:** and **CC:** fields when you reply to a message. If this feature is disabled when you reply to a message, the original sender is added to the **To:** field, all other recipients are added to the **CC:** field, and your address is added to the **From:** field.
|
||||
* **Enable Background Sending:** This speeds the Alpine user interface response when sending an email.
|
||||
* **Enable Verbose SMTP Posting:** This produces more verbose information during SMTP conversations with the server. It is a problem-determination aid for the sysadmin.
|
||||
* **Warn if Blank Subject:** This prevents sending emails with no subject.
|
||||
* **Combined Folder Display:** This combines all folder collections into a single main display. Otherwise, collections will be in separate views.
|
||||
* **Combined Subdirectory Display:** This combines all subdirectories' collections into a single main display. Otherwise, subdirectories will be in separate views. This is useful when searching for a subdirectory to attach or save files.
|
||||
* **Enable Incoming Folders Collection:** This lists all incoming folders in the same collection as the Inbox. Incoming folders can be used with a tool like procmail to presort email into folders other than the Inbox and makes it easier to see the folders where new emails are sorted.
|
||||
* **Enable Incoming Folders Checking:** This enables Alpine to check for new emails in the incoming folders collection.
|
||||
* **Incoming Checking Includes Total:** This displays the number of old and new emails in the incoming folders.
|
||||
* **Expanded View of Folders:** This displays all folders in each collection when you view the **Folder List** screen. Otherwise, only the collections are shown, and the folders are not shown until selected.
|
||||
* **Separate Folder and Directory Entries:** If your mail directory has email folders and regular directories that use the same name, this causes Alpine to list them separately.
|
||||
* **Use Vertical Folder List:** This sorts mail folders vertically first and then horizontally. The default is horizontal, then vertical.
|
||||
* **Convert Dates To Localtime:** By default, all dates and times are displayed in their originating time zones. This converts the dates to display in local time.
|
||||
* **Show Sort in Titlebar:** Alpine can sort emails in a mail folder using multiple criteria. This causes the sort criteria to be displayed in the title bar.
|
||||
* **Enable Message View Address Links:** This highlights email addresses in the body of the email.
|
||||
* **Enable Message View Attachment Links:** This highlights URL links in the body of the email.
|
||||
* **Prefer Plain Text:** Many emails contain two versions, plain text and HTML. When this feature is turned on, Alpine always displays the plain text version. You can use the **A** key to toggle to the "preferred" version, usually the HTML one. I usually find the plain text easier to visualize the structure of and read the email. This can depend upon the sending client, so I use the **A** key when needed.
|
||||
* **Enable Print Via Y Command:** This prints a message using the previous default, **Y**. Because **Y** is also used to confirm many commands, the keystroke can inadvertently cause you to print a message. The new default is **%** to prevent accidental printing. I like the ease of using **Y**, but it has caused some extra print jobs, so I am thinking about turning this feature off.
|
||||
* **Print Formfeed Between Messages:** This prints each message on a new sheet of paper.
|
||||
* **Customized Headers:** Customized headers enables overriding the default **From:** and **Reply-To:** headers. I set mine to: [code] - From: "David Both" <[[david@example.com][7]](mailto:[david@both.org][8])>
|
||||
\- Reply-To: "David Both"
|
||||
<[[david@example.com][7]](mailto:[david@both.org][8])>
|
||||
* Alternate Role (#) Menu: This allows multiple identities using different email addresses on the same client and server. The server must be configured to allow multiple addresses to be delivered to your primary email account.
|
||||
* Compose Rejects Unqualified Addresses: Alpine will not accept an address that is not fully qualified. That is, it must be in the form `<username@example.com>`.
|
||||
* Enable Sigdashes: This enables Alpine to automatically add dashes (--) in the row just above the signature. This is a common way of delineating the start of the signature.
|
||||
* Prevent User Lookup in Password File: This prevents the lookup of the full user name from the Gecos field of the passwd file.
|
||||
* Spell Check Before Sending: Although you can invoke the spell checker at any time while composing an email, this forces a spell check when you use the `^X` keystroke to send an email.
|
||||
* Include Header in Reply: This includes a message's headers when you reply.
|
||||
* Include Text in Reply: This includes the text of the original message in your reply.
|
||||
* Signature at Bottom: Many people prefer to have their signature at the very bottom of the email. This setting changes the default, which puts the signature at the end of the reply and before the message being replied to.
|
||||
* Preserve Original Fields: This preserves the original addresses in the To: and CC: fields when you reply to a message. If this feature is disabled when you reply to a message, the original sender is added to the To: field, all other recipients are added to the CC: field, and your address is added to the From: field.
|
||||
* Enable Background Sending: This speeds the Alpine user interface response when sending an email.
|
||||
* Enable Verbose SMTP Posting: This produces more verbose information during SMTP conversations with the server. It is a problem-determination aid for the sysadmin.
|
||||
* Warn if Blank Subject: This prevents sending emails with no subject.
|
||||
* Combined Folder Display: This combines all folder collections into a single main display. Otherwise, collections will be in separate views.
|
||||
* Combined Subdirectory Display: This combines all subdirectories' collections into a single main display. Otherwise, subdirectories will be in separate views. This is useful when searching for a subdirectory to attach or save files.
|
||||
* Enable Incoming Folders Collection: This lists all incoming folders in the same collection as the Inbox. Incoming folders can be used with a tool like procmail to presort email into folders other than the Inbox and makes it easier to see the folders where new emails are sorted.
|
||||
* Enable Incoming Folders Checking: This enables Alpine to check for new emails in the incoming folders collection.
|
||||
* Incoming Checking Includes Total: This displays the number of old and new emails in the incoming folders.
|
||||
* Expanded View of Folders: This displays all folders in each collection when you view the Folder List screen. Otherwise, only the collections are shown, and the folders are not shown until selected.
|
||||
* Separate Folder and Directory Entries: If your mail directory has email folders and regular directories that use the same name, this causes Alpine to list them separately.
|
||||
* Use Vertical Folder List: This sorts mail folders vertically first and then horizontally. The default is horizontal, then vertical.
|
||||
* Convert Dates To Localtime: By default, all dates and times are displayed in their originating time zones. This converts the dates to display in local time.
|
||||
* Show Sort in Titlebar: Alpine can sort emails in a mail folder using multiple criteria. This causes the sort criteria to be displayed in the title bar.
|
||||
* Enable Message View Address Links: This highlights email addresses in the body of the email.
|
||||
* Enable Message View Attachment Links: This highlights URL links in the body of the email.
|
||||
* Prefer Plain Text: Many emails contain two versions, plain text and HTML. When this feature is turned on, Alpine always displays the plain text version. You can use the A key to toggle to the "preferred" version, usually the HTML one. I usually find the plain text easier to visualize the structure of and read the email. This can depend upon the sending client, so I use the A key when needed.
|
||||
* Enable Print Via Y Command: This prints a message using the previous default, Y. Because Y is also used to confirm many commands, the keystroke can inadvertently cause you to print a message. The new default is % to prevent accidental printing. I like the ease of using Y, but it has caused some extra print jobs, so I am thinking about turning this feature off.
|
||||
* Print Formfeed Between Messages: This prints each message on a new sheet of paper.
|
||||
* Customized Headers: Customized headers enables overriding the default From: and Reply-To: headers. I set mine to:
|
||||
- From: "David Both" <[david@example.com](mailto:david@both.org)>
|
||||
- Reply-To: "David Both"
|
||||
<[david@example.com](mailto:david@both.org)>
|
||||
* Sort key: By default, Alpine sorts messages in a folder by arrival time. I found this to be a bit confusing, so I changed it to Date, which can be significantly different from arrival time. Many spammers use dates and times in the past or future, so this setting can sort the future ones to the top of the list (or bottom, depending on your preferences for forward or reverse sorts).
|
||||
* Image Viewer: This feature allows you to specify the image viewer to use when displaying graphics attached to or embedded in an email. This only works when using Alpine in a terminal window on the graphical desktop. It will not work in a text-only virtual console. I always set this to `=okular` because [Okular][7] is my preferred viewer.
|
||||
* URL-Viewer: This tells Alpine what web browser you want to use. I set this for `= /bin/firefox` but you could use Chrome or another browser. Be sure to verify the location of the Firefox executable.
|
||||
|
||||
#### Printing
|
||||
|
||||
It is easy to set up Alpine for printing. Select the **Printer** menu from the **Setup** page. This allows you to set a default printer and define custom print commands. The default is probably `attached-to-ansi`. Move the cursor down to the **Standard UNIX print command** section and highlight the printer list.
|
||||
|
||||
```
|
||||
* **Sort key:** By default, Alpine sorts messages in a folder by arrival time. I found this to be a bit confusing, so I changed it to **Date**, which can be significantly different from arrival time. Many spammers use dates and times in the past or future, so this setting can sort the future ones to the top of the list (or bottom, depending on your preferences for forward or reverse sorts).
|
||||
* **Image Viewer:** This feature allows you to specify the image viewer to use when displaying graphics attached to or embedded in an email. This only works when using Alpine in a terminal window on the graphical desktop. It will not work in a text-only virtual console. I always set this to `=okular` because [Okular][9] is my preferred viewer.
|
||||
* **URL-Viewer:** This tells Alpine what web browser you
|
||||
Standard UNIX print command
|
||||
|
||||
Using this option may require setting your "PRINTER" or "LPDEST"
|
||||
|
||||
environment variable using the standard UNIX utilities.
|
||||
|
||||
Printer List: "" lpr
|
||||
```
|
||||
|
||||
Then press the **Enter** key to set the standard Unix **lpr** command as the default.
|
||||
|
||||
### Final thoughts
|
||||
|
||||
This is not a step-by-step guide to Alpine configuration and use. Rather, I tried to cover the basics to get it up and running to send and receive email. I also shared some configuration changes that have made my Alpine experience much more usable. These are the configuration items that I've found most important to my experience; you may find that others are more important to you.
|
||||
|
||||
I have been using Alpine for several months now and am very happy with the experience. The text interface helps me concentrate on the message and not the distracting graphics and animations. I can view those if I choose, but 99% of the time, I choose not to.
|
||||
|
||||
Alpine is easy to use and has a huge number of features that can be configured to give the best email client experience possible.
|
||||
|
||||
Use the **Help** feature to get more information about the fields I explored above and those that I did not cover. You will undoubtedly find ways to configure Alpine that work better for you than the defaults or what I changed. I hope this will at least give you a start to set up Alpine the way you want.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/5/alpine-linux-email
|
||||
|
||||
作者:[David Both][a]
|
||||
选题:[lkxed][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/dboth
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/email_chat_communication_message.png
|
||||
[2]: https://www.thunderbird.net/en-US/
|
||||
[3]: https://alpine.x10host.com/
|
||||
[4]: https://opensource.com/article/17/10/alpine-email-client
|
||||
[5]: https://linux.die.net/man/1/mailx
|
||||
[6]: https://en.wikipedia.org/wiki/Gecos_field
|
||||
[7]: https://okular.kde.org/
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
[#]: subject: (4 steps to set up global modals in React)
|
||||
[#]: via: (https://opensource.com/article/21/5/global-modals-react)
|
||||
[#]: author: (Ajay Pratap https://opensource.com/users/ajaypratap)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: "4 steps to set up global modals in React"
|
||||
[#]: via: "https://opensource.com/article/21/5/global-modals-react"
|
||||
[#]: author: "Ajay Pratap https://opensource.com/users/ajaypratap"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
4 steps to set up global modals in React
|
||||
======
|
||||
Learn how to create interactive pop-up windows in a React web app.
|
||||
|
||||
![Digital creative of a browser on the internet][1]
|
||||
|
||||
A modal dialog is a window that appears on top of a web page and requires a user's interaction before it disappears. [React][2] has a couple of ways to help you generate and manage modals with minimal coding.
|
||||
@@ -24,11 +25,10 @@ In my opinion, the best way to manage modal dialogs in your React application is
|
||||
|
||||
Here are the steps (and code) to set up global modals in React. I'm using [Patternfly][3] as my foundation, but the principles apply to any project.
|
||||
|
||||
#### 1\. Create a global modal component
|
||||
#### 1. Create a global modal component
|
||||
|
||||
In a file called **GlobalModal.tsx**, create your modal definition:
|
||||
|
||||
|
||||
```
|
||||
import React, { useState, createContext, useContext } from 'react';
|
||||
import { CreateModal, DeleteModal,UpdateModal } from './components';
|
||||
@@ -46,25 +46,25 @@ const MODAL_COMPONENTS: any = {
|
||||
};
|
||||
|
||||
type GlobalModalContext = {
|
||||
showModal: (modalType: string, modalProps?: any) => void;
|
||||
hideModal: () => void;
|
||||
showModal: (modalType: string, modalProps?: any) => void;
|
||||
hideModal: () => void;
|
||||
store: any;
|
||||
};
|
||||
|
||||
const initalState: GlobalModalContext = {
|
||||
showModal: () => {},
|
||||
hideModal: () => {},
|
||||
showModal: () => {},
|
||||
hideModal: () => {},
|
||||
store: {},
|
||||
};
|
||||
|
||||
const GlobalModalContext = createContext(initalState);
|
||||
export const useGlobalModalContext = () => useContext(GlobalModalContext);
|
||||
export const useGlobalModalContext = () => useContext(GlobalModalContext);
|
||||
|
||||
export const GlobalModal: React.FC<{}> = ({ children }) => {
|
||||
export const GlobalModal: React.FC<{}> = ({ children }) => {
|
||||
const [store, setStore] = useState();
|
||||
const { modalType, modalProps } = store || {};
|
||||
|
||||
const showModal = (modalType: string, modalProps: any = {}) => {
|
||||
const showModal = (modalType: string, modalProps: any = {}) => {
|
||||
setStore({
|
||||
...store,
|
||||
modalType,
|
||||
@@ -72,7 +72,7 @@ export const GlobalModal: React.FC<{}> = ({ children }) => {
|
||||
});
|
||||
};
|
||||
|
||||
const hideModal = () => {
|
||||
const hideModal = () => {
|
||||
setStore({
|
||||
...store,
|
||||
modalType: null,
|
||||
@@ -80,19 +80,19 @@ export const GlobalModal: React.FC<{}> = ({ children }) => {
|
||||
});
|
||||
};
|
||||
|
||||
const renderComponent = () => {
|
||||
const renderComponent = () => {
|
||||
const ModalComponent = MODAL_COMPONENTS[modalType];
|
||||
if (!modalType || !ModalComponent) {
|
||||
return null;
|
||||
}
|
||||
return <ModalComponent id="global-modal" {...modalProps} />;
|
||||
return <ModalComponent id="global-modal" {...modalProps} />;
|
||||
};
|
||||
|
||||
return (
|
||||
<GlobalModalContext.Provider value={{ store, showModal, hideModal }}>
|
||||
<GlobalModalContext.Provider value={{ store, showModal, hideModal }}>
|
||||
{renderComponent()}
|
||||
{children}
|
||||
</GlobalModalContext.Provider>
|
||||
</GlobalModalContext.Provider>
|
||||
);
|
||||
};
|
||||
```
|
||||
@@ -103,40 +103,39 @@ The `showModal` function takes two parameters: `modalType` and `modalProps`. The
|
||||
|
||||
The `hideModal` function doesn't have any parameters; calling it causes the current open modal to close.
|
||||
|
||||
#### 2\. Create modal dialog components
|
||||
#### 2. Create modal dialog components
|
||||
|
||||
In a file called **CreateModal.tsx**, create a modal:
|
||||
|
||||
|
||||
```
|
||||
import React from "react";
|
||||
import { Modal, ModalVariant, Button } from "@patternfly/react-core";
|
||||
import { useGlobalModalContext } from "../GlobalModal";
|
||||
|
||||
export const CreateModal = () => {
|
||||
export const CreateModal = () => {
|
||||
const { hideModal, store } = useGlobalModalContext();
|
||||
const { modalProps } = store || {};
|
||||
const { title, confirmBtn } = modalProps || {};
|
||||
|
||||
const handleModalToggle = () => {
|
||||
const handleModalToggle = () => {
|
||||
hideModal();
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
<Modal
|
||||
variant={ModalVariant.medium}
|
||||
title={title || "Create Modal"}
|
||||
isOpen={true}
|
||||
onClose={handleModalToggle}
|
||||
actions={[
|
||||
<Button key="confirm" variant="primary" onClick={handleModalToggle}>
|
||||
<Button key="confirm" variant="primary" onClick={handleModalToggle}>
|
||||
{confirmBtn || "Confirm button"}
|
||||
</Button>,
|
||||
<Button key="cancel" variant="link" onClick={handleModalToggle}>
|
||||
</Button>,
|
||||
<Button key="cancel" variant="link" onClick={handleModalToggle}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Button>
|
||||
]}
|
||||
>
|
||||
>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
@@ -144,7 +143,7 @@ export const CreateModal = () => {
|
||||
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
|
||||
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
|
||||
est laborum.
|
||||
</Modal>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
```
|
||||
@@ -153,34 +152,33 @@ This has a custom hook, `useGlobalModalContext`, that provides store object from
|
||||
|
||||
To delete a modal, create a file called **DeleteModal.tsx**:
|
||||
|
||||
|
||||
```
|
||||
import React from "react";
|
||||
import { Modal, ModalVariant, Button } from "@patternfly/react-core";
|
||||
import { useGlobalModalContext } from "../GlobalModal";
|
||||
|
||||
export const DeleteModal = () => {
|
||||
export const DeleteModal = () => {
|
||||
const { hideModal } = useGlobalModalContext();
|
||||
|
||||
const handleModalToggle = () => {
|
||||
const handleModalToggle = () => {
|
||||
hideModal();
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
<Modal
|
||||
variant={ModalVariant.medium}
|
||||
title="Delete Modal"
|
||||
isOpen={true}
|
||||
onClose={handleModalToggle}
|
||||
actions={[
|
||||
<Button key="confirm" variant="primary" onClick={handleModalToggle}>
|
||||
<Button key="confirm" variant="primary" onClick={handleModalToggle}>
|
||||
Confirm
|
||||
</Button>,
|
||||
<Button key="cancel" variant="link" onClick={handleModalToggle}>
|
||||
</Button>,
|
||||
<Button key="cancel" variant="link" onClick={handleModalToggle}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Button>
|
||||
]}
|
||||
>
|
||||
>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
@@ -188,41 +186,40 @@ export const DeleteModal = () => {
|
||||
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
|
||||
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
|
||||
est laborum.
|
||||
</Modal>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
To update a modal, create a file called **UpdateModal.tsx** and add this code:
|
||||
|
||||
|
||||
```
|
||||
import React from "react";
|
||||
import { Modal, ModalVariant, Button } from "@patternfly/react-core";
|
||||
import { useGlobalModalContext } from "../GlobalModal";
|
||||
|
||||
export const UpdateModal = () => {
|
||||
export const UpdateModal = () => {
|
||||
const { hideModal } = useGlobalModalContext();
|
||||
|
||||
const handleModalToggle = () => {
|
||||
const handleModalToggle = () => {
|
||||
hideModal();
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
<Modal
|
||||
variant={ModalVariant.medium}
|
||||
title="Update Modal"
|
||||
isOpen={true}
|
||||
onClose={handleModalToggle}
|
||||
actions={[
|
||||
<Button key="confirm" variant="primary" onClick={handleModalToggle}>
|
||||
<Button key="confirm" variant="primary" onClick={handleModalToggle}>
|
||||
Confirm
|
||||
</Button>,
|
||||
<Button key="cancel" variant="link" onClick={handleModalToggle}>
|
||||
</Button>,
|
||||
<Button key="cancel" variant="link" onClick={handleModalToggle}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Button>
|
||||
]}
|
||||
>
|
||||
>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
@@ -230,15 +227,14 @@ export const UpdateModal = () => {
|
||||
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
|
||||
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
|
||||
est laborum.
|
||||
</Modal>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
#### 3\. Integrate GlobalModal into the top-level component in your application
|
||||
|
||||
To integrate the new modal structure you've created into your app, you just import the global modal class you've created. Here's my sample **App.tsx** file:
|
||||
#### 3. Integrate GlobalModal into the top-level component in your application
|
||||
|
||||
To integrate the new modal structure you've created into your app, you just import the global modal class you've created. Here's my sample **App.tsx**file:
|
||||
|
||||
```
|
||||
import "@patternfly/react-core/dist/styles/base.css";
|
||||
@@ -248,9 +244,9 @@ import { AppLayout } from "./AppLayout";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<GlobalModal>
|
||||
<AppLayout />
|
||||
</GlobalModal>
|
||||
<GlobalModal>
|
||||
<AppLayout />
|
||||
</GlobalModal>
|
||||
);
|
||||
}
|
||||
```
|
||||
@@ -259,55 +255,54 @@ App.tsx is the top-level component in your app, but you can add another componen
|
||||
|
||||
`GlobalModal` is the root-level component where all your modal components are imported and mapped with their specific `modalType`.
|
||||
|
||||
#### 4\. Select the modal's button from the AppLayout component
|
||||
#### 4. Select the modal's button from the AppLayout component
|
||||
|
||||
Adding a button to your modal with **AppLayout.js**:
|
||||
|
||||
|
||||
```
|
||||
import React from "react";
|
||||
import { Button, ButtonVariant } from "@patternfly/react-core";
|
||||
import { useGlobalModalContext, MODAL_TYPES } from "./components/GlobalModal";
|
||||
|
||||
export const AppLayout = () => {
|
||||
export const AppLayout = () => {
|
||||
const { showModal } = useGlobalModalContext();
|
||||
|
||||
const createModal = () => {
|
||||
const createModal = () => {
|
||||
showModal(MODAL_TYPES.CREATE_MODAL, {
|
||||
title: "Create instance form",
|
||||
confirmBtn: "Save"
|
||||
});
|
||||
};
|
||||
|
||||
const deleteModal = () => {
|
||||
const deleteModal = () => {
|
||||
showModal(MODAL_TYPES.DELETE_MODAL);
|
||||
};
|
||||
|
||||
const updateModal = () => {
|
||||
const updateModal = () => {
|
||||
showModal(MODAL_TYPES.UPDATE_MODAL);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button variant={ButtonVariant.primary} onClick={createModal}>
|
||||
<>
|
||||
<Button variant={ButtonVariant.primary} onClick={createModal}>
|
||||
Create Modal
|
||||
</Button>
|
||||
<br />
|
||||
<br />
|
||||
<Button variant={ButtonVariant.primary} onClick={deleteModal}>
|
||||
</Button>
|
||||
<br />
|
||||
<br />
|
||||
<Button variant={ButtonVariant.primary} onClick={deleteModal}>
|
||||
Delete Modal
|
||||
</Button>
|
||||
<br />
|
||||
<br />
|
||||
<Button variant={ButtonVariant.primary} onClick={updateModal}>
|
||||
</Button>
|
||||
<br />
|
||||
<br />
|
||||
<Button variant={ButtonVariant.primary} onClick={updateModal}>
|
||||
Update Modal
|
||||
</Button>
|
||||
</>
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
There are three buttons in the AppLayout component: create modal, delete modal, and update modal. Each modal is mapped with the corresponding `modalType`: `CREATE_MODAL`, `DELETE_MODAL`, or `UPDATE_MODAL`.
|
||||
There are three buttons in the AppLayout component: create modal, delete modal, and update modal. Each modal is mapped with the corresponding `modalType` : `CREATE_MODAL`, `DELETE_MODAL`, or `UPDATE_MODAL`.
|
||||
|
||||
### Use global dialogs
|
||||
|
||||
@@ -315,22 +310,20 @@ Global modals are a clean and efficient way to handle dialogs in React. They are
|
||||
|
||||
If you'd like to see the code in action, I've included the [complete application][4] I created for this article in a sandbox.
|
||||
|
||||
Leslie Hinson sits down with Andrés Galante, an expert HTML and CSS coder who travels the world...
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/5/global-modals-react
|
||||
|
||||
作者:[Ajay Pratap][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/ajaypratap
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/browser_web_internet_website.png?itok=g5B_Bw62 (Digital creative of a browser on the internet)
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/browser_web_internet_website.png
|
||||
[2]: https://reactjs.org/
|
||||
[3]: https://www.patternfly.org/v4/
|
||||
[4]: https://codesandbox.io/s/affectionate-pine-gib74
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
[#]: subject: (Get started with Java serverless functions)
|
||||
[#]: via: (https://opensource.com/article/21/6/java-serverless-functions)
|
||||
[#]: author: (Daniel Oh https://opensource.com/users/daniel-oh)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: "Get started with Java serverless functions"
|
||||
[#]: via: "https://opensource.com/article/21/6/java-serverless-functions"
|
||||
[#]: author: "Daniel Oh https://opensource.com/users/daniel-oh"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Get started with Java serverless functions
|
||||
======
|
||||
Quarkus allows you to develop serverless workloads with familiar Java
|
||||
technology.
|
||||
Quarkus allows you to develop serverless workloads with familiar Java technology.
|
||||
|
||||
![Tips and gears turning][1]
|
||||
|
||||
Image by: opensource.com
|
||||
|
||||
The [serverless Java][2] journey started out with functions—small snippets of code running on demand. This phase didn't last long. Although functions based on virtual machine architecture in the 1.0 phase made this paradigm very popular, as the graphic below shows, there were limits around execution time, protocols, and poor local-development experience.
|
||||
|
||||
Developers then realized that they could apply the same serverless traits and benefits to microservices and Linux containers. This launched the 1.5 phase, where some serverless containers completely abstracted [Kubernetes][3], delivering the serverless experience through [Knative][4] or another abstraction layer that sits on top of it.
|
||||
@@ -21,24 +23,21 @@ In the 2.0 phase, serverless starts to handle more complex orchestration and int
|
||||
|
||||
![The serverless Java journey][5]
|
||||
|
||||
(Daniel Oh, [CC BY-SA 4.0][6])
|
||||
|
||||
Before Java developers can start developing new serverless functions, their first task is to choose a new cloud-native Java framework that allows them to run Java functions quicker with a smaller memory footprint than traditional monolithic applications. This can be applied to various infrastructure environments, from physical servers to virtual machines to containers in multi- and hybrid-cloud environments.
|
||||
|
||||
Developers might consider an opinionated Spring framework that uses the `java.util.function` package in [Spring Cloud Function][7] to support the development of imperative and reactive functions. Spring also enables developers to deploy Java functions to installable serverless platforms such as [Kubeless][8], [Apache OpenWhisk][9], [Fission][10], and [Project Riff][11]. However, there are concerns about slow startup and response times and heavy memory-consuming processes with Spring. This problem can be worse when running Java functions on scalable container environments such as Kubernetes.
|
||||
Developers might consider an opinionated Spring framework that uses the `java.util.function` package in [Spring Cloud Function][6] to support the development of imperative and reactive functions. Spring also enables developers to deploy Java functions to installable serverless platforms such as [Kubeless][7], [Apache OpenWhisk][8], [Fission][9], and [Project Riff][10]. However, there are concerns about slow startup and response times and heavy memory-consuming processes with Spring. This problem can be worse when running Java functions on scalable container environments such as Kubernetes.
|
||||
|
||||
[Quarkus][12] is a new open source cloud-native Java framework that can help solve these problems. It aims to design serverless applications and write cloud-native microservices for running on cloud infrastructures (e.g., Kubernetes).
|
||||
[Quarkus][11] is a new open source cloud-native Java framework that can help solve these problems. It aims to design serverless applications and write cloud-native microservices for running on cloud infrastructures (e.g., Kubernetes).
|
||||
|
||||
Quarkus rethinks Java, using a closed-world approach to building and running it. It has turned Java into a runtime that's comparable to Go. Quarkus also includes more than 100 extensions that integrate enterprise capabilities, including database access, serverless integration, messaging, security, observability, and business automation.
|
||||
|
||||
Here is a quick example of how developers can scaffold a Java serverless function project with Quarkus.
|
||||
|
||||
### 1\. Create a Quarkus serverless Maven project
|
||||
### 1. Create a Quarkus serverless Maven project
|
||||
|
||||
Developers have multiple options to install a local Kubernetes cluster, including [Minikube][13] and [OKD][14] (OpenShift Kubernetes Distribution). This tutorial uses an OKD cluster for a developer's local environment because of the easy setup of serverless functionality on Knative and DevOps toolings. These guides for [OKD installation][15] and [Knative operator installation][16] offer more information about setting them up.
|
||||
|
||||
The following command generates a Quarkus project (e.g., `quarkus-serverless-restapi`) to expose a simple REST API and download a `quarkus-openshift` extension for Knative service deployment:
|
||||
Developers have multiple options to install a local Kubernetes cluster, including [Minikube][12] and [OKD][13] (OpenShift Kubernetes Distribution). This tutorial uses an OKD cluster for a developer's local environment because of the easy setup of serverless functionality on Knative and DevOps toolings. These guides for [OKD installation][14] and [Knative operator installation][15] offer more information about setting them up.
|
||||
|
||||
The following command generates a Quarkus project (e.g., `quarkus-serverless-restapi` ) to expose a simple REST API and download a `quarkus-openshift` extension for Knative service deployment:
|
||||
|
||||
```
|
||||
$ mvn io.quarkus:quarkus-maven-plugin:1.13.4.Final:create \
|
||||
@@ -48,50 +47,45 @@ $ mvn io.quarkus:quarkus-maven-plugin:1.13.4.Final:create \
|
||||
-DclassName="org.acme.getting.started.GreetingResource"
|
||||
```
|
||||
|
||||
### 2\. Run serverless functions locally
|
||||
### 2. Run serverless functions locally
|
||||
|
||||
Run the application using Quarkus development mode to check if the REST API works, then tweak the code a bit:
|
||||
|
||||
|
||||
```
|
||||
`$ ./mvnw quarkus:dev`
|
||||
$ ./mvnw quarkus:dev
|
||||
```
|
||||
|
||||
The output will look like this:
|
||||
|
||||
|
||||
```
|
||||
__ ____ __ _____ ___ __ ____ ______
|
||||
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
|
||||
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
|
||||
\--\\___\\_\\____/_/ |_/_/|_/_/|_|\\____/___/
|
||||
INFO [io.quarkus] (Quarkus Main Thread) quarkus-serverless-restapi 1.0.0-SNAPSHOT on JVM (powered by Quarkus xx.xx.xx.) started in 2.386s. Listening on: <http://localhost:8080>
|
||||
__ ____ __ _____ ___ __ ____ ______
|
||||
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
|
||||
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
|
||||
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
|
||||
INFO [io.quarkus] (Quarkus Main Thread) quarkus-serverless-restapi 1.0.0-SNAPSHOT on JVM (powered by Quarkus xx.xx.xx.) started in 2.386s. Listening on: http://localhost:8080
|
||||
INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
|
||||
INFO [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, kubernetes, resteasy]
|
||||
```
|
||||
|
||||
> **Note**: Keep your Quarkus application running to use Live Coding. This allows you to avoid having to rebuild, redeploy the application, and restart the runtime whenever the code changes.
|
||||
|
||||
Now you can hit the REST API with a quick `curl` command. The output should be `Hello RESTEasy`:
|
||||
|
||||
Now you can hit the REST API with a quick `curl` command. The output should be `Hello RESTEasy` :
|
||||
|
||||
```
|
||||
$ curl localhost:8080/hello
|
||||
Hello RESTEasy
|
||||
```
|
||||
|
||||
Tweak the return text in `GreetingResource.java`:
|
||||
|
||||
Tweak the return text in `GreetingResource.java` :
|
||||
|
||||
```
|
||||
public [String][17] hello() {
|
||||
public String hello() {
|
||||
return "Quarkus Function on Kubernetes";
|
||||
}
|
||||
```
|
||||
|
||||
You will see new output when you reinvoke the REST API:
|
||||
|
||||
|
||||
```
|
||||
$ curl localhost:8080/hello
|
||||
Quarkus Function on Kubernetes
|
||||
@@ -99,87 +93,77 @@ Quarkus Function on Kubernetes
|
||||
|
||||
There's not been a big difference between normal microservices and serverless functions. A benefit of Quarkus is that it enables developers to use any microservice to deploy Kubernetes as a serverless function.
|
||||
|
||||
### 3\. Deploy the functions to a Knative service
|
||||
### 3. Deploy the functions to a Knative service
|
||||
|
||||
If you haven't already, [create a namespace][18] (e.g., `quarkus-serverless-restapi`) on your OKD (Kubernetes) cluster to deploy this Java serverless function.
|
||||
|
||||
Quarkus enables developers to generate Knative and Kubernetes resources by adding the following variables in `src/main/resources/application.properties`:
|
||||
If you haven't already, [create a namespace][16] (e.g., `quarkus-serverless-restapi` ) on your OKD (Kubernetes) cluster to deploy this Java serverless function.
|
||||
|
||||
Quarkus enables developers to generate Knative and Kubernetes resources by adding the following variables in `src/main/resources/application.properties` :
|
||||
|
||||
```
|
||||
quarkus.container-image.group=quarkus-serverless-restapi <1>
|
||||
quarkus.container-image.registry=image-registry.openshift-image-registry.svc:5000 <2>
|
||||
quarkus.kubernetes-client.trust-certs=true <3>
|
||||
quarkus.kubernetes.deployment-target=knative <4>
|
||||
quarkus.kubernetes.deploy=true <5>
|
||||
quarkus.openshift.build-strategy=docker <6>
|
||||
quarkus.container-image.group=quarkus-serverless-restapi <1>
|
||||
quarkus.container-image.registry=image-registry.openshift-image-registry.svc:5000 <2>
|
||||
quarkus.kubernetes-client.trust-certs=true <3>
|
||||
quarkus.kubernetes.deployment-target=knative <4>
|
||||
quarkus.kubernetes.deploy=true <5>
|
||||
quarkus.openshift.build-strategy=docker <6>
|
||||
```
|
||||
|
||||
> Legend:
|
||||
>
|
||||
> <1> Define a project name where you deploy a serverless application
|
||||
> <2> The container registry to use
|
||||
> <3> Use self-signed certs in this simple example to trust them
|
||||
> <4> Enable the generation of Knative resources
|
||||
> <5> Instruct the extension to deploy to OpenShift after the container image is built
|
||||
> <6> Set the Docker build strategy
|
||||
|
||||
> <1> Define a project name where you deploy a serverless application
|
||||
<2> The container registry to use
|
||||
<3> Use self-signed certs in this simple example to trust them
|
||||
<4> Enable the generation of Knative resources
|
||||
<5> Instruct the extension to deploy to OpenShift after the container image is built
|
||||
<6> Set the Docker build strategy
|
||||
|
||||
This command builds the application then deploys it directly to the OKD cluster:
|
||||
|
||||
|
||||
```
|
||||
`$ ./mvnw clean package -DskipTests`
|
||||
$ ./mvnw clean package -DskipTests
|
||||
```
|
||||
|
||||
> **Note:** Make sure to log in to the right project (e.g., `quarkus-serverless-restapi`) by using the `oc login` command ahead of time.
|
||||
> **Note:** Make sure to log in to the right project (e.g., `quarkus-serverless-restapi` ) by using the `oc login` command ahead of time.
|
||||
|
||||
The output should end with `BUILD SUCCESS`.
|
||||
|
||||
Add a Quarkus label to the Knative service with this `oc` command:
|
||||
|
||||
|
||||
```
|
||||
$ oc label rev/quarkus-serverless-restapi-00001
|
||||
$ oc label rev/quarkus-serverless-restapi-00001
|
||||
app.openshift.io/runtime=quarkus --overwrite
|
||||
```
|
||||
|
||||
Then access the OKD web console to go to the [Topology view in the Developer perspective][19]. You might see that your pod (serverless function) is already scaled down to zero (white-line circle).
|
||||
Then access the OKD web console to go to the [Topology view in the Developer perspective][17]. You might see that your pod (serverless function) is already scaled down to zero (white-line circle).
|
||||
|
||||
![Topology view][20]
|
||||
![Topology view][18]
|
||||
|
||||
(Daniel Oh, [CC BY-SA 4.0][6])
|
||||
|
||||
### 4\. Test the functions on Kubernetes
|
||||
### 4. Test the functions on Kubernetes
|
||||
|
||||
Retrieve a route `URL` of the serverless function by running the following `oc` command:
|
||||
|
||||
|
||||
```
|
||||
$ oc get rt/quarkus-serverless-restapi
|
||||
[...]
|
||||
NAME URL READY REASON
|
||||
quarkus-serverless[...] <http://quarkus\[...\].SUBDOMAIN> True
|
||||
quarkus-serverless[...] http://quarkus[...].SUBDOMAIN True
|
||||
```
|
||||
|
||||
Access the route `URL` with a `curl` command:
|
||||
|
||||
|
||||
```
|
||||
`$ curl http://quarkus-serverless-restapi-quarkus-serverless-restapi.SUBDOMAIN/hello`
|
||||
$ curl http://quarkus-serverless-restapi-quarkus-serverless-restapi.SUBDOMAIN/hello
|
||||
```
|
||||
|
||||
In a few seconds, you will get the same result as you got locally:
|
||||
|
||||
|
||||
```
|
||||
`Quarkus Function on Kubernetes`
|
||||
Quarkus Function on Kubernetes
|
||||
```
|
||||
|
||||
When you return to the Topology view in the OKD cluster, the Knative service scales up automatically.
|
||||
|
||||
![Scaling the Knative Function][21]
|
||||
|
||||
(Daniel Oh, [CC BY-SA 4.0][6])
|
||||
![Scaling the Knative Function][19]
|
||||
|
||||
This Knative service pod will go down to zero again in 30 seconds because of Knative serving's default setting.
|
||||
|
||||
@@ -189,37 +173,37 @@ The serverless journey has evolved, starting with functions on virtual machines
|
||||
|
||||
The next article in this series will guide you on optimizing Java serverless functions in Kubernetes for faster startup time and small memory footprints at scale.
|
||||
|
||||
Image by: (Daniel Oh, CC BY-SA 4.0)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/6/java-serverless-functions
|
||||
|
||||
作者:[Daniel Oh][a]
|
||||
选题:[lujun9972][b]
|
||||
选题:[lkxed][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/daniel-oh
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/gears_devops_learn_troubleshooting_lightbulb_tips_520.png?itok=HcN38NOk (Tips and gears turning)
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/gears_devops_learn_troubleshooting_lightbulb_tips_520.png
|
||||
[2]: https://opensource.com/article/21/5/what-serverless-java
|
||||
[3]: https://opensource.com/article/19/6/reasons-kubernetes
|
||||
[4]: https://cloud.google.com/knative/
|
||||
[5]: https://opensource.com/sites/default/files/uploads/serverless-journey.png (The serverless Java journey)
|
||||
[6]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[7]: https://spring.io/serverless
|
||||
[8]: https://kubeless.io/
|
||||
[9]: https://openwhisk.apache.org/
|
||||
[10]: https://fission.io/
|
||||
[11]: https://projectriff.io/
|
||||
[12]: https://quarkus.io/
|
||||
[13]: https://minikube.sigs.k8s.io/docs/start/
|
||||
[14]: https://docs.okd.io/latest/welcome/index.html
|
||||
[15]: https://docs.okd.io/latest/installing/index.html
|
||||
[16]: https://knative.dev/docs/install/knative-with-operators/
|
||||
[17]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+string
|
||||
[18]: https://docs.okd.io/latest/applications/projects/configuring-project-creation.html
|
||||
[19]: https://docs.okd.io/latest/applications/application_life_cycle_management/odc-viewing-application-composition-using-topology-view.html
|
||||
[20]: https://opensource.com/sites/default/files/uploads/topologyview.png (Topology view)
|
||||
[21]: https://opensource.com/sites/default/files/uploads/scale-up-knative-function.png (Scaling the Knative Function)
|
||||
[5]: https://opensource.com/sites/default/files/uploads/serverless-journey.png
|
||||
[6]: https://spring.io/serverless
|
||||
[7]: https://kubeless.io/
|
||||
[8]: https://openwhisk.apache.org/
|
||||
[9]: https://fission.io/
|
||||
[10]: https://projectriff.io/
|
||||
[11]: https://quarkus.io/
|
||||
[12]: https://minikube.sigs.k8s.io/docs/start/
|
||||
[13]: https://docs.okd.io/latest/welcome/index.html
|
||||
[14]: https://docs.okd.io/latest/installing/index.html
|
||||
[15]: https://knative.dev/docs/install/knative-with-operators/
|
||||
[16]: https://docs.okd.io/latest/applications/projects/configuring-project-creation.html
|
||||
[17]: https://docs.okd.io/latest/applications/application_life_cycle_management/odc-viewing-application-composition-using-topology-view.html
|
||||
[18]: https://opensource.com/sites/default/files/uploads/topologyview.png
|
||||
[19]: https://opensource.com/sites/default/files/uploads/scale-up-knative-function.png
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
[#]: subject: (How to Convert File Formats With Pandoc in Linux [Quick Guide])
|
||||
[#]: via: (https://itsfoss.com/pandoc-convert-file/)
|
||||
[#]: author: (Bill Dyer https://itsfoss.com/author/bill/)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
How to Convert File Formats With Pandoc in Linux [Quick Guide]
|
||||
======
|
||||
|
||||
In an earlier article, I covered the [procedure to batch convert a handful of Markdown files to HTML][1] using pandoc. In that article, multiple HTML files were created, but pandoc can do much more. It has been called “the Swiss army knife” of document conversion – and with good reason. There isn’t a lot that it can’t do.
|
||||
|
||||
[Pandoc][2] can covert .docx, .odt, .html, .epub, LaTeX, DocBook, etc. to these and other formats, such as JATS, TEI Simple, AsciiDoc, and more.
|
||||
|
||||
Yes, this means that pandoc can convert .docx files to .pdf and .html, but you may be thinking: “Word can export files to .pdf and .html too. Why would I need pandoc?”
|
||||
|
||||
You would have a good point there, but since pandoc can convert so many formats, it could well become your go-to tool for all of your conversion tasks. For example, many of us know that [Markdown editors][3] can export its Markdown files to .html. With pandoc, Markdown files can be converted to numerous other formats as well.
|
||||
|
||||
I rarely have Markdown export to HTML; I normally let pandoc do it.
|
||||
|
||||
### Converting File Formats with Pandoc
|
||||
|
||||
![][4]
|
||||
|
||||
Here, I will convert Markdown files into a few different formats. I do almost all of my writing using Markdown syntax, but I often have to convert to another format: .docx files are usually required for school work, .html for web pages that I create – and for .epub work, .pdf for flyers and handouts, and even an occasional TEI Simple file for a university digital humanities project. Pandoc can handle all of these, and more, easily.
|
||||
|
||||
First, you need to [install pandoc][5]. Also, to create .pdf files, LaTeX will be needed as well. The package I prefer is [TeX Live][6].
|
||||
|
||||
**Note**: If you would like to try out pandoc before installing it, there is an online try-out page at: <http://pandoc.org/try/>
|
||||
|
||||
#### Installing pandoc and texlive
|
||||
|
||||
Users of Ubuntu and other Debian distros can type the following commands in the terminal:
|
||||
|
||||
```
|
||||
sudo apt-get update
|
||||
sudo apt-get install pandoc texlive
|
||||
```
|
||||
|
||||
Notice on the second line, you are installing pandoc and texlive in one shot. [apt-get command][7] will have no problem with this, but go get some coffee; this may take a few minutes.
|
||||
|
||||
#### Getting to Conversion
|
||||
|
||||
Once pandoc and texlive are installed, you can burn through some work!
|
||||
|
||||
The sample document for this project will be an article that was first published in the _North American Review_ in December of 1894, and is titled: “How To Repel Train Robbers”. The Markdown file that I will be using was created some time ago as part of a restoration project.
|
||||
|
||||
The file: `how_to_repel_train_robbers.md` is located in my Documents directory, in a sub-directory named samples. Here is what it looks like in Ghostwriter.
|
||||
|
||||
![Markdown file in Ghostwriter][8]
|
||||
|
||||
I want to create .docx, .pdf, and .html versions of this file.
|
||||
|
||||
#### The First Conversion
|
||||
|
||||
I’ll start with making a .pdf copy first, since I went through the trouble of installing a LaTeX package.
|
||||
|
||||
While in the ~/Documents/samples/ directory, I type the following to create a .pdf file:
|
||||
|
||||
```
|
||||
pandoc -o htrtr.pdf how_to_repel_train_robbers.md
|
||||
```
|
||||
|
||||
The above command will create a file called htrtr.pdf from the how_to_repel_train_robbers.md file. The reason I used htrtr as a name was that it is shorter than how_to_repel_train_robbers – htrtr is the first letter of each word in the long title.
|
||||
|
||||
Here is a snapshot of the .pdf file once it is made:
|
||||
|
||||
![Converted PDF file viewed in Ocular][9]
|
||||
|
||||
#### The Second Conversion
|
||||
|
||||
Next, I want to create a .docx file. The command is almost identical to the one I used to create the .pdf and it is:
|
||||
|
||||
```
|
||||
pandoc -o htrtr.docx how_to_repel_train_robbers.md
|
||||
```
|
||||
|
||||
In no time, a .docx file is created. Here is what it looks like in Libre Writer:
|
||||
|
||||
![Converted DOCX file viewed in Libre Writer][10]
|
||||
|
||||
#### The Third Conversion
|
||||
|
||||
I may want to post this on the web, so a web page would be nice. I will create a .html file with this command:
|
||||
|
||||
```
|
||||
pandoc -o htrtr.html how_to_repel_train_robbers.md
|
||||
```
|
||||
|
||||
Again, the command to create it is very much like the last two conversions. Here is what the .html file looks like in a browser:
|
||||
|
||||
![Converted HTML file viewed in Firefox][11]
|
||||
|
||||
#### Noticed Anything Yet?
|
||||
|
||||
Let’s look at the past commands again. They were:
|
||||
|
||||
```
|
||||
pandoc -o htrtr.pdf how_to_repel_train_robbers.md
|
||||
pandoc -o htrtr.docx how_to_repel_train_robbers.md
|
||||
pandoc -o htrtr.html how_to_repel_train_robbers.md
|
||||
```
|
||||
|
||||
The only thing different about these three commands is the extension next to htrtr. This gives you a hint that pandoc relies on the extension of the output filename you provide.
|
||||
|
||||
### Conclusion
|
||||
|
||||
Pandoc can do far more than the three little conversions done here. If you write with a preferred format, but need to convert the file to another format, chances are great that pandoc will be able to do it for you.
|
||||
|
||||
What would you do with this? Would you automate this? What if you had a web site that had articles for your readers to download? You could modify these little commands to work as a script and your readers could decide which format they would like. You could offer .docx, .pdf, .odt, .epub, or more. Your readers choose, the proper conversion script runs, and your readers download their file. It can be done.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/pandoc-convert-file/
|
||||
|
||||
作者:[Bill Dyer][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/bill/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/convert-markdown-files/
|
||||
[2]: https://pandoc.org/
|
||||
[3]: https://itsfoss.com/best-markdown-editors-linux/
|
||||
[4]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/06/pandoc-quick-guide.png?resize=800%2C450&ssl=1
|
||||
[5]: https://pandoc.org/installing.html
|
||||
[6]: https://www.tug.org/texlive/
|
||||
[7]: https://itsfoss.com/apt-get-linux-guide/
|
||||
[8]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/06/convert_with_pandoc_ghostwriter.png?resize=800%2C516&ssl=1
|
||||
[9]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/06/convert_with_pandoc_ocular.png?resize=800%2C509&ssl=1
|
||||
[10]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/06/convert_with_pandoc_libre_writer.png?resize=800%2C545&ssl=1
|
||||
[11]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/06/convert_with_pandoc_firefox.png?resize=800%2C511&ssl=1
|
||||
@@ -1,209 +0,0 @@
|
||||
[#]: subject: (9 reasons I love to use the Qt Creator IDE)
|
||||
[#]: via: (https://opensource.com/article/21/6/qtcreator)
|
||||
[#]: author: (Stephan Avenwedde https://opensource.com/users/hansic99)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (hadisi1993)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
9 reasons I love to use the Qt Creator IDE
|
||||
======
|
||||
Qt Creator is the glue between Qt's rich set of libraries and the
|
||||
programmer.
|
||||
![Business woman on laptop sitting in front of window][1]
|
||||
|
||||
Qt Creator is the Qt framework's default integrated development environment (IDE) and hence the glue between Qt's rich set of libraries and the user. In addition to its basic features such as intelligent code completion, debugging, and project administration, Qt Creator offers a lot of nice features that make software development easier.
|
||||
|
||||
In this article, I will highlight some of my favorite [Qt Creator][2] features.
|
||||
|
||||
### Dark mode
|
||||
|
||||
My first question when working with a new application is: _Is there a dark mode?_ Qt Creator answers with: _Which dark mode do you prefer?_
|
||||
|
||||
You can activate dark mode in the Options menu. On the top menu bar, go to **Tools**, select **Options**, and go to the **Environment** section. Here is where you can select the general appearance:
|
||||
|
||||
![ QT Creator dark mode][3]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
### Custom appearance
|
||||
|
||||
Like every Qt application, Qt Creator's appearance is highly customizable with style sheets. Below, you can follow along with my approach to give Qt Creator a fancy look.
|
||||
|
||||
Create the file `mycustomstylesheet.css` with the following content:
|
||||
|
||||
|
||||
```
|
||||
QMenuBar { background-color: olive }
|
||||
QMenuBar::item { background-color: olive }
|
||||
QMenu { background-color : beige; color : black }
|
||||
QLabel { color: green }
|
||||
```
|
||||
|
||||
Then start Qt Creator from the command line and pass the style sheet as a parameter with:
|
||||
|
||||
|
||||
```
|
||||
`qtcreator -stylesheet=mycustomstylesheet.css`
|
||||
```
|
||||
|
||||
It should look like this:
|
||||
|
||||
![QT Creator custom stylesheet][5]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
Read more about style sheets in the [documentation][6].
|
||||
|
||||
### Command-line parameters
|
||||
|
||||
Qt Creator accepts many command-line options. For example, if you want to automatically load your current project at startup, pass the path to the `*.pro-file`:
|
||||
|
||||
|
||||
```
|
||||
`qtcreator ~/MyProject/MyQtProject.pro`
|
||||
```
|
||||
|
||||
You can even pass the file and the line number that should be opened by default. This command opens the file `main.cpp` at line 20:
|
||||
|
||||
|
||||
```
|
||||
`qtcreator ~/MyProject/main.cpp:20`
|
||||
```
|
||||
|
||||
Read more about the Qt Creator-specific command-line options in the [documentation][7].
|
||||
|
||||
Qt Creator is an ordinary Qt application, so, in addition to its own command-line arguments, it also accepts the generic arguments for [QApplication][8] and [QGuiApplication][9].
|
||||
|
||||
### Cross-compiling
|
||||
|
||||
Qt Creator allows you to define several toolchains, called **Kits**. A kit defines the binaries and SDK for building and running an application:
|
||||
|
||||
![QT Creator kits][10]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
This allows you to switch between completely different toolchains with just two clicks:
|
||||
|
||||
![Switching between Kits in Qt Creator][11]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
Read more about kits in the [manual][12].
|
||||
|
||||
### Analyzer
|
||||
|
||||
Qt Creator integrates several of the most popular analyzers, such as:
|
||||
|
||||
* [Linux Performance Analyzer][13] (requires a special kernel)
|
||||
* [Valgrind][14] memory profiler
|
||||
* [Clang-Tidy and Clazy][15], a linter for C/C++
|
||||
|
||||
|
||||
|
||||
![Qt Creator analyzer][16]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
### Debugger
|
||||
|
||||
When it comes to debugging, Qt Creator has a nice interface for GNU Debugger (GDB). I like its easy way of inspecting container types and creating conditional breakpoints:
|
||||
|
||||
![Qt Creator debugger][17]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
### FakeVim
|
||||
|
||||
If you like Vim, enable FakeVim in the settings to control Qt Creator like Vim. Go to **Tools** and select **Options**. In the **FakeVim** section, you can find many switches to customize FakeVim's behavior. In addition to the editor functions, you can also map your own functions to custom Vim commands.
|
||||
|
||||
For example, you can map the function **Build Project** to the `build` command:
|
||||
|
||||
![FakeVim in Qt Creator][18]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
Back in the editor, when you press the colon button and enter `build`, Qt Creator starts a build process with the configured toolchain:
|
||||
|
||||
![FakeVim in Qt Creator][19]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
You can find more information about FakeVim [in the docs][20].
|
||||
|
||||
### Class inspector
|
||||
|
||||
When developing in C++, open the right window by clicking on the button in the bottom-right corner of Qt Creator. Then choose **Outline** from the dropdown menu on the top border. If you have a header file open on the left pane, you get a nice overview of the defined classes or types. If you switch to a source file (`*.cpp`), the right pane will list all defined methods, and you can jump to one by double-clicking on it:
|
||||
|
||||
![List of classes in Qt Creator][21]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
### Project configuration
|
||||
|
||||
Qt Creator projects are built around the `*.pro-file` in the project's directory. You can add your own custom configuration to the project's `*.pro-file` of your project. I added `my_special_config` to the `*.pro-file`, which adds `MY_SPECIAL_CONFIG` to the compiler defined:
|
||||
|
||||
|
||||
```
|
||||
QT -= gui
|
||||
|
||||
CONFIG += c++11 console
|
||||
CONFIG -= app_bundle
|
||||
|
||||
CONFIG += my_special_config
|
||||
|
||||
my_special_config {
|
||||
DEFINES += MY_SPECIAL_CONFIG
|
||||
}
|
||||
```
|
||||
|
||||
Qt Creator automatically highlights the code according to the active configuration:
|
||||
|
||||
![Special configuration in Qt Creator][22]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
The `*.pro-file` is written in the [qmake language][23].
|
||||
|
||||
### Summary
|
||||
|
||||
These features are only the tip of the iceberg of what Qt Creator provides. Beginners shouldn't feel overwhelmed by the many features, as Qt Creator is absolutely beginner-friendly. It may even be the easiest way to start developing in C++. To get a complete overview of its features, refer to the [official Qt Creator documentation][24].
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/6/qtcreator
|
||||
|
||||
作者:[Stephan Avenwedde][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/hansic99
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/lenovo-thinkpad-laptop-concentration-focus-windows-office.png?itok=-8E2ihcF (Woman using laptop concentrating)
|
||||
[2]: https://www.qt.io/product/development-tools
|
||||
[3]: https://opensource.com/sites/default/files/uploads/qt_creator_dark_mode.png ( QT Creator dark mode)
|
||||
[4]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[5]: https://opensource.com/sites/default/files/uploads/qt_creator_custom_stylesheet2.png (QT Creator custom stylesheet)
|
||||
[6]: https://doc.qt.io/qt-5/stylesheet-reference.html
|
||||
[7]: https://doc.qt.io/qtcreator/creator-cli.html
|
||||
[8]: https://doc.qt.io/qt-5/qapplication.html#QApplication
|
||||
[9]: https://doc.qt.io/qt-5/qguiapplication.html#supported-command-line-options
|
||||
[10]: https://opensource.com/sites/default/files/uploads/qt_creator_cross_compiling.png (QT Creator kits)
|
||||
[11]: https://opensource.com/sites/default/files/uploads/qt_creator_select_kits.png (Switching between Kits in Qt Creator)
|
||||
[12]: https://doc.qt.io/qtcreator/creator-targets.html
|
||||
[13]: https://doc.qt.io/qtcreator/creator-cpu-usage-analyzer.html
|
||||
[14]: https://doc.qt.io/qtcreator/creator-valgrind-overview.html
|
||||
[15]: https://doc.qt.io/qtcreator/creator-clang-tools.html
|
||||
[16]: https://opensource.com/sites/default/files/uploads/qt_creator_analyzer.png (Qt Creator analyzer)
|
||||
[17]: https://opensource.com/sites/default/files/uploads/qt_creator_debugger2.png (Qt Creator debugger)
|
||||
[18]: https://opensource.com/sites/default/files/uploads/qt_creator_fakevim_ex_commands.png (FakeVim in Qt Creator)
|
||||
[19]: https://opensource.com/sites/default/files/uploads/qt_creator_fakevim_build_commands.png (FakeVim in Qt Creator)
|
||||
[20]: https://doc.qt.io/qtcreator/creator-editor-fakevim.html
|
||||
[21]: https://opensource.com/sites/default/files/uploads/qtcreator_class_overview.png (List of classes in Qt Creator)
|
||||
[22]: https://opensource.com/sites/default/files/uploads/qtcreater_special_config.png (Special configuration in Qt Creator)
|
||||
[23]: https://doc.qt.io/qt-5/qmake-language.html
|
||||
[24]: https://doc.qt.io/qtcreator/
|
||||
@@ -1,88 +0,0 @@
|
||||
[#]: subject: "How to Enable Minimize, Maximize Window Buttons in elementary OS"
|
||||
[#]: via: "https://www.debugpoint.com/2021/08/enable-minimize-maximize-elementary/"
|
||||
[#]: author: "Arindam https://www.debugpoint.com/author/admin1/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
How to Enable Minimize, Maximize Window Buttons in elementary OS
|
||||
======
|
||||
This is how you can enable the Minimize, Maximize window buttons in elementary OS.
|
||||
|
||||
Many people (mostly new users to elementary OS) asks these questions in various forums:
|
||||
|
||||
1. How do I enable minimize buttons in elementary OS?
|
||||
2. How to I enable restore, minimize, maximize?
|
||||
3. Is it possible to bring back the minimize and maximize buttons?
|
||||
|
||||
And they are completely valid questions, and It’s okay to ask questions. Right? This guide to help them to get those buttons in elementary OS.
|
||||
|
||||
The Pantheon desktop which is used by elementary OS does not come with default standard window buttons. The reason primarily being a different concept of handling user behavior and activities via Dock and Application menu. Arguably, this design or implementation of this behavior mimics macOS.
|
||||
|
||||
That said, many users prefers the window buttons because it is a “muscle-memory'” thing and some migrated from other desktop environments, even windows.
|
||||
|
||||
Although elementary doesn’t provide you this as a default settings, you can still enable it. Here’s how.
|
||||
|
||||
### Enable minimize maximize Buttons – elementary OS
|
||||
|
||||
Open a terminal and install the software properties common which is required for adding a PPA. By default, this package is not installed in elementary OS (don’t ask me why, seriously?).
|
||||
|
||||
```
|
||||
sudo apt install software-properties-common
|
||||
```
|
||||
|
||||
#### elementary OS 6 Odin
|
||||
|
||||
The Tweak tool is renamed with a new name and being developed separately. It is called [Pantheon Tweaks][1]. And using the following commands you can install it.
|
||||
|
||||
```
|
||||
sudo add-apt-repository -y ppa:philip.scott/pantheon-tweaks
|
||||
sudo apt install -y pantheon-tweaks
|
||||
```
|
||||
|
||||
#### elementary OS 5 Juno and below
|
||||
|
||||
If you are using elementary OS 5 June and below, you can install the earlier [elementary-tweaks][2] using the same PPA. Follow the below commands from terminal.
|
||||
|
||||
```
|
||||
sudo add-apt-repository -y ppa:philip.scott/elementary-tweaks
|
||||
sudo apt install -y elementary-tweaks
|
||||
```
|
||||
|
||||
#### Change the settings
|
||||
|
||||
* After installation, click on the Application at the top bar and open System Settings.In the System settings window, click on Tweaks under Personal section.
|
||||
* In the Tweaks window, go to Appearance section.
|
||||
* Under Window Controls, select Layout: Windows.
|
||||
|
||||
![enable minimize maximize buttons elementary OS][3]
|
||||
|
||||
* And you should have the minimized, maximize and close button on the right side of the top window bar.
|
||||
|
||||
There are other combinations as well, such as Ubuntu, macOS, etc. You can choose whatever you feel like:
|
||||
|
||||
![Other Options of Window buttons in elementary][4]
|
||||
|
||||
This step completes the guide. There are other options in gsettings which you may try to use, but the window manager gala recently removed those options. Hence, they may not work at the moment.
|
||||
|
||||
I hope this guide helps you to enable minimize maximize buttons elementary OS. Let me know in the comment box below if you need any help.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.debugpoint.com/2021/08/enable-minimize-maximize-elementary/
|
||||
|
||||
作者:[Arindam][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.debugpoint.com/author/admin1/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://github.com/pantheon-tweaks/pantheon-tweaks
|
||||
[2]: https://github.com/elementary-tweaks/elementary-tweaks
|
||||
[3]: https://www.debugpoint.com/wp-content/uploads/2021/08/enable-minimize-maximize-buttons-elementary-OS.png
|
||||
[4]: https://www.debugpoint.com/wp-content/uploads/2021/08/Other-Options-of-Window-buttons-in-elementary.jpg
|
||||
@@ -0,0 +1,253 @@
|
||||
[#]: subject: "The Definitive Guide to Using and Customizing the Dock in Ubuntu"
|
||||
[#]: via: "https://itsfoss.com/customize-ubuntu-dock/"
|
||||
[#]: author: "Abhishek Prakash https://itsfoss.com/author/abhishek/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
The Definitive Guide to Using and Customizing the Dock in Ubuntu
|
||||
======
|
||||
When you log into Ubuntu, you’ll see the dock on the left side with some application icons on it. This dock (also known as launcher or sometimes as panel) allows you to quickly launch your frequently used programs.
|
||||
|
||||
![Ubuntu Dock][1]
|
||||
|
||||
I rely heavily on the dock and I am going to share a few tips about using the dock effectively and customize its looks and position.
|
||||
|
||||
You’ll learn the following in this tutorial:
|
||||
|
||||
* Basic usage of the dock: adding more applications and using shortcuts for launching applications.
|
||||
* Customize the looks of the dock: Change the icon size, icon positions.
|
||||
* Change the position: for single screen and multi-monitor setup
|
||||
* Hide mounted disk from the dock
|
||||
* Auto-hide or disable the dock
|
||||
* Possibility of additional dock customization with dconf-editor
|
||||
* Replace dock with other docking applications
|
||||
|
||||
I’ll use the terms dock, panel and launcher in the tutorial. All of them refer to the same thing.
|
||||
|
||||
### Using the Ubuntu dock: Absolute basic that you must know
|
||||
|
||||
If you are new to Ubuntu, you should know a few things about using the dock. You’ll eventually discover these dock features, I’ll just speed up the discovery process for you.
|
||||
|
||||
![A Video from YouTube][2]
|
||||
|
||||
[Subscribe to our YouTube channel for more Linux videos][3]
|
||||
|
||||
#### Add new applications to the dock (or remove them)
|
||||
|
||||
The steps are simple. Search for the application from the menu and run it.
|
||||
|
||||
The running application appears in the dock, below all other icons. Right click on it and select the “Add to Favorites” option. This will lock the icon to the dock.
|
||||
|
||||
![Right click on the icon and select "Add to Favorites" to add icons to the dock in Ubuntu][4]
|
||||
|
||||
Removing an app icon from the doc is even easier. You don’t even need to run the application. Simply right click on it and select “Remove From Favorites”.
|
||||
|
||||
![Right-click on the icon and select "Remove from Favorites" to remove icons from the dock in Ubuntu][5]
|
||||
|
||||
#### Reorder icon position
|
||||
|
||||
By default, new application icons are added after all the other icons on the launcher. You don’t have to live with it as it is.
|
||||
|
||||
To change the order of the icons, you just need to drag and drop to the other position of your choice. No need to “lock it” or any additional effort. It stays on that location until you make some changes again.
|
||||
|
||||
![Reorder Icons On Ubuntu Docks][6]
|
||||
|
||||
#### Right click to get additional options for some apps
|
||||
|
||||
Left-clicking on an icon launches the application or bring it to focus if the application is already running.
|
||||
|
||||
Right-clicking the icon gives you additional options. Different applications will have different options.
|
||||
|
||||
For browsers, you can open a new private window or preview all the running windows.
|
||||
|
||||
![Right Click Icons Ubuntu Dock][7]
|
||||
|
||||
For file manager, you can go to all the bookmarked directories or preview opened windows.
|
||||
|
||||
You can, of course, quit the application. Most applications will quit while some applications like Telegram will be minimized to the system tray.
|
||||
|
||||
#### Use keyboard shortcut to launch applications quickly [Not many people know about this one]
|
||||
|
||||
The dock allows you to launch an application in a single mouse click. But if you are like me, you can save that mouse click with a keyboard shortcut.
|
||||
|
||||
Using the Super/Window key and a number key will launch the application on that position.
|
||||
|
||||
![Keyboard Shortcut For Ubuntu Dock][8]
|
||||
|
||||
If the application is already running, it is brought to focus, i.e. it appears in front of all the other running application windows.
|
||||
|
||||
Since it is position-based, you should make sure that you don’t reorder the icons all the time. Personally, I keep Firefox at position 1, file manager at 2 and the alternate browser at 3 and so on until number 9. This way, I quickly launch the file manager with Super+2.
|
||||
|
||||
I find it easier specially because I have a three screen setup and moving the mouse to the launcher on the first screen is a bit too much of trouble. You can enable or disable the dock on additional screen. I’ll show that to you later in this tutorial.
|
||||
|
||||
### Change the position of the dock
|
||||
|
||||
By default, the dock is located on the left side of your screen. Some people like the launcher at the bottom, in a more traditional way.
|
||||
|
||||
[Ubuntu allows you to change the position of the dock][9]. You can move it to the bottom or to the right side. I am not sure many people actually put the dock on the top, so moving the dock to the top is not an option here.
|
||||
|
||||
![Change Launcher Position in Ubuntu][10]
|
||||
|
||||
To change the dock position, go to Settings->Appearance. You should see some options under Dock section. You need to change the “Position on screen” settings here.
|
||||
|
||||
![Change Dock Position in Ubuntu][11]
|
||||
|
||||
#### Position of dock on a multiple monitor setup
|
||||
|
||||
If you have multiple screens attached to your system, you can choose whether to display the dock on all screens or one of the chosen screens.
|
||||
|
||||
![Ubuntu Dock Settings Multimonitor][12]
|
||||
|
||||
Personally, I display the dock on my laptop screen only which is my main screen. This gives me maximum space on the additional two screens.
|
||||
|
||||
### Change the appearance of the dock
|
||||
|
||||
Let’s see some more dock customization options in Ubuntu.
|
||||
|
||||
Imagine you added too many applications to the dock or have too many applications open. It will fill up the space and you’ll have to scroll to the top and bottom to go to the applications at end points.
|
||||
|
||||
What you can do here is to change the icon size and the dock will now accommodate more icons. Don’t make it too small, though.
|
||||
|
||||
![Normal Icon Size Dock][13]
|
||||
|
||||
![Smaller Icon Size Dock][14]
|
||||
|
||||
To do that, go to Settings-> Appearance and change it by moving the slider under Icon size. The default icons size is 48 pixels.
|
||||
|
||||
![Changing Icon Size In Ubuntu Dock][15]
|
||||
|
||||
#### Hide mounted disks from the launcher
|
||||
|
||||
If you plug in a USB disk or SD Card, it is mounted to the system, and an icon appear in the launcher immediately. This is helpful because you can right click on it and select safely remove drive option.
|
||||
|
||||
![External Mounted Disks In Ubuntu Dock][16]
|
||||
|
||||
If you somehow find it troublesome, you can turn this feature off. Don’t worry, you can still access the mounted drives from the file manager.
|
||||
|
||||
Open a terminal and use the following command:
|
||||
|
||||
```
|
||||
gsettings set org.gnome.shell.extensions.dash-to-dock show-mounts false
|
||||
```
|
||||
|
||||
The changes take into effect immediately. You won’t be bothered with mounted disk being displayed in the launcher.
|
||||
|
||||
If you want the default behavior back, use this command:
|
||||
|
||||
```
|
||||
gsettings set org.gnome.shell.extensions.dash-to-dock show-mounts true
|
||||
```
|
||||
|
||||
### Change the behavior of dock
|
||||
|
||||
Let’s customize the default behavior of the dock and make it more suitable to your needs.
|
||||
|
||||
#### Enable minimize on click
|
||||
|
||||
If you click on the icon of a running application, its window will be brought to focus. That’s fine. However, if you click on it, nothing happens. By default, clicking on the same icon won’t minimize the application.
|
||||
|
||||
Well, this is the behavior in modern desktop, but I don’t like it. I prefer that the application is minimized when I click on its icon for the second time.
|
||||
|
||||
If you are like me, you may want to [enable click to minimize option in Ubuntu][17]:
|
||||
|
||||
![A Video from YouTube][18]
|
||||
|
||||
To do that, open a terminal and enter the following command:
|
||||
|
||||
```
|
||||
gsettings set org.gnome.shell.extensions.dash-to-dock click-action 'minimize'
|
||||
```
|
||||
|
||||
#### Auto-hide Ubuntu dock and get more screen space
|
||||
|
||||
If you want to utilize the maximum screen space, you can enable auto-hide option for the dock in Ubuntu.
|
||||
|
||||
This will hide the dock, and you’ll get the entire screen. The dock is still accessible, though. Move your cursor to the location of the dock where it used to be, and it will appear again. When the dock reappears, it is overlaid on the running application window. And that’s a good thing otherwise too many elements would start moving on the screen.
|
||||
|
||||
The auto-hide option is available in Settings-> Appearance and under Dock section. Just toggle it.
|
||||
|
||||
![Autohide the Dock Ubuntu][19]
|
||||
|
||||
If you don’t like this behavior, you can enable it again the same way.
|
||||
|
||||
#### Disable Ubuntu dock
|
||||
|
||||
Auto-hide option is good enough for many people, but some users simply don’t like the dock. If you are one of those users, you also have the option to disable the Ubuntu dock entirely.
|
||||
|
||||
Starting with Ubuntu 20.04, you have the Extensions application available at your disposal to [manage GNOME Extensions][20].
|
||||
|
||||
![Gnome Extensions App Ubuntu][21]
|
||||
|
||||
With this Extensions application, you can easily disable or re-enable the dock.
|
||||
|
||||
![Disable Dock Ubuntu][22]
|
||||
|
||||
### Advanced dock customization with dconf-editor [Not recommended]
|
||||
|
||||
##### Warning
|
||||
|
||||
The dconf-editor allows you to change almost every aspect of the GNOME desktop environment. This is both good and bad because you must be careful in editing. Most of the settings can be changed on the fly, without asking for conformation. While you may reset the changes, you could still put your system in such a state that it would be difficult to put things back in order.For this reason, I advise not to play with dconf-editor, specially if you don’t like spending time in troubleshooting and fixing problems or if you are not too familiar with Linux and GNOME.
|
||||
|
||||
The [dconf editor][23] gives you additional options to customize the dock in Ubuntu. Install it from the software center and then navigate to org > gnome > shell > extensions > dash-to-dock. You’ll find plenty of options here. I cannot even list them all here.
|
||||
|
||||
![Dconf Editor Dock][24]
|
||||
|
||||
### Replace the dock in Ubuntu
|
||||
|
||||
There are several third-party dock applications available for Ubuntu and other Linux distributions. You can install a dock of your choice and use it.
|
||||
|
||||
For example, you can install Plank dock from the software center and use it in similar fashion to Ubuntu dock.
|
||||
|
||||
![Plank Dock Ubuntu][25]
|
||||
|
||||
Disabling Ubuntu Dock would be a better idea in this case. It won’t be wise to use multiple docks at the same time.
|
||||
|
||||
### Conclusion
|
||||
|
||||
This tutorial is about customizing the default dock or launcher provided in Ubuntu’s GNOME implementation. Some suggestions should work on the dock in vanilla GNOME as work well.
|
||||
|
||||
I have shown you most of the common Ubuntu dock customization. You don’t need to go and blindly follow all of them. Read and think which one suits your need and then act upon it.
|
||||
|
||||
Was it too trivial or did you learn something new? Would you like to see more such tutorials? I welcome your suggestions and feedback on dock customization.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/customize-ubuntu-dock/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lkxed][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/lkxed
|
||||
[1]: https://itsfoss.com/wp-content/uploads/2021/01/ubuntu-dock.png
|
||||
[2]: https://player.vimeo.com/video/534830884
|
||||
[3]: https://www.youtube.com/c/itsfoss?sub_confirmation=1
|
||||
[4]: https://itsfoss.com/wp-content/uploads/2021/01/add-icons-to-dock.png
|
||||
[5]: https://itsfoss.com/wp-content/uploads/2021/01/remove-icons-from-dock.png
|
||||
[6]: https://itsfoss.com/wp-content/uploads/2021/01/reorder-icons-on-ubuntu-docks-800x430.gif
|
||||
[7]: https://itsfoss.com/wp-content/uploads/2021/01/right-click-icons-ubuntu-dock.png
|
||||
[8]: https://itsfoss.com/wp-content/uploads/2021/01/keyboard-shortcut-for-ubuntu-dock.png
|
||||
[9]: https://itsfoss.com/move-unity-launcher-bottom/
|
||||
[10]: https://itsfoss.com/wp-content/uploads/2021/01/change-launcher-position-ubuntu.png
|
||||
[11]: https://itsfoss.com/wp-content/uploads/2021/01/change-dock-position-ubuntu.png
|
||||
[12]: https://itsfoss.com/wp-content/uploads/2021/01/ubuntu-dock-settings-multimonitor.png
|
||||
[13]: https://itsfoss.com/wp-content/uploads/2021/01/normal-icon-size-dock.jpg
|
||||
[14]: https://itsfoss.com/wp-content/uploads/2021/01/smaller-icon-size-dock.jpg
|
||||
[15]: https://itsfoss.com/wp-content/uploads/2021/01/changing-icon-size-in-ubuntu-dock.png
|
||||
[16]: https://itsfoss.com/wp-content/uploads/2021/01/external-mounted-disks-in-ubuntu-dock.png
|
||||
[17]: https://itsfoss.com/click-to-minimize-ubuntu/
|
||||
[18]: https://giphy.com/embed/52FlrSIMxnZ1qq9koP
|
||||
[19]: https://itsfoss.com/wp-content/uploads/2021/01/autohide-dock-ubuntu.png
|
||||
[20]: https://itsfoss.com/gnome-shell-extensions/
|
||||
[21]: https://itsfoss.com/wp-content/uploads/2020/06/GNOME-extensions-app-ubuntu.jpg
|
||||
[22]: https://itsfoss.com/wp-content/uploads/2021/01/disable-dock-ubuntu.png
|
||||
[23]: https://wiki.gnome.org/Apps/DconfEditor
|
||||
[24]: https://itsfoss.com/wp-content/uploads/2021/01/dconf-editor-dock.png
|
||||
[25]: https://itsfoss.com/wp-content/uploads/2021/01/plank-dock-Ubuntu-800x382.jpg
|
||||
@@ -1,183 +0,0 @@
|
||||
[#]: subject: "A guide to Kubernetes architecture"
|
||||
[#]: via: "https://opensource.com/article/22/2/kubernetes-architecture"
|
||||
[#]: author: "Nived Velayudhan https://opensource.com/users/nivedv"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "MjSeven"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
A guide to Kubernetes architecture
|
||||
======
|
||||
Learn how the different components of Kubernetes architecture fit
|
||||
together so you can be better equipped to diagnose problems, maintain a
|
||||
healthy cluster, and optimize your own workflow.
|
||||
![Parts, modules, containers for software][1]
|
||||
|
||||
You use Kubernetes to orchestrate containers. It's an easy description to say, but understanding what that actually means and how you accomplish it is another matter entirely. If you're running or managing a Kubernetes cluster, then you know that Kubernetes consists of one computer that gets designated as the _control plane_, and lots of other computers that get designated as _worker nodes_. Each of these has a complex but robust stack making orchestration possible, and getting familiar with each component helps understand how it all works.
|
||||
|
||||
![Kubernetes architecture diagram][2]
|
||||
|
||||
(Nived Velayudhan, [CC BY-SA 4.0][3])
|
||||
|
||||
### Control plane components
|
||||
|
||||
You install Kubernetes on a machine called the control plane. It's the one running the Kubernetes daemon, and it's the one you communicate with when starting containers and pods. The following sections describe the control plane components.
|
||||
|
||||
#### Etcd
|
||||
|
||||
Etcd is a fast, distributed, and consistent key-value store used as a backing store for persistently storing Kubernetes object data such as pods, replication controllers, secrets, and services. Etcd is the only place where Kubernetes stores cluster state and metadata. The only component that talks to etcd directly is the Kubernetes API server. All other components read and write data to etcd indirectly through the API server.
|
||||
|
||||
Etcd also implements a watch feature, which provides an event-based interface for asynchronously monitoring changes to keys. Once you change a key, its watchers get notified. The API server component heavily relies on this to get notified and move the current state of etcd towards the desired state.
|
||||
|
||||
_Why should the number of etcd instances be an odd number?_
|
||||
|
||||
You would typically have three, five, or seven etcd instances running in a high-availability (HA) environment, but why? Because etcd is a distributed data store. It is possible to scale it horizontally but also you need to ensure that the data in each instance is consistent, and for this, your system needs to reach a consensus on what the state is. Etcd uses the [RAFT consensus algorithm][4] for this.
|
||||
|
||||
The algorithm requires a majority (or quorum) for the cluster to progress to the next state. If you have only two ectd instances and either of them fails, the etcd cluster can't transition to a new state because no majority exists. If you have three ectd instances, one instance can fail but still have a majority of instances available to reach a quorum.
|
||||
|
||||
#### API server
|
||||
|
||||
The API server is the only component in Kubernetes that directly interacts with etcd. All other components in Kubernetes must go through the API server to work with the cluster state, including the clients (kubectl). The API server has the following functions:
|
||||
|
||||
* Provides a consistent way of storing objects in etcd.
|
||||
* Performs validation of those objects so clients can't store improperly configured objects (which could happen if they write directly to the etcd datastore).
|
||||
* Provides a RESTful API to create, update, modify, or delete a resource.
|
||||
* Provides [optimistic concurrency locking][5], so other clients never override changes to an object in the event of concurrent updates.
|
||||
* Performs authentication and authorization of a request that the client sends. It uses the plugins to extract the client's username, user ID, groups the user belongs to, and determine whether the authenticated user can perform the requested action on the requested resource.
|
||||
* Responsible for [admission control][6] if the request is trying to create, modify, or delete a resource. For example, AlwaysPullImages, DefaultStorageClass, and ResourceQuota.
|
||||
* Implements a watch mechanism (similar to etcd) for clients to watch for changes. This allows components such as the Scheduler and Controller Manager to interact with the API Server in a loosely coupled manner.
|
||||
|
||||
|
||||
|
||||
#### Controller Manager
|
||||
|
||||
In Kubernetes, controllers are control loops that watch the state of your cluster, then make or request changes where needed. Each controller tries to move the current cluster state closer to the desired state. The controller tracks at least one Kubernetes resource type, and these objects have a spec field that represents the desired state.
|
||||
|
||||
Controller examples:
|
||||
|
||||
* Replication Manager (a controller for ReplicationController resources)
|
||||
* ReplicaSet, DaemonSet, and Job controllers
|
||||
* Deployment controller
|
||||
* StatefulSet controller
|
||||
* Node controller
|
||||
* Service controller
|
||||
* Endpoints controller
|
||||
* Namespace controller
|
||||
* PersistentVolume controller
|
||||
|
||||
|
||||
|
||||
Controllers use the watch mechanism to get notified of changes. They watch the API server for changes to resources and perform operations for each change, whether it's a creation of a new object or an update or deletion of an existing object. Most of the time, these operations include creating other resources or updating the watched resources themselves. Still, because using watches doesn't guarantee the controller won't miss an event, they also perform a re-list operation periodically to ensure they haven't missed anything.
|
||||
|
||||
The Controller Manager also performs lifecycle functions such as namespace creation and lifecycle, event garbage collection, terminated-pod garbage collection, [cascading-deletion garbage collection][7], and node garbage collection. See [Cloud Controller Manager][8] for more information.
|
||||
|
||||
#### Scheduler
|
||||
|
||||
The Scheduler is a control plane process that assigns pods to nodes. It watches for newly created pods that have no nodes assigned. For every pod that the Scheduler discovers, the Scheduler becomes responsible for finding the best node for that pod to run on.
|
||||
|
||||
Nodes that meet the scheduling requirements for a pod get called feasible nodes. If none of the nodes are suitable, the pod remains unscheduled until the Scheduler can place it. Once it finds a feasible node, it runs a set of functions to score the nodes, and the node with the highest score gets selected. It then notifies the API server about the selected node. They call this process binding.
|
||||
|
||||
The selection of nodes is a two-step process:
|
||||
|
||||
1. Filtering the list of all nodes to obtain a list of acceptable nodes to which you can schedule the pod (for example, the PodFitsResources filter checks whether a candidate node has enough available resources to meet a pod's specific resource requests).
|
||||
2. Scoring the list of nodes obtained from the first step and ranking them to choose the best node. If multiple nodes have the highest score, a round-robin process ensures the pods get deployed across all of them evenly.
|
||||
|
||||
|
||||
|
||||
Factors to consider for scheduling decisions include:
|
||||
|
||||
* Does the pod request hardware/software resources? Is the node reporting a memory or a disk pressure condition?
|
||||
* Does the node have a label that matches the node selector in the pod specification?
|
||||
* If the pod requests binding to a specific host port, is that port available?
|
||||
* Does the pod tolerate the taints of the node?
|
||||
* Does the pod specify node affinity or anti-affinity rules?
|
||||
|
||||
|
||||
|
||||
The Scheduler doesn't instruct the selected node to run the pod. All the Scheduler does is update the pod definition through the API server. The API server then notifies the kubelet that the pod got scheduled through the watch mechanism. Then the kubelet service on the target node sees that the pod got scheduled to its node, it creates and runs the pod's containers.
|
||||
|
||||
**[ Read next: [How Kubernetes creates and runs containers: An illustrated guide][9] ]**
|
||||
|
||||
### Worker node components
|
||||
|
||||
Worker nodes run the kubelet agent, which permits them to get recruited by the control plane to process jobs. Similar to the control plane, the worker node uses several different components to make this possible. The following sections describe the worker node components.
|
||||
|
||||
#### Kubelet
|
||||
|
||||
Kubelet is an agent that runs on each node in the cluster and is responsible for everything running on a worker node. It ensures that the containers run in the pod.
|
||||
|
||||
The main functions of kubelet service are:
|
||||
|
||||
* Register the node it's running on by creating a node resource in the API server.
|
||||
* Continuously monitor the API server for pods that got scheduled to the node.
|
||||
* Start the pod's containers by using the configured container runtime.
|
||||
* Continuously monitor running containers and report their status, events, and resource consumption to the API server.
|
||||
* Run the container liveness probes, restart containers when the probes fail and terminate containers when their pod gets deleted from the API server (notifying the server about the pod termination).
|
||||
|
||||
|
||||
|
||||
#### Service proxy
|
||||
|
||||
The service proxy (kube-proxy) runs on each node and ensures that one pod can talk to another pod, one node can talk to another node, and one container can talk to another container. It is responsible for watching the API server for changes on services and pod definitions to maintain that the entire network configuration is up to date. When a service gets backed by more than one pod, the proxy performs load balancing across those pods.
|
||||
|
||||
The kube-proxy got its name because it began as an actual proxy server that used to accept connections and proxy them to the pods. The current implementation uses iptables rules to redirect packets to a randomly selected backend pod without passing them through an actual proxy server.
|
||||
|
||||
A high-level view of how it works:
|
||||
|
||||
* When you create a service, a virtual IP address gets assigned immediately.
|
||||
* The API server notifies the kube-proxy agents running on worker nodes that a new service exists.
|
||||
* Each kube-proxy makes the service addressable by setting up iptables rules, ensuring each service IP/port pair gets intercepted and the destination address gets modified to one of the pods that back the service.
|
||||
* Watches the API server for changes to services or its endpoint objects.
|
||||
|
||||
|
||||
|
||||
#### Container runtime
|
||||
|
||||
There are two categories of container runtimes:
|
||||
|
||||
* **Lower-level container runtimes:** These focus on running containers and setting up the namespace and cgroups for containers.
|
||||
* **Higher-level container runtimes (container engine):** These focus on formats, unpacking, management, sharing of images, and providing APIs for developers.
|
||||
|
||||
|
||||
|
||||
Container runtime takes care of:
|
||||
|
||||
* Pulls the required container image from an image registry if it's not available locally.
|
||||
* Extracts the image onto a copy-on-write filesystem and all the container layers overlay to create a merged filesystem.
|
||||
* Prepares a container mount point.
|
||||
* Sets the metadata from the container image like overriding CMD, ENTRYPOINT from user inputs, and sets up SECCOMP rules, ensuring the container runs as expected.
|
||||
* Alters the kernel to assign isolation like process, networking, and filesystem to this container.
|
||||
* Alerts the kernel to assign some resource limits like CPU or memory limits.
|
||||
* Pass system call (syscall) to the kernel to start the container.
|
||||
* Ensures that the SElinux/AppArmor setup is proper.
|
||||
|
||||
|
||||
|
||||
### Working together
|
||||
|
||||
System-level components work together to ensure that each part of a Kubernetes cluster can realize its purpose and perform its functions. It can sometimes be overwhelming (when you're deep into editing a [YAML file)][10] to understand how your requests get communicated within your cluster. Now that you have a map of how the pieces fit together, you can better understand what's happening inside Kubernetes, which helps you diagnose problems, maintain a healthy cluster, and optimize your own workflow.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/22/2/kubernetes-architecture
|
||||
|
||||
作者:[Nived Velayudhan][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/nivedv
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/containers_modules_networking_hardware_parts.png?itok=rPpVj92- (Parts, modules, containers for software)
|
||||
[2]: https://opensource.com/sites/default/files/uploads/kubernetes-architecture-diagram.png (Kubernetes architecture diagram)
|
||||
[3]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[4]: https://www.geeksforgeeks.org/raft-consensus-algorithm/
|
||||
[5]: https://stackoverflow.com/questions/52910322/kubernetes-resource-versioning#:~:text=Optimistic%20concurrency%20control%20(sometimes%20referred,updated%2C%20the%20version%20number%20increases.
|
||||
[6]: https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/
|
||||
[7]: https://kubernetes.io/docs/concepts/architecture/garbage-collection/
|
||||
[8]: https://kubernetes.io/docs/concepts/architecture/cloud-controller/
|
||||
[9]: https://www.redhat.com/architect/how-kubernetes-creates-runs-containers
|
||||
[10]: https://www.redhat.com/sysadmin/yaml-beginners
|
||||
@@ -2,7 +2,7 @@
|
||||
[#]: via: "https://www.opensourceforu.com/2022/06/containerisation-of-java-microservices/"
|
||||
[#]: author: "Krishna Mohan Koyya https://www.opensourceforu.com/author/krishna-mohan-koyya/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
[#]: subject: "Compress Images in Linux Easily With Curtail GUI App"
|
||||
[#]: via: "https://itsfoss.com/curtail-image-compress/"
|
||||
[#]: author: "Abhishek Prakash https://itsfoss.com/author/abhishek/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Compress Images in Linux Easily With Curtail GUI App
|
||||
======
|
||||
|
||||
Got a bunch of images with huge file sizes taking too much disk space? Or perhaps you have to upload an image to a web portal that has file size restrictions?
|
||||
|
||||
There could be a number of reasons why you would want to compress images. There are tons of tools to help you with it and I am not talking about the command line ones here.
|
||||
|
||||
You can use a full-fledged image editor like GIMP. You may also use web tools like [Squoosh][1], an open source project from Google. It even lets you compare the files for each compression level.
|
||||
|
||||
However, all these tools work on individual images. What if you want to bulk compress photos? Curtail is an app that saves your day.
|
||||
|
||||
### Curtail: Nifty tool for image compression in Linux
|
||||
|
||||
Built with Python and GTK3, Curtail is a simple GUI app that uses open source libraries like OptiPNG, [jpegoptim][2], etc to provide the image compression feature.
|
||||
|
||||
It is available as a [Flatpak application][3]. Please make sure that you have [Flatpak support enabled on your system][4].
|
||||
|
||||
Add the Flathub repo first:
|
||||
|
||||
```
|
||||
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
```
|
||||
|
||||
And then use the command below to install Curtail:
|
||||
|
||||
```
|
||||
flatpak install flathub com.github.huluti.Curtail
|
||||
```
|
||||
|
||||
Once installed, look for it in your Linux system’s menu and start it from there.
|
||||
|
||||
![curtail app][5]
|
||||
|
||||
The interface is plain and simple. You can choose whether you want a lossless or lossy compression.
|
||||
|
||||
The lossy compression will have poor-quality images but with a smaller size. The lossless compression will have better quality but the size may not be much smaller than the original.
|
||||
|
||||
![curtail app interface][6]
|
||||
|
||||
You can either browse for images or drag and drop them into the application.
|
||||
|
||||
Yes. You can compress multiple images in one click with Curtail.
|
||||
|
||||
In fact, you don’t even need a click. As soon as you select the images or drop them, they are compressed and you see a summary of the compression process.
|
||||
|
||||
![curtail image compression summary][7]
|
||||
|
||||
As you can see in the image above, I got a 35% size reduction for one image and 3 and 8 percent for the other two. This was with lossless compression.
|
||||
|
||||
The images are saved with a -min suffix (by default), in the same directory as the original image.
|
||||
|
||||
Though it looks minimalist, there are a few options to configure Curtail. Click on the hamburger menu and you are presented with a few settings options.
|
||||
|
||||
![curtail configuration options][8]
|
||||
|
||||
You can select whether you want to save the compressed file as new or replace the existing one. If you go for a new file (default behavior), you can also provide a different suffix for the compressed images. The option to keep the file attributes is also there.
|
||||
|
||||
In the next tab, you can configure the settings for lossy compression. By default, the compression level is at 90%.
|
||||
|
||||
![curtail compression options][9]
|
||||
|
||||
The Advanced tab gives you the option to configure the lossless compression level for PNG and WebP files.
|
||||
|
||||
![curtain advanced options][10]
|
||||
|
||||
### Conclusion
|
||||
|
||||
As I stated earlier, it’s not a groundbreaking tool. You can do the same with other tools like GIMP. It just makes the task of image compression simpler, especially for bulk image compression.
|
||||
|
||||
I would love to see the option to [convert the image file formats][11] with the compression like what we have in tools like Converseen.
|
||||
|
||||
Overall, a good little utility for the specific purpose of image compression.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/curtail-image-compress/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lkxed][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/lkxed
|
||||
[1]: https://squoosh.app/
|
||||
[2]: https://github.com/tjko/jpegoptim
|
||||
[3]: https://itsfoss.com/what-is-flatpak/
|
||||
[4]: https://itsfoss.com/flatpak-guide/
|
||||
[5]: https://itsfoss.com/wp-content/uploads/2022/06/curtail-app.png
|
||||
[6]: https://itsfoss.com/wp-content/uploads/2022/06/curtail-app-interface.png
|
||||
[7]: https://itsfoss.com/wp-content/uploads/2022/06/curtail-image-compression-summary.png
|
||||
[8]: https://itsfoss.com/wp-content/uploads/2022/06/curtail-configuration-options.png
|
||||
[9]: https://itsfoss.com/wp-content/uploads/2022/06/curtail-compression-options.png
|
||||
[10]: https://itsfoss.com/wp-content/uploads/2022/06/curtain-advanced-options.png
|
||||
[11]: https://itsfoss.com/converseen/
|
||||
@@ -1,37 +0,0 @@
|
||||
[#]: subject: "The First Commercial Unikernel With POSIX Support"
|
||||
[#]: via: "https://www.opensourceforu.com/2022/06/the-first-commercial-unikernel-with-posix-support/"
|
||||
[#]: author: "Laveesh Kocher https://www.opensourceforu.com/author/laveesh-kocher/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
The First Commercial Unikernel With POSIX Support
|
||||
======
|
||||
![operating system][1]
|
||||
|
||||
Lynx Software Technologies has released a unikernel that it claims is the first to be POSIX compatible for real-time operation and commercially available. LynxElement will be included in the MOSA.ic range of mission-critical embedded applications. To provide more security with third-party or open source software, Lynx prefers a unikernel approach over hypervisors or virtual machines. LynxElement is based on Lynx’s commercially proven LynxOS-178 real-time operating system, which allows for compatibility between the Unikernel and the standalone LynxOS-178 product. This enables designers to move applications between environments and is compliant with the POSIX API and US FACE specifications.
|
||||
|
||||
LynxElement initially focused on security on both Intel and Arm multicore processor architectures. Running security components such as virtual private networks is a common use case (VPNs). The unikernel, by utilising a one-way software ‘data diode’ and filter, can enable a customer to replace a Linux virtual machine, saving memory space and drastically reducing the attack surface while ensuring timing requirements and safety certifiability.
|
||||
|
||||
Unikernels are best suited for applications that require speed, agility, and a small attack surface in order to increase security and certifiability, such as aircraft systems, autonomous vehicles, and critical infrastructure. These run pre-built applications with their own libraries, reducing the attack surface caused by resource sharing. This also enables the secure use of containerised applications such as Kubernetes or Docker, which are increasingly moving from enterprise to embedded designs, owing to the need to support AI frameworks.
|
||||
|
||||
Unikernels are also an excellent choice for mission-critical systems with heterogeneous workloads that require the coexistence of RTOS, Linux, Unikernel, and bare-metal guest operating systems. Existing open source unikernel implementations, according to Lynx, haven’t fared well due to a lack of adequate functionality, a lack of a clear path to safety certification, and immature toolchains for debugging and producing images.
|
||||
|
||||
Lynx created the MOSA.ic software framework for developing and integrating complex multi-core safety- or security-critical systems. The framework includes built-in security for the unikernel, allowing for security and safety certification in mission-critical applications and making it enterprise-ready. With the assistance of DESE Research, Lynx created the safety-critical Unikernel solution. LynxElement is being evaluated by existing Lynx customers as well as additional organisations around the world, including naval, air force, and army organisations.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.opensourceforu.com/2022/06/the-first-commercial-unikernel-with-posix-support/
|
||||
|
||||
作者:[Laveesh Kocher][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.opensourceforu.com/author/laveesh-kocher/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://www.opensourceforu.com/wp-content/uploads/2022/06/operating-system-1.jpg
|
||||
@@ -0,0 +1,255 @@
|
||||
[#]: subject: "A site reliability engineer's guide to change management"
|
||||
[#]: via: "https://opensource.com/article/22/6/change-management-site-reliability-engineers"
|
||||
[#]: author: "Robert Kimani https://opensource.com/users/robert-charles"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
A site reliability engineer's guide to change management
|
||||
======
|
||||
The three core tenets of effective change management for SREs are progressive rollouts, monitoring, and safe and fast rollbacks.
|
||||
|
||||
![change button with arrow clicking][1]
|
||||
|
||||
Image by: Opensource.com
|
||||
|
||||
In my [previous article][2], I wrote about incident management (IM), an important component of site reliability engineering. In this article, I focus on change management (CM). Why is there a need to manage change? Why not simply just have a free-for-all where anyone can make a change at any time?
|
||||
|
||||
There are three tenets of effective CM. This gives you a forecast framework for your CM strategy:
|
||||
|
||||
* Rolling out changes progressively: There's a difference between progressive rollouts in which you deploy changes in stages, and doing it all at once. You get to find out that even though progressive change may look good on paper,there are pitfalls to avoid.
|
||||
* Detecting problems with changes: Monitoring is extremely critical for your CM to work. I discuss and look at examples of how to setup effective monitoring to ensure that you can detect problems and make changes as quickly as possible.
|
||||
* Rollback procedures: How can you effectively rollback when things go wrong?
|
||||
|
||||
### Why manage change?
|
||||
|
||||
It's estimated that 75% of production outages are due to changes. Scheduled and approved changes that we all perform. This number is staggering and only requires you to get on top of CM to ensure that everything is in order before the change is attempted. The primary reason for these staggering numbers is that there are inherent problems with changes.
|
||||
|
||||
Infrastructure and platforms are rapidly evolving. Not so long ago, infrastructure was not as complex, and it was easy to manage. For example an organization could have a few servers, where they ran an application server, web-servers, and database servers. But lately the infrastructure and platform are as complex as ever.
|
||||
|
||||
It is impossible to analyze every interconnection and dependency after the fact caused by the numerous sub-systems involved. For instance an application owner may not even know a dependency of an external service until it actually breaks. Even if the application team is aware of the dependency, they may not know all of the intricacies and all the different ways the remote service will respond due to their change.
|
||||
|
||||
You cannot possibly test for unknown scenarios. This goes back to the complexity of the current infrastructure and platforms. It will be cost prohibitive in terms of the time you spend to test each and every scenario before you actually apply a change. Whenever you make a change in your existing production environment, whether it's a configuration change or a code change, the truth is that, you are at high risk of creating an outage. So how do we handle this problem? Let's take a peek at the three tenets of an effective CM system.
|
||||
|
||||
### 3 tenets of an effective change management system for SREs
|
||||
|
||||
Automation is the foundational aspect of effective CM. Automation flows across the entire process of CM. This involves a few things:
|
||||
|
||||
* Progressive rollouts: Instead of doing one big change, the progressive rollouts mechanism allows you to implement change in stages, thereby reducing the impact to the user-base if something goes wrong. This attribute is critical especially if your user-base is large, for instance – web-scale companies.
|
||||
* Monitoring: You need to quickly and accurately detect any issue with changes. Your monitoring system should be able to reveal the current state of your application and service without any considerable lag in time.
|
||||
* Safe rollback: The CM system should rollback quickly and safely when needed. Do not attempt any change in your environment without having a bulletproof rollback plan.
|
||||
|
||||
#### Role of automation
|
||||
|
||||
Many of you are aware of the concept of automation, however a lot of organizations lack automation. To increase the velocity of releases, which is an important part of running an Agile organization, manual operations must be eliminated. This can be accomplished by using Continuous Integration and Continuous Delivery but it is only effective when most of the operations are fully automated. This naturally eliminates human errors due to fatigue and carelessness. By virtue, auto-scaling which is an important function of cloud-based applications requires no manual intervention. This process needs to be completely automated.
|
||||
|
||||
### Progressive rollouts for SREs: deploying changes progressively
|
||||
|
||||
Changes to configuration files and binaries have serious consequences, in other words when you make a change to an existing production system, you are at serious risk of impacting the end-user experience.
|
||||
|
||||
For this reason, when you deploy changes progressively instead of all at once you can reduce the impact when things go wrong. If we need to roll back, the effort is generally smaller when the changes are done in a progressive manner. The idea here is, that you would start your change with a smaller set of clients. If you find an issue with the change, you can rollback the change immediately because the size of the impact is small at that point.
|
||||
|
||||
There is an exception to the progressive rollout, you can rollout the change globally all at once if it is an emergency fix and it is warranted to do so.
|
||||
|
||||
#### Pitfalls to progressive rollouts
|
||||
|
||||
Rollout and rollback can get complex because you are dealing with multiple stages of a release. Lack of required traffic can undermine the effectiveness of a release. Especially if in the initial stages you are targeting a smaller set of clients in your rollout. The danger is that, you may prematurely sign off on a release based on a smaller set of clients. It also releases a pipline where you run one script with multiple stages
|
||||
|
||||
Releases can get much longer compared to one single (big) change. In a truly web-scale application that is scattered across the globe, a change can take several days to fully rollout, which can be a problem in some instances.
|
||||
|
||||
Documentation is important. Especially when a stage takes a long time and it requires multiple teams to be involved to manage the change. Everything must be documented in detail in case a rollback or a roll forward is warranted.
|
||||
|
||||
Due to these pitfalls, it is advised that you take a deeper look into your organization change rollout strategy. While progressive rollout is efficient and recommended, if your application is small enough and does not require frequent changes, a change all at once is the way to go. By doing it all at once, you have a clean way to rollback if there is a need to do so.
|
||||
|
||||
#### High level overview of progressive rollout
|
||||
|
||||
Once the code is committed and merged, we start a "Canary release," where canaries are the test subjects. Keep in mind that they are not a replacement for complete automated testing. The name "canary" comes from the early days of mining, when a canary bird was used to detect whether a mine contained poisonous gas before humans entering.
|
||||
|
||||
After the test, a small set of clients are used to rollout our changes and see how things go. Once the "canaries" are signed off, go to the next stage, which is the "Early Adaptors release." This is a slightly bigger set of clients you use to do the rollout. Finally, if the "Early Adaptors" are signed off, move to the biggest pack of the bunch: "All users."
|
||||
|
||||
![high level overview of a progressive rollout][3]
|
||||
|
||||
Image by: (Robert Kimani, CC BY-SA 4.0)
|
||||
|
||||
"Blast radius" refers to the size of the impact if something goes wrong. It is the smallest when we do the canary rollout and actually the biggest when we rollout to all users.
|
||||
|
||||
#### Options for progressive rollouts
|
||||
|
||||
A progressive rollout is either dependent on an application or an organization. For global applications, a geography-based method is an option. For instance you can choose to release to the Americas first, followed by Europe and regions of Asia. When your rollout is dependent on departments within an organization, you can use the classic progressive rollout model, used by many web-scale companies. For instance, you could start off with "Canaries", HR, Marketing, and then customers.
|
||||
|
||||
It's common to choose internal departments as the first clients for progressive rollouts, and then gradually move on to the external users.
|
||||
|
||||
You can also choose a size-based progressive rollout. Suppose you have one-thousand servers running your application. You could start off with 10% in the beginning, then pump up the rollout to 25%, 50%, 75%, and finally 100%. In this way, you can only affect a smaller set of servers as you advance through your progressive rollout.
|
||||
|
||||
There are periods where an application must run 2 different versions simultaneously. This is something you cannot avoid in progressive rollout situations.
|
||||
|
||||
#### Binary and configuration packages
|
||||
|
||||
There are three major components of a system: binary: (software), data (for instance, a database), and configuration (the parameters that govern the behavior of an application).
|
||||
|
||||
It's considered best practice to keep binary and configuration files separate from one another. You want to use version controlled configuration. Your configurations must be "hermetic." At any given time, when the configuration is derived by the application, it's the same regardless of when and where the configurations are derived. This is achieved by treating configuration as code.
|
||||
|
||||
### Monitoring for SREs
|
||||
|
||||
Monitoring is a foundation capability of an SRE organization. You need to know if something is wrong with your application that affects the end-user experience. In addition, your monitoring should help you identify the root cause.
|
||||
|
||||
The primary functions of monitoring are:
|
||||
|
||||
* Provides visibility into service health.
|
||||
* Allows you to create alerts based on a custom threshold.
|
||||
* Analyzes trends and plan capacity.
|
||||
* Provides detailed insight into various subsystems that make up your application or service.
|
||||
* Provides Code-level metrics to understand behavior.
|
||||
* Makes use of visualization and reports.
|
||||
|
||||
#### Data Sources for Monitoring
|
||||
|
||||
You can monitor several aspects of your environment. These include:
|
||||
|
||||
* Raw logs: Generally unstructured generated from your application or a server or network devices.
|
||||
* Structured event logs: Easy to consume information. For example Windows Event Viewer logs.
|
||||
* Metrics: A numeric measurement of a component.
|
||||
* Distributed tracing: Trace events are generally either created automatically by frameworks, such as open telemetry, or manually using your own code.
|
||||
* Event introspection: Helps to examine properties at runtime at a detailed level.
|
||||
|
||||
When choosing a monitoring tool for your SRE organization, you must consider what's most important.
|
||||
|
||||
#### Speed
|
||||
|
||||
How fast can you retrieve and send data into the monitoring system?
|
||||
|
||||
* How fresh the data should be? The fresher the data, the better. You don't want to be looking at data that's 2 hours old. You want the data to be as real-time as possible.
|
||||
* Ingesting data and alerting of real-time data can be expensive. You may have to invest in a platform like Splunk or InfluxDB or ElasticSearch to fully implement this.
|
||||
* Consider your service level objective (SLO) – to determine how fast the monitoring system should be. For instance, if your SLO is 2 hours, you do not have to invest in systems that process machine data in real-time.
|
||||
* Querying vast amounts of data can be inefficient. You may have to invest in enterprise platforms if you need very fast retrieval of data.
|
||||
|
||||
#### Resolution check
|
||||
|
||||
What is the granularity of the monitoring data?
|
||||
|
||||
* Do you really need to record data every second? The recommended way is to use aggregation wherever possible.
|
||||
* Use sampling if it makes sense for your data.
|
||||
* Metrics are suited for high-resolution monitoring instead of raw log files.
|
||||
|
||||
#### Alerting
|
||||
|
||||
What alert capabilities can the monitoring tool provide?
|
||||
|
||||
Ensure the monitoring system can be integrated with other event processing tools or third party tools. For instance, can your monitoring system page someone in case of emergency? Can your monitoring system integrate with a ticketing system?
|
||||
|
||||
You should also classify the alerts with different severity levels. You may want to choose a severity level of three for a slow application versus a severity level of one for an application that is not available. Make sure the alerts can be easily suppressed to avoid alert flooding. Email or page flooding can be very distracting to the On-Call experience. There must be an efficient way to suppress the alerts.
|
||||
|
||||
#### User interface check
|
||||
|
||||
How versatile is it?
|
||||
|
||||
* Does your monitoring tool provide feature-rich visualization tools?
|
||||
* Can it show time series data as well as custom charts effectively?
|
||||
* Can it be easily shared? This is important because you may want to share what you found not only with other team members but you may have to share certain information with leadership.
|
||||
* Can it be managed using code? You don't want to be a full-time monitoring administrator. You need to be able to manage your monitoring system through code.
|
||||
|
||||
#### Metrics
|
||||
|
||||
Metrics may not be efficient in identifying the root cause of a problem. It can tell what's going on in the system, but it can't tell you why it's happening. They are suitable for low-cardinality data, when you do not have millions of unique values in your data.
|
||||
|
||||
* Numerical measurement of a property.
|
||||
* A counter accompanied by attributes.
|
||||
* Efficient to ingest.
|
||||
* Efficient to query.
|
||||
* It may not be efficient in identifying the root cause. Metrics can tell what's going on in the system but it won't be able to tell you why that's happening.
|
||||
* Suitable for low-cardinality data – When you do not have millions of unique values in your data.
|
||||
|
||||
#### Logs
|
||||
|
||||
Raw text data is usually arbitrary text filled with debug data. Parsing is generally required to get at the data. Data retrieval and recall is slower than using metrics. Raw text data is useful to determine the root causes of many problems and there are no strict requirements in terms of the cardinaltiy of data.
|
||||
|
||||
* Arbitrary text, usually filled with debug data.
|
||||
* Generally parsing is required.
|
||||
* Generally slower than metrics, both to ingest and to retrieve.
|
||||
* Most of the times you will need raw logs to determine the root cause.
|
||||
* No strict requirements in-terms of cardinality of data.
|
||||
|
||||
You should use metrics because they can be assimilated, indexed and retrieved at a fast pace compared to logs. Analyzing with metrics and logs are fast, so you can give an alert fast. In contrast, logs are actually required for root cause analysis (RCA).
|
||||
|
||||
#### 4 signals to monitor
|
||||
|
||||
There's a lot you can monitor, and at some point you have to decide what's important.
|
||||
|
||||
* Latency: What are the end-users experiencing when it comes to responsiveness from your application.
|
||||
* Errors: This can be both Hard errors such as an HTTP:500 internal server error or Soft errors, which could refer to a functionality error. It could also mean a slow response time of a particular component within your application.
|
||||
* Traffic: Refers to the total number of requests coming in.
|
||||
* Saturation: Generally occurs in a component or a resource when it cannot handle the load anymore.
|
||||
|
||||
#### Monitoring resources
|
||||
|
||||
Data has to be derived from somewhere. Here are common resources used in building a monitoring system:
|
||||
|
||||
* CPU: In some cases CPU utilization can indicate an underlying problem.
|
||||
* Memory: Application and System memory. Application memory could be the Java heap size in a Java application.
|
||||
* Disk I/O: Many applications are heavy I/O dependent, so it's important to monitor disk performance.
|
||||
* Disk volume: Monitors the sizes of all your file-systems.
|
||||
* Network bandwidth: It's critical to monitor the network bandwidth utilized by your application. This can provide insight into eliminating performance bottlenecks.
|
||||
|
||||
#### 3 best practices for monitoring for SREs
|
||||
|
||||
Above all else, remember the three best practices for an effective monitoring system in your SRE organization:
|
||||
|
||||
1. Configuration as code: Makes it easy to deploy monitoring to new environments.
|
||||
2. Unified dashboards: Converge to a unified pattern that enables reuse of the dashboards.
|
||||
3. Consistency: Whatever monitoring tool you use, the components that you create within the monitoring tool should follow a consistent naming convention.
|
||||
|
||||
### Rolling back changes
|
||||
|
||||
To minimize user impact when change did not go as expected, you should buy time to fix bugs. With fine-grained rollback, you are able to rollback only a portion of your change that was impacted, thus minimizing overall user impact.
|
||||
|
||||
If things don't go well during your "canary" release, you may want to roll back your changes. When combined with progressive rollouts, it's possible to completely eliminate user impact when you have a solid rollback mechanism in place.
|
||||
|
||||
Rollback fast and rollback often. Your rollback process will become bulletproof over time!
|
||||
|
||||
#### Mechanics of rollback
|
||||
|
||||
Automation is key. You need to have scripts and processes in place before you attempt a rollback. One of the ways application developers rollback a change is to simply toggle flags as part of the configuration. A new feature in your application can be turned on and off based on simply switching a flag.
|
||||
|
||||
The entire rollback could be a configuration file release. In general, a rollback of the entire release is more preferred than a partial rollback. Use a package management system with version numbers and labels that are clearly documented.
|
||||
|
||||
A rollback is still a change, technically speaking. You have already made a change and you are reverting it back. Most cases entail a scenario that was not tested before so you have to be cautious when it comes to rollbacks.
|
||||
|
||||
#### Roll forward
|
||||
|
||||
With roll forward, instead of rolling back your changes, you release a quick fix "Hot Fix," an upgraded software that includes the fixes. Rolling forward may not always be possible. You might have to run the system in degraded status until an upgrade is available so the "roll forward is fully complete." In some cases, rolling forward may be safer than a rollback, especially when the change involves multiple sub-systems.
|
||||
|
||||
### Change is good
|
||||
|
||||
Automation is key. Your builds, tests, and releases should all be automated.
|
||||
|
||||
Use "canaries" for catching issues early, but remember that "canaries" are not a replacement for automated testing.
|
||||
|
||||
Monitoring should be designed to meet your service level objectives. Choose your monitoring tools carefully. You may have to deploy more than one monitoring system.
|
||||
|
||||
Finally, there are three tenets of an effective CM system:
|
||||
|
||||
1. Progressive rollout: Strive to do your changes in a progressive manner.
|
||||
2. Monitoring: A foundational capability for your SRE teams.
|
||||
3. Safe and fast rollbacks: Do this with processes and automation in place which increase confidence in your SRE organization functionality.
|
||||
|
||||
In the next article, the third part of this series, I will cover some important technical topics when it comes to SRE best practices. These topics will include the Circuit Breaker Pattern, self healing systems, distributed consensus, effective load balancing, autoscaling, and effective health check.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/22/6/change-management-site-reliability-engineers
|
||||
|
||||
作者:[Robert Kimani][a]
|
||||
选题:[lkxed][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/robert-charles
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/Open%20Health.jpg
|
||||
[2]: https://opensource.com/article/22/6/introduction-site-reliability-engineering
|
||||
[3]: https://opensource.com/sites/default/files/2022-05/effetiverollout1.png
|
||||
[4]: https://enterprisersproject.com/article/2021/3/7-top-site-reliability-engineer-sre-job-interview-questions
|
||||
@@ -0,0 +1,170 @@
|
||||
[#]: subject: "5 Useful Linux Command Line Tools that Everyone Should Use"
|
||||
[#]: via: "https://www.debugpoint.com/2022/06/useful-linux-command/"
|
||||
[#]: author: "Arindam https://www.debugpoint.com/author/admin1/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
5 Useful Linux Command Line Tools that Everyone Should Use
|
||||
======
|
||||
In this article, I will explain five useful Linux command(s) that will change your life forever.
|
||||
|
||||
### 5 Useful Linux Command(s)
|
||||
|
||||
#### 1. rmlint
|
||||
|
||||
Have you ever wondered how you can easily find duplicate, empty folders and empty files? Well, for that, there is a nifty utility called **rmlint**.
|
||||
|
||||
The [rmlint][1] scans your file system and tells you how much space is taken by duplicate files, folders, broken symlinks, empty files and more.
|
||||
|
||||
Moreover, it gives you an autogenerated shell script to remove all those files with just a single command. In addition, it also outputs a nice-looking report for your to analyze.
|
||||
|
||||
I think it’s a must-have terminal utility for your Ubuntu, Fedora and other Linux systems. Here are two images of rmlint in action.
|
||||
|
||||
![rmlint output – Figure 1][2]
|
||||
|
||||
![rmlint output – Figure 2][3]
|
||||
|
||||
Let’s take a look at how you can install rmlint. Installation is easy as it’s available in the major distro’s repo. Here are the commands
|
||||
|
||||
For Ubuntu, Linux Mint and similar distros:
|
||||
|
||||
```
|
||||
sudo apt install rmlint
|
||||
```
|
||||
|
||||
For Fedora, RHEL and similar distros:
|
||||
|
||||
```
|
||||
sudo dnf install rmlint
|
||||
```
|
||||
|
||||
After installation, run `rmlint` from the terminal. And it will give you a summary of the status of your system.
|
||||
|
||||
```
|
||||
rmlint
|
||||
```
|
||||
|
||||
Not only that, but you can also scan by file size, modification dates and so on—all the examples you can find in the [beginner’s guide][4].
|
||||
|
||||
#### 2. ntfy
|
||||
|
||||
The second useful command in this list is ntfy. It is a nifty utility that helps you send notifications to your desktop. The ntfy works via system DBUS and libnotify in all the popular Linux desktops (KDE Plasma, GNOME) and provides a system-like notification.
|
||||
|
||||
Now, you may ask – why do you need to send a custom notification?
|
||||
|
||||
Well, think about a use case where you are writing some script to achieve some purpose (e.g. taking backups), and you need the script to send a notification after it finishes. In this example, you can run ntfy via shell script to notify that the backup is complete.
|
||||
|
||||
The syntax of ntfy is simple.
|
||||
|
||||
```
|
||||
ntfy send "Your task is complete"
|
||||
```
|
||||
|
||||
![ntfy output][5]
|
||||
|
||||
Installing ntfy requires Python3. In Ubuntu Linux, you can install it using the below set of commands.
|
||||
|
||||
```
|
||||
sudo apt install python3-pippip install ntfy
|
||||
```
|
||||
|
||||
By default, it installs the binary at ~/.local/bin, where you can get the executable to run.
|
||||
|
||||
You can further customize it with its wide range of options available in the [documentation][6].
|
||||
|
||||
#### 3. btop
|
||||
|
||||
There are some excellent terminal-based system monitors available. And I think btop is the best. Firstly, it’s available pre-compiled executable, so you do not need to install it. All you need to do is download and run.
|
||||
|
||||
Secondly, one single interface gives you the entire system snapshot, containing the following features.
|
||||
|
||||
* Battery level and available time
|
||||
* Disks usage by partition and IO
|
||||
* Process list with executables, path, threads, memory and lazy CPU
|
||||
* Deep dive into a single process to investigate
|
||||
* Network interface utilization details
|
||||
|
||||
In addition, you can also configure it with various themes from its settings. I think it’s a perfect utility for terminal lovers to monitor your system.
|
||||
|
||||
![btop][7]
|
||||
|
||||
To get this application, visit the [GitHub page here][8] and download the zip file for Linux distros. You need to run the executable after extracting the zip file.
|
||||
|
||||
#### 4. ncdu
|
||||
|
||||
The fourth command in this list is super helpful ncdu (NCurses Disk Usage). The ncdu is a disk usage analyzer with an NCurses interface which scans your system and gives you an excellent representation of the disk space status in the terminal.
|
||||
|
||||
Then, you can use this report and manually remove the files which are not needed.
|
||||
|
||||
Furthermore, ncdu is a perfect tool to analyze your remote servers where you do not have access to a graphical user interface. It’s simple, fast and can run in any POSIX-like environment.
|
||||
|
||||
In addition, you can also browse the directories via keyboard in the terminal, and you can sort by size, date, etc.
|
||||
|
||||
That’s not all. Ncdu is available for almost all Linux distributions. Here are the commands to install in Ubuntu and Fedora-related distributions.
|
||||
|
||||
```
|
||||
sudo apt install ncdu
|
||||
```
|
||||
|
||||
```
|
||||
sudo dnf install ncdu
|
||||
```
|
||||
|
||||
![ncdu][9]
|
||||
|
||||
For more details, visit the [homepage][10].
|
||||
|
||||
#### 5. rclone
|
||||
|
||||
The rclone is the best command-line program to sync and manage files from your local system to the cloud storage such as Google driver, AWS etc. It’s a feature-rich program which currently supports 40+ cloud storage products.
|
||||
|
||||
Moreover, if you configure rclone effectively, you may not need rsync or login to the cloud provider’s web interface to manage your files. All of the operations can be easily done via the terminal.
|
||||
|
||||
Not only that, but rclone is also capable of handling the integrity of data such as:
|
||||
|
||||
* Verify checksum
|
||||
* Preserve timestamps
|
||||
* Options to transfer over limited bandwidth
|
||||
|
||||
In addition, to make it safer, it provides a “–dry-run” switch to verify which files or folders get replaced during the sync operation to the cloud.
|
||||
|
||||
You can install rclone using the commands below in your favourite distros.
|
||||
|
||||
After you install, head over to [this page][11]. For each cloud storage provider, there is a one-time configuration needed. Choose your cloud provider and select the config link. Then follow the easy instructions to set up.
|
||||
|
||||
For more details and documentation, visit the [official website][12].
|
||||
|
||||
### Closing Notes
|
||||
|
||||
We discussed some useful command-line tools in this article. These tools are perfect for remote system administration from anywhere in the world. It ranges from disk usage analyzer, system monitors and backup of your data.
|
||||
|
||||
Do you know any other useful Linux command line tools? Let me know in the comment box below, and we will feature it in the next article.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.debugpoint.com/2022/06/useful-linux-command/
|
||||
|
||||
作者:[Arindam][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.debugpoint.com/author/admin1/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://rmlint.readthedocs.io/en/latest/index.html
|
||||
[2]: https://www.debugpoint.com/wp-content/uploads/2022/06/rmlint-output-Figure-1.jpg
|
||||
[3]: https://www.debugpoint.com/wp-content/uploads/2022/06/rmlint-output-Figure-2.jpg
|
||||
[4]: https://rmlint.readthedocs.io/en/latest/tutorial.html#beginner-examples
|
||||
[5]: https://www.debugpoint.com/wp-content/uploads/2022/06/ntfy-output.jpg
|
||||
[6]: https://ntfy.readthedocs.io/en/v2.0.1/
|
||||
[7]: https://www.debugpoint.com/wp-content/uploads/2022/06/btop.jpg
|
||||
[8]: https://github.com/aristocratos/btop/releases/
|
||||
[9]: https://www.debugpoint.com/wp-content/uploads/2022/06/ncdu.jpg
|
||||
[10]: https://dev.yorhel.nl/ncdu
|
||||
[11]: https://rclone.org/#providers
|
||||
[12]: https://rclone.org/
|
||||
@@ -0,0 +1,129 @@
|
||||
[#]: subject: "How to Boot into an Older Kernel By Default in Ubuntu and Other Linux"
|
||||
[#]: via: "https://itsfoss.com/boot-older-kernel-default/"
|
||||
[#]: author: "Abhishek Prakash https://itsfoss.com/author/abhishek/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
How to Boot into an Older Kernel By Default in Ubuntu and Other Linux
|
||||
======
|
||||
Here’s a possible scenario. Your system received a kernel update but somehow things are not working as smoothly as previously.
|
||||
|
||||
You realized that if you boot into the older kernel (yes, you can downgrade kernel), things are back to normal.
|
||||
|
||||
That makes you happy with a little inconvenience. You have to manually select the older kernel at each boot.
|
||||
|
||||
This problem was faced by an elderly It’s FOSS reader. The new kernel update in [Linux Mint][1] wasn’t working as expected. Booting into the older kernel ‘fixed’ the issues but choosing the older kernel at each boot was a problem.
|
||||
|
||||
Removing the new kernel (while using the older kernel) is not a good idea because the new kernel will be installed and used with the next system updates.
|
||||
|
||||
So, I suggested booting into the older Linux kernel by default. How to do that? That’s what I am going to show you in this tutorial.
|
||||
|
||||
### Booting into the older Linux kernel
|
||||
|
||||
If you are not already familiar with it, your Linux distribution keeps more than one Linux kernel installed on your system. Don’t believe me? [List the installed kernels in Ubuntu][2] with this command:
|
||||
|
||||
```
|
||||
apt list --installed | grep linux-image
|
||||
```
|
||||
|
||||
When you get a new kernel version with the system updates, your system automatically chooses to boot into the latest available kernel.
|
||||
|
||||
From the [grub][3] screen, you can **go to the Advanced options** (or older Linux versions):
|
||||
|
||||
![ubuntu grub][4]
|
||||
|
||||
Here, you can see the available kernels to boot into. Choose the older one (without recovery option):
|
||||
|
||||
![grub advanced options][5]
|
||||
|
||||
You won’t notice any visual difference. Your files and applications remain the same.
|
||||
|
||||
Now that you have booted into the older kernel, it’s time to make your system boot into it automatically.
|
||||
|
||||
### Making older kernel the default
|
||||
|
||||
If you are comfortable with Linux terminal and commands, you can modify the /etc/default/grub file and add the following lines to it:
|
||||
|
||||
```
|
||||
GRUB_DEFAULT=saved
|
||||
GRUB_SAVEDEFAULT=true
|
||||
```
|
||||
|
||||
And then [update grub][6] with:
|
||||
|
||||
```
|
||||
sudo update-grub
|
||||
```
|
||||
|
||||
What you did here is to tell your system to save the currently used entry as the default entry for the future runs of GRUB.
|
||||
|
||||
However, not everyone is okay with the command line and hence I’ll focus on a GUI tool called [Grub Customizer][7].
|
||||
|
||||
#### Installing Grub Customizer
|
||||
|
||||
Use the official PPA to [install Grub Customizer in Ubuntu-based distributions][8]:
|
||||
|
||||
```
|
||||
sudo add-apt-repository ppa:danielrichter2007/grub-customizer
|
||||
sudo apt update
|
||||
sudo apt install grub-customizer
|
||||
```
|
||||
|
||||
For other distributions, please use your package manager to install this tool.
|
||||
|
||||
#### Using Grub Customizer to change the default boot entry
|
||||
|
||||
When you run Grub Customizer, it shows the available boot entries.
|
||||
|
||||
![grub customizer ubuntu][9]
|
||||
|
||||
You have two options here.
|
||||
|
||||
**Option1:** Select the desired kernel entry and use the arrow (displayed on the top menu) to move it up the order.
|
||||
|
||||
![move older kernel up the order ubntu grub][10]
|
||||
|
||||
**Option2:** Make the ‘previously booted entry’ the ‘default entry’.
|
||||
|
||||
![make currently booted entry as default ubuntu][11]
|
||||
|
||||
I would suggest going with option 2 because it will work even when there are new kernel updates.
|
||||
|
||||
This way you downgrade the kernel in Ubuntu or other distributions without even removing the older kernel version.
|
||||
|
||||
Do note that most distributions like Ubuntu only keep two kernel versions at a time. So eventually, your preferred older kernel will be removed with the newer kernel versions.
|
||||
|
||||
This neat trick helped me when I [installed the latest Linux kernel in Ubuntu][12] and it had issues with my audio system for some reason.
|
||||
|
||||
Whatever may be the reason, you now know how to boot into an older kernel automatically.
|
||||
|
||||
Questions? Suggestions? The comment section is all yours.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/boot-older-kernel-default/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lkxed][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/lkxed
|
||||
[1]: https://linuxmint.com/
|
||||
[2]: https://learnubuntu.com/list-installed-kernels/
|
||||
[3]: https://itsfoss.com/what-is-grub/
|
||||
[4]: https://itsfoss.com/wp-content/uploads/2022/06/ubuntu-grub.jpg
|
||||
[5]: https://itsfoss.com/wp-content/uploads/2022/06/Grub-Advanced-Options.jpg
|
||||
[6]: https://itsfoss.com/update-grub/
|
||||
[7]: https://itsfoss.com/customize-grub-linux/
|
||||
[8]: https://itsfoss.com/install-grub-customizer-ubuntu/
|
||||
[9]: https://itsfoss.com/wp-content/uploads/2022/06/grub-customizer-ubuntu.png
|
||||
[10]: https://itsfoss.com/wp-content/uploads/2022/06/move-older-kernel-up-the-order-ubntu-grub.png
|
||||
[11]: https://itsfoss.com/wp-content/uploads/2022/06/make-currently-booted-entry-as-default-ubuntu.png
|
||||
[12]: https://itsfoss.com/upgrade-linux-kernel-ubuntu/
|
||||
@@ -0,0 +1,132 @@
|
||||
[#]: subject: "Minetest, an Open Source Minecraft Alternative"
|
||||
[#]: via: "https://itsfoss.com/minetest/"
|
||||
[#]: author: "John Paul https://itsfoss.com/author/john/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Minetest, an Open Source Minecraft Alternative
|
||||
======
|
||||
Back in 2009, Minecraft was introduced to the world. Since then, it has become a cultural phenomenon. In that time period, several developers have released open-source games with similar ideas and mechanics. Today, we will look at one of the biggest ones: Minetest.
|
||||
|
||||
### What is Minetest?
|
||||
|
||||
![minetest start][1]
|
||||
|
||||
[Minetest][2], put simply, is a voxel based sandbox game, very similar to Minecraft. Unlike Minecraft, Minetest is written in C++ and is designed to run natively on most systems. It also has a very large map area. With a map size of “62,000 × 62,000 × 62,000 blocks”, “you can mine 31,000 blocks down, or build 31,000 blocks up”.
|
||||
|
||||
Interestingly, Minetest was originally released under a proprietary license but was later relicensed as GPL. It has since been relicensed to LGPL.
|
||||
|
||||
Minetest has a couple of modes. You can either build and be creative, or you can try to survive the elements. You aren’t limited to these modes. There is a wealth of [extra content available][3] to Minetest in terms of mods, texture packs, and games built within Minetest. This is largely done using Minetest’s [modding API][4] and Lua.
|
||||
|
||||
![minetest packages][5]
|
||||
|
||||
For those who have played Minecraft, you will find a very similar experience in Minetest. You can dig for resources, build structures, and combine materials to make tools. The one thing that I have not noticed in Minetest is monsters. I don’t think there are any creatures in Minetest, but then again, I’ve on only played in creative mode. I haven’t played survival mode.
|
||||
|
||||
Minetest is also used in [education][6]. For example, the people at CERN in Switzerland created a game with Minetest to [show how the Internet works][7] and how it was created. Minetest has also been [used to teach][8] programming, earth sciences, and calculus and trigonometry.
|
||||
|
||||
![minetes map1][9]
|
||||
|
||||
### How to Install Minetest?
|
||||
|
||||
Minetest is available on almost every system. Here is a list of commands that you can use to install Minetest in some of the most popular Linux distros.
|
||||
|
||||
#### Ubuntu or Debian
|
||||
|
||||
If you have a distro based on Ubuntu or Debian, just enter this command in the terminal:
|
||||
|
||||
```
|
||||
sudo apt install mintest
|
||||
```
|
||||
|
||||
#### Arch or Manjaro
|
||||
|
||||
For systems based on Arch (such as Manjaro), use:
|
||||
|
||||
```
|
||||
sudo pacman -S minetest
|
||||
```
|
||||
|
||||
#### Fedora
|
||||
|
||||
You can install Mintest from the Fedora servers by entering:
|
||||
|
||||
```
|
||||
sudo dnf install mintest
|
||||
```
|
||||
|
||||
#### openSUSE
|
||||
|
||||
openSUSE users can install Minetest using this command:
|
||||
|
||||
```
|
||||
sudo zypper in mintest
|
||||
```
|
||||
|
||||
#### FreeBSD
|
||||
|
||||
FreeBSD users are in luck. They can install Mintest using this command:
|
||||
|
||||
```
|
||||
pkg install minetest minetest_game
|
||||
```
|
||||
|
||||
![minetest map2][10]
|
||||
|
||||
#### Snap
|
||||
|
||||
To install a Snap of Minetest, enter the following command in the terminal:
|
||||
|
||||
```
|
||||
sudo snap install minetest
|
||||
```
|
||||
|
||||
#### Flathub
|
||||
|
||||
To install, enter`:`
|
||||
|
||||
```
|
||||
flatpak install flathub net.minetest.Minetest
|
||||
```
|
||||
|
||||
You can download a portable executable for Windows [here][11]. You can also install Minetest on Android, either by going to [Google Play][12] or [download the APK][13].
|
||||
|
||||
### Final Thoughts
|
||||
|
||||
![minetest about][14]
|
||||
|
||||
I’ve spent hours in Minetest building and exploring on my local system. It’s great fun. I haven’t gotten around to trying out any of the extra content because I’ve been more than happy with the relatively small portion of the game I’ve played. The only trouble that I’ve encountered was that it ran slow on Fedora, for some reason. I might have had something configured wrong.
|
||||
|
||||
If you ever thought that Minecraft looked interesting, but didn’t want to spend the money, check out Minetest. You’ll be glad that you did.
|
||||
|
||||
If you have played Minetest, tell us how your experience was in the comments.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/minetest/
|
||||
|
||||
作者:[John Paul][a]
|
||||
选题:[lkxed][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/john/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://itsfoss.com/wp-content/uploads/2022/03/minetest-start-800x411.jpg
|
||||
[2]: https://www.minetest.net/
|
||||
[3]: https://content.minetest.net/
|
||||
[4]: https://dev.minetest.net/Modding_Intro
|
||||
[5]: https://itsfoss.com/wp-content/uploads/2022/03/minetest-packages-800x411.jpg
|
||||
[6]: https://www.minetest.net/education/
|
||||
[7]: https://forum.minetest.net/viewtopic.php?t=22871
|
||||
[8]: https://en.wikipedia.org/wiki/Minetest#Usage_in_education
|
||||
[9]: https://itsfoss.com/wp-content/uploads/2022/03/minetes-map1-800x411.png
|
||||
[10]: https://itsfoss.com/wp-content/uploads/2022/03/minetest-map2-800x413.png
|
||||
[11]: https://www.minetest.net/downloads/
|
||||
[12]: https://play.google.com/store/apps/details?id=net.minetest.minetest&utm_source=website&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1
|
||||
[13]: https://github.com/minetest/minetest/releases/download/5.5.0/app-armeabi-v7a-release.apk
|
||||
[14]: https://itsfoss.com/wp-content/uploads/2022/03/minetest-about-800x407.jpg
|
||||
113
sources/tech/20220624 How I sketchnote with open source tools.md
Normal file
113
sources/tech/20220624 How I sketchnote with open source tools.md
Normal file
@@ -0,0 +1,113 @@
|
||||
[#]: subject: "How I sketchnote with open source tools"
|
||||
[#]: via: "https://opensource.com/article/22/6/open-source-sketchnotes"
|
||||
[#]: author: "Amrita Sakthivel https://opensource.com/users/amrita42"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
How I sketchnote with open source tools
|
||||
======
|
||||
Sketchnoting, or visual notetaking, is a method of taking notes using illustrations, symbols, graphic layouts, and text. Here's why I love sketchnotes and you should too.
|
||||
|
||||
![Colorful pens][1]
|
||||
|
||||
Image by: [Opensource.com][2]
|
||||
|
||||
[Sketchnoting][3], also called visual notetaking, is a method of taking notes using illustrations, symbols, graphic layouts, and text. It's meant to be a creative and engaging way to record your thoughts. It can work well in your personal life as well as in your work life. You don't need to be an artist to create a sketchnote, but you do need to listen, and visually combine and summarize ideas through text and drawings.
|
||||
|
||||
### Why sketchnotes?
|
||||
|
||||
Here are some interesting facts about why visual aids are so helpful:
|
||||
|
||||
* The picture superiority effect is when people remember and retain pictures and images more than just plain old words.
|
||||
* Writing is complicated and takes a long time to get good at.
|
||||
* Visual information can be processed 60,000 times faster than text. This is one reason that iconography is so prevalent and has been throughout history.
|
||||
* Researchers state that people remember only 20% of what they read, whilst 37% are visual learners.
|
||||
|
||||
### An example of how visual aids and regular text process in the mind
|
||||
|
||||
A [SMART goal][4] is used to help guide goal setting. SMART is an acronym that stands for Specific, Measurable, Achievable, Realistic, and Timely. Therefore, a SMART goal incorporates all of these criteria to help focus your efforts and increase the chances of achieving your goal.
|
||||
|
||||
![SMART goals on a sketchnote][5]
|
||||
|
||||
Image by:
|
||||
|
||||
(Amrita Sakthivel, CC BY-SA 40)
|
||||
|
||||
Which form of information did you retain more easily? Was it the visual or the text version that held your attention more? What does this say about how you process information?
|
||||
|
||||
### 4 open source sketchnote tools
|
||||
|
||||
A sketchnote is just a drawing, so you don't need any special application to start making them yourself. However, if you're an avid digital creator, you might want to try these open source illustration applications:
|
||||
|
||||
* [Mypaint][6]: Simple and elegant. It's you, your stylus, and a blank canvas.
|
||||
* [Krita][7]: You, your stylus, a blank canvas, and an art supply store.
|
||||
* [Inkscape][8]: Grab some clip art or create your own and let the layout begin.
|
||||
* [Drawpile][9]: Make collaborative sketchnotes.
|
||||
|
||||
### How I use sketchnotes
|
||||
|
||||
I recently contributed to a presentation about customer support and Knowledge-centered support (KCS) analysis. I did two versions:
|
||||
|
||||
![Image of knowledge centered support sketch][10]
|
||||
|
||||
![Image of knowledge centered support 2][11]
|
||||
|
||||
I created a sketchnote to demonstrate the differences between OpenShift and Kubernetes.
|
||||
|
||||
![Image of differences between Openshift and Kubernetes][12]
|
||||
|
||||
As a technical writer, my objective is to write documentation from a user perspective so that the user gets the optional usage of the product or feature.
|
||||
|
||||
![Image of a sketchnote featuring technical writing][13]
|
||||
|
||||
### How to best convey information through a visual medium
|
||||
|
||||
1. Plan what you want to convey.
|
||||
2. Decide the structure you want to use for for the sketchnote.
|
||||
3. Start with the text first, then add icons and visuals.
|
||||
4. Use color combinations to help show the content effectively.
|
||||
|
||||
Sometimes, using plain text to convey easy concepts can be inelegant in comparison to a simple visual aid. Visual aids are an easier and faster way to display information to your audience. They can also be helpful when taking your own notes. Give it a try.
|
||||
|
||||
### More resources
|
||||
|
||||
* [Verbal to Visual: What is sketchnoting?][14]
|
||||
* [Noun Project][15]
|
||||
* [Creative Market: 50+ Awesome Resources to Create Visual Notes, Graphic Recordings & Sketchnotes][16]
|
||||
* [Sketchnote Love: Mini Sketchnotes Tutorial][17]
|
||||
|
||||
Image by: (Amrita Sakthivel, CC BY-SA 40)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/22/6/open-source-sketchnotes
|
||||
|
||||
作者:[Amrita Sakthivel][a]
|
||||
选题:[lkxed][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/amrita42
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/2022-06/colorful-pens.jpg
|
||||
[2]: https://opensource.com/node/69046
|
||||
[3]: https://sketchnote-love.com/en/sketchnotes-tutorial/
|
||||
[4]: https://corporatefinanceinstitute.com/resources/knowledge/other/smart-goal/
|
||||
[5]: https://opensource.com/sites/default/files/2022-06/smart.png
|
||||
[6]: https://opensource.com/article/21/12/mypaint
|
||||
[7]: https://opensource.com/article/21/12/krita-digital-paint
|
||||
[8]: https://opensource.com/article/21/12/linux-draw-inkscape
|
||||
[9]: https://opensource.com/article/20/3/drawpile
|
||||
[10]: https://opensource.com/sites/default/files/2022-06/SketchnotesKCS.png
|
||||
[11]: https://opensource.com/sites/default/files/2022-06/sketchnote2version.png
|
||||
[12]: https://opensource.com/sites/default/files/2022-06/SketchnoteKubernetesvsOpens.png
|
||||
[13]: https://opensource.com/sites/default/files/2022-06/sketchnotestechwriter.png
|
||||
[14]: https://www.verbaltovisual.com/what-is-sketchnoting/
|
||||
[15]: https://thenounproject.com/
|
||||
[16]: https://creativemarket.com/blog/50-awesome-resources-to-create-visual-notes-graphic-recordings-sketchnotes
|
||||
[17]: https://sketchnote-love.com/en/sketchnotes-tutorial/
|
||||
@@ -0,0 +1,96 @@
|
||||
[#]: subject: "Download YouTube Videos with VLC (Because, Why Not?)"
|
||||
[#]: via: "https://itsfoss.com/download-youtube-videos-vlc/"
|
||||
[#]: author: "Community https://itsfoss.com/author/itsfoss/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Download YouTube Videos with VLC (Because, Why Not?)
|
||||
======
|
||||
|
||||
[VLC][1] is one of the [most popular video players for Linux][2] and other platforms.
|
||||
|
||||
It’s not just a video player. It provides a number of multimedia and network-related features among other things. You’ll be surprised to [learn what VLC is capable of][3].
|
||||
|
||||
I’ll demonstrate a simple VLC feature and that is to download YouTube videos with it.
|
||||
|
||||
Yes. You can play YouTube videos in VLC and download them too. Let me show you how.
|
||||
|
||||
### Download YouTube videos with VLC Media Player
|
||||
|
||||
Now, there are ways to [download YouTube videos][4]. Use a browser extension or use dedicated websites or tools for it.
|
||||
|
||||
But if you don’t want to use anything additional, the already installed VLC player can be used for this purpose.
|
||||
|
||||
**Important:**Before copying the link from YouTube, make sure to choose desired video quality from the YouTube player because we will get the same quality in which the video was streaming while copying the link.
|
||||
|
||||
#### Step 1: Get the Video link of your desired video
|
||||
|
||||
You can use any of your favorite browsers and copy the video link from the address bar.
|
||||
|
||||
![copy youtube link][5]
|
||||
|
||||
#### Step 2: Paste copied Link to Network Stream
|
||||
|
||||
The option of Network stream lies under Media which is the first option of our top menu bar. Just click on Media and you will get the option of “Open Network Stream”. You can also use the shortcut to open Network Stream CTRL + N.
|
||||
|
||||
![click on media and select network stream][6]
|
||||
|
||||
Now, you just have to paste copied YouTube video link and click on the play button. I know it just plays video in our VLC but there is a little extra step that will allow us to download currently streaming video.
|
||||
|
||||
![paste video link][7]
|
||||
|
||||
#### Step 3: Get Location Link from Codec Information
|
||||
|
||||
Under the codec information prompt, we will get a location link for the currently playing video. To open the Codec Information prompt, you can use the shortcut CTRL + J or you’ll find the option for Codec Information under “Tools”.
|
||||
|
||||
![click on tools and then codec information][8]
|
||||
|
||||
It will bring detailed info about currently streaming video. But what we need is ‘Location’. You just have to copy the location link and 90% of our task is complete.
|
||||
|
||||
![copy location link][9]
|
||||
|
||||
#### Step 4: Paste Location Link to New Tab
|
||||
|
||||
Open any of your favorite browsers and paste copied location link to the new tab and it will start playing the exact video in the browser.
|
||||
|
||||
Now, right-click on playing video and you will get an option for “Save Video As”.
|
||||
|
||||
![click on save][10]
|
||||
|
||||
It will open the file manager and ask you whether you want to save this video locally or not. You can also rename that file as by default it will be named “videoplayback.mp4”
|
||||
|
||||
![showing file in folder][11]
|
||||
|
||||
### Conclusion
|
||||
|
||||
If you have internet connection issues or if you want to save some video for future viewing, downloading the YouTube video makes sense.
|
||||
|
||||
Of course, we don’t encourage piracy. This method is just for fair use please make sure that the creator of the video has allowed the video for fair usage and also make sure to give credits to the original owner of the video before using it somewhere else.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/download-youtube-videos-vlc/
|
||||
|
||||
作者:[Community][a]
|
||||
选题:[lkxed][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/itsfoss/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://www.videolan.org/vlc/
|
||||
[2]: https://itsfoss.com/video-players-linux/
|
||||
[3]: https://itsfoss.com/vlc-pro-tricks-linux/
|
||||
[4]: https://itsfoss.com/download-youtube-videos-ubuntu/
|
||||
[5]: https://itsfoss.com/wp-content/uploads/2022/06/copy-Youtube-link-800x190.jpg
|
||||
[6]: https://itsfoss.com/wp-content/uploads/2022/06/click-on-media-and-select-network-stream.png
|
||||
[7]: https://itsfoss.com/wp-content/uploads/2022/06/paste-video-link.png
|
||||
[8]: https://itsfoss.com/wp-content/uploads/2022/06/click-on-tools-and-then-codec-information-800x249.png
|
||||
[9]: https://itsfoss.com/wp-content/uploads/2022/06/copy-location-link.png
|
||||
[10]: https://itsfoss.com/wp-content/uploads/2022/06/click-on-save-800x424.jpg
|
||||
[11]: https://itsfoss.com/wp-content/uploads/2022/06/showing-file-in-folder-800x263.png
|
||||
@@ -0,0 +1,138 @@
|
||||
[#]: subject: "Linux Distros That Turn Your PC into Retro Gaming Console"
|
||||
[#]: via: "https://itsfoss.com/retro-gaming-console-linux-distros/"
|
||||
[#]: author: "Ankush Das https://itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Linux Distros That Turn Your PC into Retro Gaming Console
|
||||
======
|
||||
|
||||
[Steam Deck][1] is making news for all the right reasons. It is a fantastic piece of tech, powered by a variant of Arch Linux (SteamOS 3.0) developed by Valve.
|
||||
|
||||
While you can install any other operating system in it, it is best to have it as it is for convenience.
|
||||
|
||||
Unfortunately, Steam Deck or anything similar is not available everywhere. So, what if you can convert your system to a Linux-powered retro gaming console using a distribution?
|
||||
|
||||
### Turn your PC into a Retro Gaming Console With These Linux Distros
|
||||
|
||||
Of course, with a retro gaming console, you can’t expect to play the latest and greatest, but if you are looking for something interesting, this should take your eyes off the Steam Deck. Or, maybe if you already have a modern gaming console/system, you can play some retro games for a change.
|
||||
|
||||
Some distributions also support Raspberry Pi. So, it can be one of your [Raspberry Pi project ideas][2] if you want to put some good use to it.
|
||||
|
||||
#### 1. Batocera.linux
|
||||
|
||||
![A Video from YouTube][3]
|
||||
|
||||
A perfect open-source retro-gaming distribution that can work via a USB or an SD card. This enables you to convert any type of computer to your personal retro gaming machine in no time.
|
||||
|
||||
In fact, it is also one of the [best Linux distributions for gaming][4].
|
||||
|
||||
In other words, it is a plug-and-play distribution that lets you play any of the retro games you own. It features a powerful emulator to help you run supported games along with numerous features to customize shaders, themes, etc.
|
||||
|
||||
You can check its [official compatibility list][5] to know the supported emulated games. You should find plenty of supported games to get started.
|
||||
|
||||
Note that it does not include any games, you will have to ensure that you own/have the game files that you want to run. For more information, you can explore its [GitHub page][6].
|
||||
|
||||
[Batocera.linux][7]
|
||||
|
||||
#### 2. Lakka
|
||||
|
||||
![lakka linux][8]
|
||||
|
||||
Lakka is a lightweight Linux distribution that can transform your computer/Raspberry Pi into a retro gaming console.
|
||||
|
||||
Note that it is the official Linux distribution of [RetroArch][9] and libretro ecosystem. Both combined give you a usable retro gaming experience.
|
||||
|
||||
It offers a nice, minimal user interface to let anyone comfortably use the distro. Like the previous option, you can install it on your USB flash drive or the SD card. The project says that it is under heavy development, but is a popular option for playing retro games.
|
||||
|
||||
[Lakka][10]
|
||||
|
||||
### 3. RetroPie
|
||||
|
||||
![retropiewebsitelogo][11]
|
||||
|
||||
One of the easy projects to put your Raspberry Pi for some good use.
|
||||
|
||||
RetroPie is a Linux distribution tailored for Raspberry Pi but also supports ODroid, and PCs to help you convert it into a retro gaming machine.
|
||||
|
||||
It is based on Raspbian, EmulationsStations, and uses projects like RetroArch to give you the experience of a home console with minimal setup.
|
||||
|
||||
If you like customizing your setup, it also allows a variety of configuration tools for advanced users.
|
||||
|
||||
For instance, you also use Kodi from within it by installing it from the menu. Of course, you might want to look at some [media server tools][12] if you want specifically for entertainment and movies.
|
||||
|
||||
You can grab the RestroPie image to get started on your system or install it on top of Raspbian, as you prefer.
|
||||
|
||||
[RetroPie][13]
|
||||
|
||||
### 4. Retro Home (Alpha Builds)
|
||||
|
||||
![retro home][14]
|
||||
|
||||
An unofficial Ubuntu-based Linux distribution for Raspberry Pi by the creator of Ubuntu MATE. It supports Raspberry Pi 2, 3, 4, and 400 as of now. You can also boot from USB.
|
||||
|
||||
It utilizes [Ludo][15] to present a minimal frontend to work with the emulators.
|
||||
|
||||
You can find the images in its GitHub releases section. Additionally, a script is available that builds Retro Home images. If you are curious to give it a try, you can check out its [GitHub page][16] to know more.
|
||||
|
||||
[Retro Home][17]
|
||||
|
||||
### 5. ChimeraOS
|
||||
|
||||
![steam library chimera][18]
|
||||
|
||||
For a change, if you want to play modern games along with the support for retro consoles from a single platform, ChimeraOS can help you out.
|
||||
|
||||
While it starts with a Steam picture mode to give you the convenience, you can also play games using GOG, Epic Games Store, and Flathub as well.
|
||||
|
||||
It should be an interesting option to try if you haven’t already. Head to its [GitH][19][u][20][b page][21] to know more.
|
||||
|
||||
[ChimeraOS][22]
|
||||
|
||||
### Wrapping Up
|
||||
|
||||
You can always use game emulator programs, or directly play games using Steam, Lutris, or more (refer to our [gaming guide][23] if you’re new to gaming on Linux).
|
||||
|
||||
However, it is always a different experience when you convert your entire system to a console-like experience using some of these Linux distributions. And, what’s more exciting than a retro game console powered by Linux?
|
||||
|
||||
*Have you tried out any of the mentioned options? Did we miss any of your favorites? Let us know in the comments.*
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/retro-gaming-console-linux-distros/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lkxed][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/lkxed
|
||||
[1]: https://store.steampowered.com/steamdeck
|
||||
[2]: https://itsfoss.com/raspberry-pi-projects/
|
||||
[3]: https://youtu.be/C1sw55VAj5E
|
||||
[4]: https://itsfoss.com/linux-gaming-distributions/
|
||||
[5]: https://batocera.org/compatibility.php
|
||||
[6]: https://github.com/batocera-linux/batocera.linux
|
||||
[7]: https://batocera.org/
|
||||
[8]: https://itsfoss.com/wp-content/uploads/2022/06/lakka-linux.jpg
|
||||
[9]: https://www.retroarch.com/
|
||||
[10]: https://www.lakka.tv/
|
||||
[11]: https://itsfoss.com/wp-content/uploads/2022/06/RetroPieWebsiteLogo.png
|
||||
[12]: https://itsfoss.com/best-linux-media-server/
|
||||
[13]: https://retropie.org.uk/
|
||||
[14]: https://itsfoss.com/wp-content/uploads/2022/06/retro-home-800x450.jpg
|
||||
[15]: https://ludo.libretro.com/
|
||||
[16]: https://github.com/wimpysworld/retro-home
|
||||
[17]: https://github.com/wimpysworld/retro-home
|
||||
[18]: https://itsfoss.com/wp-content/uploads/2022/06/steam-library-chimera-800x450.jpg
|
||||
[19]: https://github.com/ChimeraOS/chimeraos
|
||||
[20]: https://github.com/ChimeraOS/chimeraos
|
||||
[21]: https://github.com/ChimeraOS/chimeraos
|
||||
[22]: https://chimeraos.org/
|
||||
[23]: https://itsfoss.com/linux-gaming-guide/
|
||||
@@ -0,0 +1,60 @@
|
||||
[#]: subject: "An open source project that opens the internet for all"
|
||||
[#]: via: "https://opensource.com/article/22/6/equalify-open-internet-accessibility"
|
||||
[#]: author: "Blake Bertuccelli https://opensource.com/users/blake"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
An open source project that opens the internet for all
|
||||
======
|
||||
Equalify is an open source project with the goal of making the open internet more accessible.
|
||||
|
||||
![Plumeria by Bernard Spragg][1]
|
||||
|
||||
Image by: "Plumeria (Frangipani)" by Bernard Spragg is marked with CC0 1.0.
|
||||
|
||||
Accessibility is key to promoting an open society.
|
||||
|
||||
We learn online. We bank online. Political movements are won and lost online. Most importantly, the information we access online inspires us to make a better world. When we ignore accessibility requirements, people born without sight or who lost limbs in war are restricted from online information that others enjoy.
|
||||
|
||||
*We must ensure that everyone has access to the open internet*, and I am doing my part to work toward that goal by building [Equalify][2].
|
||||
|
||||
### What is Equalify?
|
||||
|
||||
Equalify is "the accessibility platform."
|
||||
|
||||
The platform allows users to run multiple accessibility scans on thousands of websites. With our latest version, users can also filter millions of alerts to create a dashboard of statistics that are meaningful to them.
|
||||
|
||||
The project is just getting started. Equalify aims to open source all the premium features that expensive services like SiteImprove provide. With better tools, we can ensure that the internet is more accessible and our society is more open.
|
||||
|
||||
### How do we judge website accessibility?
|
||||
|
||||
W3C's Web Accessibility publishes the Web Content Accessibility Guideline (WCAG) report that sets standards for accessibility. Equalify, and others, including the US Federal Government, use WCAG to meter website accessibility. The more websites we scan, the more we can understand the shortcomings and potentials of WCAG standards.
|
||||
|
||||
### How do I use Equalify?
|
||||
|
||||
Take a few minutes to browse our GitHub and learn more about the product. Specifically, the [README][3] provides steps on how to begin supporting and using Equalify.
|
||||
|
||||
### Our goal
|
||||
|
||||
Our ultimate goal is to make the open internet more accessible. 96.8% of homepages do not meet WCAG guidelines, according to [The WebAIM Million][4]. As more people build and use Equalify, we combat inaccessible pages. Everyone deserves equal access to the open internet. Equalify is working toward that goal as we work toward building a stronger and more open society for all.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/22/6/equalify-open-internet-accessibility
|
||||
|
||||
作者:[Blake Bertuccelli][a]
|
||||
选题:[lkxed][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/blake
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/2022-06/plumeria-frangipani-bernard-spragg.jpg
|
||||
[2]: https://equalify.app/
|
||||
[3]: https://github.com/bbertucc/equalify
|
||||
[4]: https://webaim.org/projects/million/
|
||||
@@ -0,0 +1,168 @@
|
||||
[#]: subject: "Linux Mint: The Beginner-Friendly Linux Operating System for Everyone"
|
||||
[#]: via: "https://www.debugpoint.com/linux-mint"
|
||||
[#]: author: "Arindam https://www.debugpoint.com/author/admin1/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Linux Mint: The Beginner-Friendly Linux Operating System for Everyone
|
||||
======
|
||||
This article contains all the necessary information you need for Linux Mint and helps you to learn and make a wise decision on your journey with this operating system.
|
||||
|
||||
![Linux Mint: The King of all distros][1]
|
||||
|
||||
Linux Mint is a Ubuntu LTS-based (Long Term Support) Linux operating system which brings an out-of-the-box computing experience. This distribution is designed with such a craft that it can act as a go-to Linux for new users, beginners, advanced users, casual users and so on. Moreover, many use Linux Mint as a safe distro to recover a broken system.
|
||||
|
||||
On August 27, 2006, Clement Lefebvre created Linux Mint, which millions of users use today. The development effort also includes huge community support with the help of generous Linux Mint sponsors.
|
||||
|
||||
![The Linux Mint Logo][2]
|
||||
|
||||
### Linux Mint Releases
|
||||
|
||||
Linux Mint does not follow any official schedule. If you are wondering when a new version of Linux Mint would be, the answer is – “Linux Mint releases when it’s ready”.
|
||||
|
||||
However, as per recent trends, Linux Mint releases one major version per year and three minor versions at approx 6-months intervals. In addition, five years’ worth of support is available for each major version.
|
||||
|
||||
### Code Names
|
||||
|
||||
The mint team gives a code name to each release version (major and minor). In addition, code names start with an increasing sequence of the English alphabet. And always ends with an “a”. Moreover, the names are generally feminine in nature. For example, “Tara”, “Ulyana”, etc.
|
||||
|
||||
### Features
|
||||
|
||||
Linux Mint provides ISO images for free download and installation. By default, the ISO image contains all the necessary software that you may require for your work and play. For example, Linux Mint provides LibreOffice, a web browser, email Client, Firewall utility, backup and system restore software and many more. Moreover, peripheral devices such as Printers, webcams, wireless devices, and Bluetooth speakers – all work out of the box. That means you do not need to look for the driver.
|
||||
|
||||
### Desktop Editions
|
||||
|
||||
There are three primary desktop variants or editions available with Linux Mint. They are:
|
||||
|
||||
* Cinnamon Edition (Flagship)
|
||||
* Xfce Edition
|
||||
* MATE Edition
|
||||
|
||||
The Cinnamon Edition features the stunning Cinnamon desktop environment and is the recommended version for Linux Mint. Moreover, if you ever have to decide which one of the above flavours, go for Cinnamon Edition.
|
||||
|
||||
Other than that, Xfce and MATE editions feature their respective desktops. It’s all about your taste and preferences to choosing the one.
|
||||
|
||||
But, at the core, all the above are similar, running the Linux Mint packages.
|
||||
|
||||
### Software
|
||||
|
||||
The more important aspect of Linux Mint is its own set of applications. The devs create some fantastic software with their user base in mind. Here’s a list of native applications that it provides:
|
||||
|
||||
* Nemo File Manager (best file manager ever!)
|
||||
* Sticky Notes
|
||||
* Screenshot tool
|
||||
* Warpinator (File transfer via network)
|
||||
* Celluloid Video Player
|
||||
* Hypnotix ([IPTV player][3])
|
||||
* Timeshift (System restore point creator)
|
||||
|
||||
In addition, it pre-loads all sorts of necessary applications such as sticky notes, firewall management, web browser, disk partition software and LibreOffice. In summary, you do not require additional software for a general use case.
|
||||
|
||||
### System Requirement
|
||||
|
||||
Linux Mint can run on older to newer hardware. And its system requirement is very flexible. During our multiple tests, we could run it in 12+ years old hardware without any problem. However, here’s the minimum system requirement of Linux Mint.
|
||||
|
||||
* 2 GB RAM (Recommended 4 GB)
|
||||
* 20 GB of hard-drive space (Recommended 100 GB)
|
||||
* Display of 1024×768 resolution
|
||||
* Either a CD/DVD drive or a USB port for the installation media
|
||||
* Internet access (optional)
|
||||
|
||||
This distro primarily supports amd64 (64-bit) architecture from version 20.x onwards, and no 32-bit support is available. Because of its parent OS, Ubuntu dropped 32-bit support from Ubuntu 20.04 LTS.
|
||||
|
||||
However, Linux Mint Debian Edition (LMDE) still support 32-bit architecture because it is based on the Debian Operating system.
|
||||
|
||||
### Download Details
|
||||
|
||||
Linux Mint provides all the editions as direct download ISO files and torrents. There are mirrors available in many countries to help you download from a nearby source. Download links are present at the .
|
||||
|
||||
### Screenshots
|
||||
|
||||
Here are some of the screenshots of this distribution.
|
||||
|
||||
![Cinnamon Desktop - image 1][4]
|
||||
|
||||
![Cinnamon Desktop - image 2][5]
|
||||
|
||||
![Cinnamon Desktop - image 3][6]
|
||||
|
||||
### FAQ
|
||||
|
||||
Yes, it is free to download and use. The upgrades are also free because Linux Mint is a free and open-source operating system.
|
||||
|
||||
Among all the Linux operating systems, Linux Mint is the best for beginners. If you are planning to kick-start your Linux journey, this is a perfect distro to start with.
|
||||
|
||||
Theoretically, you can install Linux Mint in Windows 10 or 11. But you have to run it under a virtual machine such as Virtual Box.
|
||||
|
||||
We recommend using the flagship Cinnamon edition for the best experience. However, you can also use the Xfce, MATE or the Debian edition.
|
||||
|
||||
This is a difficult question to answer. Both are great pieces of the operating systems. However, we think Mint is best because it is more user-friendly and convenient (e.g. Snap fiasco) than Ubuntu.
|
||||
|
||||
### Recent Articles and Reviews
|
||||
|
||||
* [Linux Mint 21 – Announcement][7]
|
||||
* [5 Reasons to switch to Linux Mint][8]
|
||||
* [Give your Linux Mint a Makeover with Twister UI][9]
|
||||
* [Linux Mint Debian Edition 5 – Review][10]
|
||||
* [New Mint Upgrade tool – Everything you need to know][11]
|
||||
* [10 Things to do after installing Linux Mint][12]
|
||||
* [Linux Mint 20 – Everything you need to know][13]
|
||||
* [How to enable Snap packages in Linux Mint][14]
|
||||
* [Linux Mint 20.1 – Everything you need to know][15]
|
||||
* [Linux Mint 20.2 – Everything you need to know][16]
|
||||
|
||||
### Summary
|
||||
|
||||
| Page | Link |
|
||||
| :- | :- |
|
||||
| Home Page | https://linuxmint.com/ |
|
||||
| Official Forum | https://forums.linuxmint.com/ |
|
||||
| Official News and Blog | https://blog.linuxmint.com/ |
|
||||
| Community and collaboration | https://community.linuxmint.com/ |
|
||||
| Source Code (GitHub) | https://www.github.com/linuxmint |
|
||||
| Documentation | https://linuxmint.com/documentation.php |
|
||||
| Official download | https://linuxmint.com/download.php |
|
||||
| Official download (all together) | https://linuxmint.com/download_all.php |
|
||||
| BETA Test images | https://community.linuxmint.com/iso |
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.debugpoint.com/linux-mint
|
||||
|
||||
作者:[Arindam][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.debugpoint.com/author/admin1/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://www.debugpoint.com/wp-content/uploads/2022/06/linuxmint-logo-1024x576.jpg
|
||||
[2]: https://www.debugpoint.com/wp-content/uploads/2022/06/The-Linux-Mint-Logo-1024x247.jpg
|
||||
[3]: https://www.debugpoint.com/wp-content/uploads/2020/12/Hypnotix-IPTV-Player-Linux-Mint-20.1.jpg
|
||||
[4]: https://i1.wp.com/www.debugpoint.com/wp-content/uploads/2022/06/Cinnamon-Desktop-image-1-1024x635.jpg?ssl=1
|
||||
[5]: https://i2.wp.com/www.debugpoint.com/wp-content/uploads/2022/06/Cinnamon-Desktop-image-2-1024x634.jpg?ssl=1
|
||||
[6]: https://i0.wp.com/www.debugpoint.com/wp-content/uploads/2022/06/Cinnamon-Desktop-image-3-1024x634.jpg?ssl=1
|
||||
[7]: https://www.debugpoint.com/linux-mint-21-announcement/
|
||||
|
||||
[8]: https://www.debugpoint.com/5-reasons-to-switch-to-linux-mint/
|
||||
|
||||
[9]: https://www.debugpoint.com/twister-ui-2022/
|
||||
|
||||
[10]: https://www.debugpoint.com/linux-mint-debian-edition-5-review/
|
||||
|
||||
[11]: https://www.debugpoint.com/mint-upgrade-tool/
|
||||
[12]: https://www.debugpoint.com/10-things-to-do-after-installing-linux-mint-20/
|
||||
[13]: https://www.debugpoint.com/linux-mint-20/
|
||||
[14]: https://www.debugpoint.com/how-to-enable-snap-package-in-linux-mint-20/
|
||||
[15]: https://www.debugpoint.com/linux-mint-20-1-ulyssa-new-features-and-release-dates/
|
||||
[16]: https://www.debugpoint.com/linux-mint-20-2-release-announcement/
|
||||
[17]: https://t.me/debugpoint
|
||||
[18]: https://twitter.com/DebugPoint
|
||||
[19]: https://www.youtube.com/c/debugpoint?sub_confirmation=1
|
||||
[20]: https://facebook.com/DebugPoint
|
||||
[21]: https://t.me/debugpoint
|
||||
@@ -0,0 +1,155 @@
|
||||
[#]: subject: "Manjaro Linux Review: Detailed deep-dive with Performance, Hardware Support + More"
|
||||
[#]: via: "https://www.debugpoint.com/manjaro-linux-review-2022/"
|
||||
[#]: author: "Arindam https://www.debugpoint.com/author/admin1/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Manjaro Linux Review: Detailed deep-dive with Performance, Hardware Support + More
|
||||
======
|
||||
|
||||
We review the [Manjaro Linux][1] with decade-old hardware and new hardware to test how it performs. Here are the results.
|
||||
|
||||
![Manjaro Linux 21.3 GNOME Desktop][2]
|
||||
|
||||
A few days back, we received several comments on why we have not included “Manjaro Linux” in the article we published – “[best Linux Distributions of 2022][3]“. So, I decided to review Manjaro’s current state and performance in various aspects of a desktop Linux operating system.
|
||||
|
||||
I will be honest. I was slightly biased on Manjaro while drafting the above article, primarily due to several media coverages ([source 1][4], [source 2][5], [source 3][6]). However, when I saw the latest feedback of Manjaro in several forums, I thought, let’s find out about the actual state of this fantastic distro.
|
||||
|
||||
Hence this review.
|
||||
|
||||
### Manjaro Review and Experience
|
||||
|
||||
#### Test Machine
|
||||
|
||||
Those who spend longer time in the Linux world know how complicated a situation can be with the above hardware from two famous (🥵) companies. I decided to test Majnaro in two ways. Firstly, on older hardware (10+ years old) with a complex NVIDIA GeForce card and Broadcom chip.
|
||||
|
||||
Second, in a standard virtual machine.
|
||||
|
||||
#### ISO Download and Installation
|
||||
|
||||
Firstly, the download from the official website of Manjaro via torrent went fine. The mirrors are super fast. I choose the Manjaro Linux GNOME Edition for this review which is around 3.2 GB download size. The primary reason for choosing GNOME is that it’s easier to compare with other non-Arch distros.
|
||||
|
||||
Secondly, the installation launcher is easy to find on the Manjaro LIVE desktop. The OS installer icon is at the GNOME default dock.
|
||||
|
||||
The installation was flawless of Manjaro Linux. It uses the Calamares installer. In both test and virtual machines, it preserved the GRUB. The physical system is a triple boot machine, and Manjaro did not mess up the GRUB. It detected all the operating systems.
|
||||
|
||||
Additionally, here’s one tiny observation related to boot. Manjaro Linux boot screen gives you two options – a) boot with an open-source driver and b) boot with a proprietary driver. When I tried to boot with the proprietory driver, Majnaro did not boot. It is stuck on the boot screen with “Starting GNOME Display Manager”. It looks like the NVIDIA card support problem (although it is out of support which I found later). Eventually, I installed it via the open-source driver option.
|
||||
|
||||
#### First Look
|
||||
|
||||
This review is based on Manjaro 21.3, the latest version as of writing this. The GNOME 42 desktop with Manjaro’s green-ish theme looks stunning. GNOME 42 brings the latest GTK4 applications in its core Shell. Overall the desktop seems nice and clean.
|
||||
|
||||
The Manjaro Hello – the official welcome screen- is a much-needed app that gives you quick access to various tasks. It is an essential app for new users mostly.
|
||||
|
||||
A set of nice Manjaro wallpapers give the desktop a professional feel.
|
||||
|
||||
#### Friendliness with Manjaro tools for a new Arch User
|
||||
|
||||
In addition to the above, Manjaro also brings two crucial native applications.
|
||||
|
||||
The first one is Manjaro Settings Manager, which gives you easy access to perform several system tasks without running commands in the terminal. This app provides the following features:
|
||||
|
||||
* Install and remove additional and experimental Kernels
|
||||
* User account management
|
||||
* Keyboard layout changes
|
||||
* Language changes
|
||||
* Hardware detection and installation of drivers
|
||||
|
||||
The second app is the Graphical Software Manager pamac. Pamac allows you to manage the software sources and search, install and uninstall software in the most convenient way possible. It also gives you access to many software, especially in Manjaro’s repo, in addition to usual Arch Linux repos.
|
||||
|
||||
![Pamac][7]
|
||||
|
||||
In addition, the GNOME flavour of Manjaro has the Extensions app pre-installed with several unique GNOME native apps installed. Thanks to the Manjaro devs, Flatpak support is present out of the box!
|
||||
|
||||
All of these small but impactful changes make it a great distro.
|
||||
|
||||
#### Connectivity and Drivers
|
||||
|
||||
Most of the connectivity worked fine in this hardware. However, there were some roadblocks.
|
||||
|
||||
Firstly, the Broadcom wireless card (BCM4313) worked out of the box, thanks to the Manjaro developers. Because, a few months back, when I ran the bare-metal Arch Linux with Xfce, the vanilla Arch Linux Kernel did not detect it. By default, Manjaro uses the open-source broadcom-r8168 driver.
|
||||
|
||||
I am glad it worked and connecting to the 4G Wi-Fi access point also went smoothly.
|
||||
|
||||
![Network Driver][8]
|
||||
|
||||
Secondly, the connection to a Bluetooth audio device also went well. Also, plug-and-play wireless USB devices worked fine.
|
||||
|
||||
Two important aspects did not go well in this hardware. Although, the Manjaro Hardware Configuration detected the NVIDIA GeForce 315M and assigned the video-linux driver. The display resolution is maxed at 1376×768, but probably this driver has limited support.
|
||||
|
||||
![Resolution in test system][9]
|
||||
|
||||
Similarly, when I tested the Linux Mint Cinnamon edition in this hardware, it was detected perfectly, and several high-resolution options were present.
|
||||
|
||||
Upon further digging in the Majnaro Forum, I found that the official driver for this card (nvidia-340) is officially removed as its an obsolete card. However, there are [some instructions][10] to compile the driver from GitHub – but that’s too much of an effort.
|
||||
|
||||
![Graphics Driver detected by Manjaro][11]
|
||||
|
||||
Secondly, the printer did not work at all. My printer is HP 2300 deskjet series. GNOME settings can detect the printer (see below), but the “Add Printer” function fails.
|
||||
|
||||
![Printer is shown in Settings][12]
|
||||
|
||||
![Add Printer did not work][13]
|
||||
|
||||
Because Linux has excellent printer support – thanks to CUPS. The same printer works well with all other recent Linux distributions, even with GNOME. I am not particularly sure why it didn’t work. Also, I think it might be something to do with GNOME Shell and its settings, not Manjaro Linux itself.
|
||||
|
||||
Besides these, Manjaro Linux brings Onlyoffice and Geary for office suite and email access, respectively.
|
||||
|
||||
#### Performance
|
||||
|
||||
One reason for trying out this distribution in a physical system is the performance metric. If it performs well in older hardware, it may run blazing fast in modern hardware.
|
||||
|
||||
In an idle state, Manjaro Linux GNOME Edition uses only 740 MB of RAM and 2% to 3% CPU in this hardware. The overall responsiveness of the desktop is fast; there is no lag whatsoever. It’s an impressive performance considering the physical system.
|
||||
|
||||
![Manjaro Linux Performance (Idle State with GNOME)][14]
|
||||
|
||||
Moreover, if you run it through a heavy workload, the performance would be slightly higher based on how many programs or applications you run.
|
||||
|
||||
But overall, Mankjaro Linux performs very well.
|
||||
|
||||
Finally, it uses ~10 GB of disk space for a default install (GNOME Edition).
|
||||
|
||||
### Closing Notes
|
||||
|
||||
Wrapping up the Manjaro Linux Review, I must say, it is indeed a time-tested distribution which brings Arch Linux to the masses. Also, I think Manjaro is the first distro which shows that Arch Linux can be a friendly distro with easy installation. Moreover, it shows the path to many similar “friendly Arch” distros which came up recently, such as EndeavourOS.
|
||||
|
||||
Because it is well designed to provide a wrapper to the “Arch Linux is difficult” myth. In addition, once you start using it, you wouldn’t feel it is an Arch Linux. It may feel like a Debian-based or a Fedora-based distro.
|
||||
|
||||
However, as always, it’s better to try modern Linux distributions in “not-so-old” hardware, which we used for this review. A five-year to 10-year-old hardware is fine. But beyond that, it’s necessary to upgrade the hardware because the modern operating systems (Linux or Windows) require more computing power due to security and other built-in functionalities (fingerprint, video conferencing, etc.), which are needed with the changing time.
|
||||
|
||||
Finally, you can easily choose Manjaro Linux for a daily driver or your workflow.
|
||||
|
||||
What is your opinion about Majnaro? Let me know in the comment box below (good or bad).
|
||||
|
||||
Cheers.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.debugpoint.com/manjaro-linux-review-2022/
|
||||
|
||||
作者:[Arindam][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.debugpoint.com/author/admin1/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://manjaro.org/
|
||||
[2]: https://www.debugpoint.com/wp-content/uploads/2022/06/Manjaro-Linux-21.3-GNOME-Desktop.jpg
|
||||
[3]: https://www.debugpoint.com/best-linux-distributions-2022/
|
||||
[4]: https://www.reddit.com/r/linux4noobs/comments/oxeeyu/please_please_stop_recommending_beginners_manjaro/
|
||||
[5]: https://www.hadet.dev/Manjaro-Bad/
|
||||
[6]: https://github.com/arindas/manjarno
|
||||
[7]: https://www.debugpoint.com/wp-content/uploads/2022/06/Pamac.jpg
|
||||
[8]: https://www.debugpoint.com/wp-content/uploads/2022/06/Network-Driver.png
|
||||
[9]: https://www.debugpoint.com/wp-content/uploads/2022/06/Resolution-in-test-system.png
|
||||
[10]: https://forum.manjaro.org/t/howto-get-legacy-340xx-nvidia-drivers-back/46969
|
||||
[11]: https://www.debugpoint.com/wp-content/uploads/2022/06/Graphics-Driver-detected-by-Manjaro.png
|
||||
[12]: https://www.debugpoint.com/wp-content/uploads/2022/06/Printer-is-shown-in-Settings.png
|
||||
[13]: https://www.debugpoint.com/wp-content/uploads/2022/06/Add-Printer-did-not-work.png
|
||||
[14]: https://www.debugpoint.com/wp-content/uploads/2022/06/Manjaro-Linux-Performance-Idle-State-with-GNOME.png
|
||||
@@ -0,0 +1,44 @@
|
||||
[#]: subject: "The Final Version Of 7-Zip 22.00 Is Now Available"
|
||||
[#]: via: "https://www.opensourceforu.com/2022/06/the-final-version-of-7-zip-22-00-is-now-available/"
|
||||
[#]: author: "Laveesh Kocher https://www.opensourceforu.com/author/laveesh-kocher/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "lkxed"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
7-Zip 的最终版本 22.00 现已推出
|
||||
======
|
||||
![7-zip-2200-500x312][1]
|
||||
|
||||
7-Zip 是用于 Windows、Mac 和 Linux 的知名开源文件归档器。它的最新版本 22.00 现已推出。它是 2022 年的第一个稳定版本。上一个版本是 21.07,于 2021 年 12 月发布。7-Zip 的用户可以从官方网站获取该应用的最新版本。下载适用于 Windows 64 位、32 位和 ARM 版本。该应用仍然与过时的 Windows 版本兼容,例如 XP 和 Vista。它还支持所有官方支持的 Windows 版本,包括服务器版本。适用于 Linux 的 7-Zip 22.00 已经可以下载,但 Mac OS 版本还不可用。
|
||||
|
||||
7-Zip 22.00 包含一些增强了应用功能的新特性。这个归档器现在支持提取<ruby>苹果文件系统<rt>Apple File System</rt></ruby>(APFS)镜像。几年前,苹果公司在 Mac OS 10.13 和 iOS 中引入了苹果文件系统。该文件系统在设计时就考虑到了闪存(Flash)和固态硬盘(SSD)存锤。
|
||||
|
||||
7-Zip 22.00 包括对其 TAR 存档支持的多项增强。使用选项 `-ttar -mm=pax` 或 `-ttar -mm=posix`,7-Zip 现在可以创建符合 POSIX 标准的 tar 格式的 TAR 档案。此外,使用选项 `ttar -mm=pax -mtp=3 -mtc -mta`,7-Zip 可以在 tar/pax 存档中存储高精度的文件时间戳。
|
||||
|
||||
最后,Linux 用户可以在 TAR 归档文件中使用以下两个新选项:
|
||||
|
||||
* `snoi`:将所有者/组 ID 保存在存档中,或将所有者/组 ID 从存档复制到提取的文件中。
|
||||
* `snon`:在存档中保留所有者/组的名称。
|
||||
|
||||
适用于 Windows 的 7-Zip 22.00 添加了对 `-snz` 选项的支持,该选项用于传播 Zone。
|
||||
|
||||
要提取文件,请使用标识符流。出于安全目的,Windows 使用了该流,它可用于确定文件是在本地创建的还是从互联网下载的。
|
||||
|
||||
在“<ruby>添加到存档<rt>add to archive</rt></ruby>”配置对话框中,7-Zip 22.00 包含一个新的选项窗口。它包括用于更改时间戳精度、更改其他与时间相关的配置选项,以及防止更改源文件的最后访问时间的选项。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.opensourceforu.com/2022/06/the-final-version-of-7-zip-22-00-is-now-available/
|
||||
|
||||
作者:[Laveesh Kocher][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[lkxed](https://github.com/lkxed)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.opensourceforu.com/author/laveesh-kocher/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://www.opensourceforu.com/wp-content/uploads/2022/06/7-zip-2200-500x312-1.jpg
|
||||
@@ -0,0 +1,69 @@
|
||||
[#]: subject: "This Open-Source Project Proves Chrome Extensions Can Track You"
|
||||
[#]: via: "https://news.itsfoss.com/chrome-extension-tracking/"
|
||||
[#]: author: "Ankush Das https://news.itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "lkxed"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
这个开源项目证明了 Chrome 扩展可以跟踪你
|
||||
======
|
||||
这会成为放弃基于 Chromium 的浏览器并开始使用 Firefox 的一个理由吗?也许吧,决定权在你。
|
||||
|
||||
![Chrome 扩展追踪器][1]
|
||||
|
||||
即使你有了所有的隐私扩展和高级的保护功能,别人仍然有方法可以识别你或跟踪你。
|
||||
|
||||
请注意,并非所有浏览器都是如此,本文中,我们只关注基于 Chromium 的浏览器,并将 Google Chrome 作为“主要嫌疑人”。
|
||||
|
||||
以前,尽管别人已经能够在你的检测 Chromium 浏览器上,检测到你的已安装的扩展程序,但许多扩展程序都实施了某些保护措施来防止这种检测。
|
||||
|
||||
然而,一位名为 “**z0ccc**” 的安全研究人员发现了一种检测已安装 Chrome 浏览器扩展程序的新方法,该方法可进一步用于**通过“浏览器指纹识别”来跟踪你**。
|
||||
|
||||
**如果你还不知道的话**:<ruby>浏览器指纹识别<rt>Browser Fingerprinting</rt></ruby>是指收集有关你的设备/浏览器的各种信息,以创建唯一的指纹 ID(哈希),从而在互联网上识别你的一种跟踪方法。“各种信息”包括:浏览器名称、版本、操作系统、已安装的扩展程序、屏幕分辨率和类似的技术数据。
|
||||
|
||||
这听起来像是一种无害的数据收集技术,但可以使用这种跟踪方法在线跟踪你。
|
||||
|
||||
### 检测 Google Chrome 扩展
|
||||
|
||||
研究人员分享了一个开源项目 “**Extension Fingerprints**”,你可以使用它来测试,你安装的 Chrome 扩展,是否正在被人检测。
|
||||
|
||||
新技术涉及一种“时差”方法,该工具比较了扩展获取资源的时间。与浏览器上未安装的其他扩展相比,受保护的扩展需要更多时间来获取资源。因此,这有助于从 1000 多个扩展列表中识别出一些扩展。
|
||||
|
||||
关键是:即使有了这些新的进步和技术来防止跟踪,Chrome 网上应用店的扩展也可以被检测到。
|
||||
|
||||
![][2]
|
||||
|
||||
并且,在检测到已安装的扩展程序后,别人可以就使用浏览器指纹识别,对你进行在线跟踪。
|
||||
|
||||
令人惊讶的是,即使你安装有 uBlocker、AdBlocker、或 Privacy Badger(一些流行的以隐私为重点的扩展程序)之类的扩展程序,使用了这种方法,它们也都可以被检测到。
|
||||
|
||||
你可以在它的 [GitHub 页面][3] 上查看所有技术细节。如果你想自己测试它,请前往它的 [扩展指纹识别网站][4] 自行检查。
|
||||
|
||||
### 大救星 Firefox?
|
||||
|
||||
嗯,似乎是的,毕竟我出于各种原因,[不断切回到 Firefox][5]。
|
||||
|
||||
这个新发现的(跟踪)方法应该适用于所有基于 Chromium 的浏览器。我在 Brave 和 Google Chrome 上都测试了这个方法。研究人员还提到,该工具不适用于在 Microsoft Edge 中使用的,微软应用商店中的扩展。但是,相同的跟踪方法仍然有效。
|
||||
|
||||
正如研究人员指出,Mozilla Firefox 可以避免这种情况,因为每个浏览器实例的扩展 ID 都是唯一的。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/chrome-extension-tracking/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[lkxed](https://github.com/lkxed)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://news.itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://news.itsfoss.com/wp-content/uploads/2022/06/opensource-project-tracker-chrome-extensions.jpg
|
||||
[2]: https://news.itsfoss.com/wp-content/uploads/2022/06/extension-fingerprints.jpg
|
||||
[3]: https://github.com/z0ccc/extension-fingerprints
|
||||
[4]: https://z0ccc.github.io/extension-fingerprints/
|
||||
[5]: https://news.itsfoss.com/why-mozilla-firefox/
|
||||
@@ -0,0 +1,63 @@
|
||||
en[#]: subject: "Linus Torvalds Expects to See Rust Support in the Kernel Soon"
|
||||
[#]: via: "https://news.itsfoss.com/linux-kernel-rust/"
|
||||
[#]: author: "Ankush Das https://news.itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "lkxed"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Linus Torvalds 暗示很快就可以在内核中看到对 Rust 的支持
|
||||
======
|
||||
正如 Linus Torvalds 所暗示,Linux Kernel 5.20 可能会与对 Rust 的支持一起首次亮相。你怎么看?
|
||||
|
||||
![Linus][1]
|
||||
|
||||
市面上已经有许多用 Rust 重写的开源项目。因此,Rust 一段时间以来被认为是 Linux 内核的第二语言,也就不足为奇了。
|
||||
|
||||
几天前,在 [Linux 基金会开源峰会][2] 上,Linus Torvals 提到他们预计将在下一个内核版本(即 Linux 内核 5.20)中对 Rust 进行试验。
|
||||
|
||||
如果你不知道,正如 [Phoronix][3] 率先报道的那样,Linux 内核补丁中已经包含了少量的示例驱动程序,以及支持基本的基础设施的 Rust 代码。
|
||||
|
||||
因此,Linus Torvalds 对可能合并 Rust 支持的暗示,也不足为奇。但是,这无疑是令人兴奋的!
|
||||
|
||||
### 用于 Linux 内核的 Rust
|
||||
|
||||
这么做的最终目标是让 Linux Kernel 变得更好,但它现在仍然处于试运行阶段。
|
||||
|
||||
凭借其所有优势,Rust 正日益成为一种流行的编程语言。不要忘记,[System76 也在开发一个用 Rust 编写的新桌面环境][4]。
|
||||
|
||||
然而,并不是所有参与维护 Linux 内核的人都熟悉这种编程语言。
|
||||
|
||||
那么,这会是一个问题吗?
|
||||
|
||||
考虑到内核中还有其他语言,Linus Torvalds 并不认为这是一个大问题。他还提到他希望看到 Rust 成为新的一份子。
|
||||
|
||||
[The Register][5] 报道称,Linus Torvalds 表示会信任维护者,除非他们犯了错误。
|
||||
|
||||
### Linux 5.20:何时发布?
|
||||
|
||||
Linux 内核 5.19 版本将于 7 月底左右发布。因此,5.20 版本的合并窗口应该会在其稳定发布后打开(假设没有意外延迟的话)。
|
||||
|
||||
除了 Rust 以外,Linux Kernel 5.20 应该也是对下一代硬件支持的重要更新(包括 RDNA3),同时提供了更多功能。
|
||||
|
||||
*你如何看待 Rust 在不久的将来会进入 Linux 呢?你感到兴奋吗?欢迎在下方评论区告诉我们~*
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/linux-kernel-rust/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[lkxed](https://github.com/lkxed)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://news.itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://news.itsfoss.com/wp-content/uploads/2022/06/linus-expects-rust-support-in-linux-kernel-soon.jpg
|
||||
[2]: https://events.linuxfoundation.org/open-source-summit-north-america/
|
||||
[3]: https://www.phoronix.com/scan.php?page=news_item&px=Rust-Linux-v7-Plus-New-Uutils
|
||||
[4]: https://news.itsfoss.com/system76-rust-cosmic-desktop/
|
||||
[5]: https://www.theregister.com/2022/06/23/linus_torvalds_rust_linux_kernel/
|
||||
@@ -0,0 +1,92 @@
|
||||
[#]: subject: "Should Businesses Opt for Serverless Computing?"
|
||||
[#]: via: "https://www.opensourceforu.com/2021/12/should-businesses-opt-for-serverless-computing/"
|
||||
[#]: author: "Krishna Mohan Koyya https://www.opensourceforu.com/author/krishna-mohan-koyya/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "lkxed"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
企业应该选择无服务器计算吗?
|
||||
======
|
||||
无服务器计算将服务器从等式中移除,使企业能够专注于应用功能。那么,企业是不是都应该选择无服务器计算呢?让我们来探究一下吧!
|
||||
|
||||
![2021 年 10月 OSFY 无服务器云计算][1]
|
||||
|
||||
直至不久之前,几乎每个产品经理都会将他/她的工程资源,分成两个独立的团队 —— 开发团队和运维团队。开发团队通常参与编码、测试和构建应用功能,而运维团队负责应用程序的交付、部署和运行维护。
|
||||
|
||||
当开发团队构建电商应用时,运维团队会搭建好服务器来托管该应用。搭建服务器涉及到许多方面,其中包括:
|
||||
|
||||
* 选择合适的硬件和操作系统
|
||||
* 应用所需的补丁集
|
||||
* 搭建所需服务器环境,如 JDK、Python、Tomcat、NodeJS 等
|
||||
* 部署、配置和提供实际的应用
|
||||
* 打开并固定合适的端口
|
||||
* 搭建所需的数据库引擎
|
||||
|
||||
……这个名单还在继续。
|
||||
|
||||
除此之外,管理人员还对容量规划感到头疼。毕竟,任何重要应用都应始终保持 100% 可用、可靠且可扩展。这需要对硬件进行最佳投资。众所周知,在一些关键时期,硬件短缺会导致业务损失,而硬件冗余又会损害利润。因此,无论应用是针对本地数据中心,还是针对云基础架构,容量规划都是至关重要的。到目前为止,很明显,企业不仅在功能构建上投入了大量的精力,还在功能交付上也花费了大量的时间。
|
||||
|
||||
<ruby>无服务器计算<rt>Serverless computing</rt></ruby>旨在提供一种无缝的方式来交付功能,而无需担心服务器的设置和维护。换句话说,无服务器计算平台提供了一个<ruby>“即用型”<rt>ready-to-use</rt></ruby>环境,企业可以尽快将应用程序构建和部署为一些较小的功能。这就是为什么这种方法被称为<ruby>“功能即服务”<rt>Function as a Service</rt></ruby>(FaaS)。
|
||||
|
||||
请记住,无服务器计算中仍然存在服务器,但它由 AWS、微软和谷歌等 FaaS 供应商负责。
|
||||
|
||||
例如,AWS 以 “Lambda 函数”的形式提供了一个无服务器计算环境。开发人员可以选择将应用程序构建为一组 Lambda 函数,这些函数可以用 NodeJS、Java、Python 和其他一些语言编写。AWS 提供了一个现成的环境来部署这些函数。它还提供了即用型数据库服务器、文件服务器、应用程序网关和身份验证服务器等。
|
||||
|
||||
同样,Microsoft Azure 也提供了一个环境,它可以用 C# 等语言构建和部署 Azure 函数。
|
||||
|
||||
### 为什么选择无服务器?
|
||||
|
||||
有两个主要因素推动了无服务器计算的普及。
|
||||
|
||||
#### 1、即用型环境
|
||||
|
||||
显然,这是无服务器计算的最大卖点。企业无需提前采购/预订硬件或实例,也无需操心许可证,以及设置和配置服务器。他们不需要为扩大和缩小规模而烦恼。所有这些都由 FaaS 供应商负责。
|
||||
|
||||
#### 2、最优成本
|
||||
|
||||
由于 FaaS 供应商总是根据环境的利用率向客户收费(按使用付费模式),因此企业无需担心前期成本和资源浪费。例如,AWS 根据 Lambda 函数接收的请求数量、在数据表上运行的查询数量等指标来向客户端收费。
|
||||
|
||||
### 无服务器计算的挑战
|
||||
|
||||
与任何其他方法一样,无服务器计算也不是每个人都可以盲目遵循的完美方法。它本身也有一系列限制。以下是其中的几个。
|
||||
|
||||
#### 1、供应商锁定
|
||||
|
||||
当使用无服务器计算时,第一个也是最重要的问题就是,Lambda 或 Azure 等函数将使用供应商提供的 API 来编写。例如,使用 AWS Lambda API 编写的函数无法部署到 Google Cloud 中,反之亦然。因此,无服务器计算迫使企业在许多年内,只能使用同一家供应商。并且,应用的成功或失败不仅取决于它的功能,还取决于供应商在性能等方面的能力。
|
||||
|
||||
#### 2、编程语言
|
||||
|
||||
没有无服务器计算平台支持所有的编程语言。此外,对于它支持的编程语言,它也可能不支持其所有版本。这样一来,应用开发团队只能选择供应商提供的语言。就团队的能力而言,这可能是非常关键的。
|
||||
|
||||
#### 3、最优成本,真的吗?
|
||||
|
||||
其实也不一定,这一切都取决于资源的使用情况。如果你的应用正在承受巨大的负载,例如每秒数百万个请求,那么你所支付的费用可能会过高。在这样的规模下,在本地或云端拥有自己的服务器可能会更便宜。这并不意味着具有 Web 规模的应用不适合用无服务器计算。归根结底,它还是取决于你的平台的构建方式,以及你与供应商签署的协议。
|
||||
|
||||
#### 4、生态系统
|
||||
|
||||
没有应用是为了一个孤立的环境而编写的。它总是需要其他组件,如数据存储、数据库、安全引擎、网关、消息服务器、队列、缓存等。每个平台都提供自己的一组此类工具。例如,AWS 提供了 Dynamo DB 作为其 NoSQL 解决方案之一。显然,其他供应商也提供了自己的 NoSQL 解决方案。因此,团队又会被迫地基于所选平台来构建应用程序。尽管大多数商业 FaaS 供应商都为特定需求提供了多个组件,但并非每个组件都可能是同类型中最佳的。
|
||||
|
||||
### 为什么不考虑容器呢?
|
||||
|
||||
在过去十年中,我们中的许多人都迁移到了容器化部署模型,因为它们为昂贵的物理机或虚拟机提供了一种轻量级的替代方案。有了 Kubernetes 等编排工具后,我们乐于部署容器化应用,同时也满足了 Web 规模的要求。容器提供了与底层环境一定程度的隔离,这使得部署相对容易。但是,我们仍然需要在硬件(本地或云)、许可证、网络、配置等方面进行投资,这需要具有前瞻性的规划、合适的技术能力和仔细的监控。无服务器计算,尽管它也有自己的优点和缺点,但它让我们把这些责任也摆脱了。
|
||||
|
||||
### 展望未来
|
||||
|
||||
我们正处于持续开发、持续集成和持续部署的时代。每个企业都面临着竞争。<ruby>上市时间<rt>Time to market</rt></ruby>(TTM)在吸引客户、留住客户这两个方面,发挥着重要作用。在这种背景下,企业喜欢花更多时间来尽可能快地推出功能,而不是在部署和维护的细节上苦苦挣扎。无服务器计算有可能满足这些需求。大玩家们正在投入巨额资金,以使 FaaS 尽可能地无缝且经济。无服务器计算的未来看起来是一片光明。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.opensourceforu.com/2021/12/should-businesses-opt-for-serverless-computing/
|
||||
|
||||
作者:[Krishna Mohan Koyya][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[lkxed](https://github.com/lkxed)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.opensourceforu.com/author/krishna-mohan-koyya/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://www.opensourceforu.com/wp-content/uploads/2021/10/Severless-Cloud-Computing-Featured-image-OSFY-Oct-2021.jpg
|
||||
@@ -0,0 +1,140 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Donke-Hao)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Configure a Linux workspace remotely from the command line)
|
||||
[#]: via: (https://opensource.com/article/21/1/remote-configuration-xfce4)
|
||||
[#]: author: (David Both https://opensource.com/users/dboth)
|
||||
|
||||
从命令行远程配置 Linux 工作区
|
||||
|
||||
======
|
||||
|
||||
几乎所有的事情都可以从 Linux 命令行完成,包括 Xfce4 的远程配置。
|
||||
![Coding on a computer][1]
|
||||
|
||||
几乎所有的事情都可以通过命令行管理和配置。意味着几乎所有的事情都可以在本地或者通过 SSH 远程登录进行管理。有时候在互联网上搜索会花费一点时间,但是如果(译者:个人感觉这里上下文有省略一些意思,我感觉是“如果利用这段时间,你能想到…”——_**请校对者注意并删除括号内的话**_)你能想到一个可能可以从命令行完成的任务。
|
||||
|
||||
|
||||
### 问题
|
||||
有时候需要使用命令行进行远程修改。在这种特殊情况下,我需要响应远程用户的请求将在 [Xfce][2] 控制板上的工作区从四个减少到三个。这种配置仅需要在互联网上搜索约 20 分钟。
|
||||
|
||||
默认工作区数量和许多其他 **xfwm4** 设置可以在 **/usr/share/xfwm4/defaults** 这个文件中找到并修改。因此将 _workspace_count=2_ 设置为 _workspace_count=4_ 改变了所有主机的默认值。 同时,非 root 用户可以执行 **xfconf-query** 命令来查询并修改 **xfwm4** 窗口管理器的不同属性。它应该由需要更改的用户帐户使用,而不是由 root 使用。
|
||||
|
||||
在下面的例子中,首先我验证了当前工作区数量为 _4_ ,然后将数量改为 _2_ ,最后确认了新设置。
|
||||
|
||||
|
||||
|
||||
```
|
||||
[user@test1 ~]# xfconf-query -c xfwm4 -p /general/workspace_count
|
||||
4
|
||||
[user@test1 ~]# xfconf-query -c xfwm4 -p /general/workspace_count -s 2
|
||||
[user@test1 ~]# xfconf-query -c xfwm4 -p /general/workspace_count
|
||||
2
|
||||
[user@test1 ~]#
|
||||
```
|
||||
|
||||
此更改会立即发生,并且用户可以看到,无需重新启动,甚至无需注销并重新登录。当我输入命令以设置不同数量的工作区时,通过观察工作区切换器的变化,使我在我的工作站上有些快乐。 这些天,我尽我所能获得娱乐。 ;-)
|
||||
|
||||
|
||||
### 更多探索
|
||||
|
||||
现在我解决了问题,我决定更详细的探索一下 **xfconf-query** 命令。不幸的是,该工具没有手册或信息页,**/usr/share** 中也没有任何文档。退而求其次,使用 **-h** 选项获取一些帮助信息。
|
||||
|
||||
|
||||
```
|
||||
$ xfconf-query -h
|
||||
Usage:
|
||||
xfconf-query [OPTION…] - Xfconf commandline utility
|
||||
Help Options:
|
||||
-h, --help 显示帮助选项
|
||||
Application Options:
|
||||
-V, --version 版本信息
|
||||
-c, --channel 询问/修改通道
|
||||
-p, --property 询问/修改属性
|
||||
-s, --set 更新权限的值
|
||||
-l, --list 罗列属性(或者通道 如果没有用 -c 指定)
|
||||
-v, --verbose 详细输出
|
||||
-n, --create 当新属性不存在,则创建它
|
||||
-t, --type 指定属性值类型
|
||||
-r, --reset 重置属性
|
||||
-R, --recursive 递归(与 -r 一起使用)
|
||||
-a, --force-array 即使只有一个元素也强制数组
|
||||
-T, --toggle 反转现有的布尔属性
|
||||
-m, --monitor 监视属性更改的通道
|
||||
```
|
||||
|
||||
这没有多大帮助,但无论如何我们都可以从中找出一些好处。首先, _通道_ 以属性分组便于修改。我对 **general** 通道进行了更改,属性为 **workspace_count** 。 让我们看看完整的通道列表。
|
||||
|
||||
```
|
||||
$ xfconf-query -l
|
||||
Channels:
|
||||
xfwm4
|
||||
xfce4-keyboard-shortcuts
|
||||
xfce4-notifyd
|
||||
xsettings
|
||||
xfdashboard
|
||||
thunar
|
||||
parole
|
||||
xfce4-panel
|
||||
xfce4-appfinder
|
||||
xfce4-settings-editor
|
||||
xfce4-power-manager
|
||||
xfce4-session
|
||||
keyboards
|
||||
displays
|
||||
keyboard-layout
|
||||
ristretto
|
||||
xfcethemer
|
||||
xfce4-desktop
|
||||
pointers
|
||||
xfce4-settings-manager
|
||||
xfce4-mixer
|
||||
```
|
||||
|
||||
给定通道的属性也可以用下列的命令来查看。我使用 **less** 寻呼机,因为结果是一长串数据。我已经缩减了下表,但留下了足够的空间来查看你可以找到的条目类型。
|
||||
|
||||
|
||||
```
|
||||
$ xfconf-query -c xfwm4 -l | less
|
||||
/general/activate_action
|
||||
/general/borderless_maximize
|
||||
/general/box_move
|
||||
/general/box_resize
|
||||
/general/button_layout
|
||||
/general/button_offset
|
||||
<SNIP>
|
||||
/general/workspace_count
|
||||
/general/workspace_names
|
||||
/general/wrap_cycle
|
||||
/general/wrap_layout
|
||||
/general/wrap_resistance
|
||||
/general/wrap_windows
|
||||
/general/wrap_workspaces
|
||||
/general/zoom_desktop
|
||||
(END)
|
||||
```
|
||||
|
||||
你可以用这种方式探索所有的通道。我发现频道通常对应 **设置管理器** 中的各种设置。属性是你将在这些对话框中设置的属性。请注意,并非您会在 **设置管理器** 对话窗口中找到的所有图标都是 **Xfce** 桌面的一部分,因此它们没有对应的通道。 **屏幕保护程序** 就是一个例子,因为它是通用的 GNU 屏幕保护程序,并不是 **Xfce** 独有的。 **设置管理器** 是 **Xfce** 定位这些配置工具的一个很好的中心位置。
|
||||
|
||||
|
||||
### 总结
|
||||
|
||||
综上所述,在 **xconf-query** 命令似乎没有任何手册或信息页,并且我在网上发现了一些错误的糟糕的记录信息。我发现对 **Xfce4** 来说最好的文件是 [Xfce 网站][2],以及一些具体信息可以在 **xconf-query** 找到。、
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/remote-configuration-xfce4
|
||||
|
||||
作者:[David Both][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[Donke-Hao](https://github.com/Donke-Hao)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/dboth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/code_computer_laptop_hack_work.png?itok=aSpcWkcl (Coding on a computer)
|
||||
[2]: https://www.xfce.org/
|
||||
@@ -0,0 +1,70 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Donkey)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (3 stress-free steps to tackling your task list)
|
||||
[#]: via: (https://opensource.com/article/21/1/break-down-tasks)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
轻松解决你的任务清单的三个步骤
|
||||
======
|
||||
将你的大任务分为小步骤,避免自己不堪重负。
|
||||
![Team checklist][1]
|
||||
|
||||
去年,这个年度系列文章覆盖了个人应用。今年,除了在 2021 年提供帮助的策略外,我们还在寻找一体化解决方案。欢迎来到 2021 年 21 天生产力的第 14 天。
|
||||
|
||||
本周开始,我先回顾我的日程安排,看看我需要或想要完成的事情。通常,列表上有些较大的项目。无论来自工作上的问题,一系列关于生产力的文章,或者改进鸡舍,当作为一项工作时,这个任务真的很艰巨。很有可能在一个时间段我不能坐下来,甚至在一天内完成类似(例如,请注意)21 篇文章之类的事情。
|
||||
|
||||
![21 Days of Productivity project screenshot][2]
|
||||
|
||||
21 天的生产力 (Kevin Sonney, [CC BY-SA 4.0][3])
|
||||
|
||||
所以当我的清单上有这样的东西时,我做的第一件事就是把它分解成更小的部分。如著名的诺贝尔文学奖得主 [William Faulkner][4] 说的“移山的人,从小石头开始。”(译注:感觉与“千里之行,始于足下”是一个意思) 我们要解决大任务(山)并且需要完成各个步骤(小石头)。
|
||||
|
||||
|
||||
我使用下面的步骤将大任务分割为小步骤:
|
||||
|
||||
1. 我通常很清楚完成一项任务需要做什么。 如果没有,我会做一些研究来弄清楚这一点。
|
||||
2. 我会顺序的写下完成的步骤。
|
||||
3. 最后,我坐下来拿着我的日历和清单,开始将任务分散到几天(或几周或几个月),以了解我何时可以完成它。
|
||||
|
||||
|
||||
现在我不仅有计划还知道多久能完成。逐步完成,我可以看到这项大任务不仅变得更小,而且更接近完成。
|
||||
|
||||
军队有句古话,“遇敌无计”。 几乎可以肯定的是,有一两点(或五点)我意识到像“截屏”这样简单的事情需要扩展到更复杂的事情。 事实上,在 [Easy!Appointments][5] 的截图中,竟然是:
|
||||
|
||||
1. 安装和配置 Easy!Appointments
|
||||
2. 安装和配置 Easy!Appointments WordPress 插件
|
||||
3. 生成 API 密钥来同步日历
|
||||
4. 截屏
|
||||
|
||||
|
||||
|
||||
即便如此,我也不得不将这些任务分解成更小的部分——下载软件、配置 NGINX、验证安装……你明白了。 没关系。 一个计划或一组任务不是一成不变的,可以根据需要进行更改。
|
||||
|
||||
![project completion pie chart][6]
|
||||
|
||||
今年的计划已经完成了 2/3 ! (Kevin Sonney, [CC BY-SA 4.0][3])
|
||||
|
||||
这是一项后天习得的技能,最初几次需要一些努力。学习如何将大任务分解成更小的步骤可以让您跟踪实现目标或完成大任务的进度,而不会在过程中不知所措。
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/break-down-tasks
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[Donkey](https://github.com/Donkey-Hao)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/checklist_todo_clock_time_team.png?itok=1z528Q0y (Team checklist)
|
||||
[2]: https://opensource.com/sites/default/files/day14-image1.png
|
||||
[3]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[4]: https://en.wikipedia.org/wiki/William_Faulkner
|
||||
[5]: https://opensource.com/article/21/1/open-source-scheduler
|
||||
[6]: https://opensource.com/sites/default/files/day14-image2_1.png
|
||||
@@ -1,94 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (godgithubf)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (3 ways to play video games on Linux)
|
||||
[#]: via: (https://opensource.com/article/21/2/linux-gaming)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
三种在Linux系统上玩视频游戏的方式
|
||||
======
|
||||
如果你准备好下载游戏并且全方位体验游戏的话,那么在 linux 下启动游戏吧!
|
||||
![Gaming with penguin pawns][1]
|
||||
|
||||
从 2021 年以后,人们有更多喜欢 Linux 的理由。在这个系列里,我将分享 21 个使用 Linux 的理由。今天,我将从游戏开始。
|
||||
|
||||
我过去认为电脑游戏者是一种特殊的人群,要被研究人员在数年的研究和测试之后严谨地认定。我从来没有把我自己归为电脑游戏者,因为我所玩过的游戏既不是桌面游戏(棋类游戏和纸笔角色扮演游戏)也不是探险游戏和俄罗斯方块。现在,这些游戏可以在移动设备、控制台、电脑和电视机等各种环境上玩。好像该是时候承认游戏者可以以形形色色的方式参与进来。如果你想自称为游戏者,你就可以,不需任何资格认定。你不必记得有科乐美等类似的游戏公司。你不必购买和玩3A级的游戏,只要你时常玩游戏你就完全可以自称为游戏者。如果你想成为一个游戏者,现在使用 Linux 正当其时。
|
||||
|
||||
### 欢迎到圈子里
|
||||
|
||||
剥除排行榜上闪闪发光的广告及背后的东西,你肯定会发现一个欣欣向荣的游戏世界。在任何人相信既不是电子表格也不是练习打字一类的软件能挣钱以前新兴的游戏市场已经开始发展起来了。非主流的游戏已经在流行文化上以各种方式打上了自己的烙印(信不信由你,《我的世界》尽管不是开源的,作为独立制作的游戏已经发展起来了),这也证实了,在玩家眼里,游戏先于产品价值。
|
||||
|
||||
在独立制作和开源开发者之间有很多交叉的地方。
|
||||
|
||||
有各种各样的开源游戏可玩,包括大量的第一视角射击游戏,益智游戏像 Nodulus ,策略经营游戏像运输大亨,竞速游戏向 Jethook ,减压游戏像 Sauerbraten ,等等还有很多未提到的(多亏了像 Open Jam 这样伟大的倡议,每年都有新增的游戏)
|
||||
|
||||
![Jethook game screenshot][10]
|
||||
|
||||
总的来说,探索开源游戏的世界的体验和主流游戏工作室的产品带来的即时的满足是很不同的。大的游戏工作室生产的游戏提供大量的视觉和听觉刺激,知名演员,和多达60小时的游戏。独立和开源游戏不可能和它匹敌。但是,主流游戏工作室无法达到的是当你发现一款别人未曾听说过的游戏时的产生的发现和个人连接的感受。主流工作室不希望当你认识到世界上的的每个人都非常需要知道你刚玩过的那个游戏所获取的那种感受。(这样翻译真别扭 )
|
||||
|
||||
花点时间找出你最喜欢的游戏,然后浏览下你的发行商的软件仓库,打开开源游戏仓库,看下哪个是发行商没有覆盖到的,如果你足够喜欢的游戏,帮忙推广一下吧。
|
||||
|
||||
### Proton and WINE
|
||||
|
||||
Linux 上的游戏不止于开源,但是从开源开始的。数年前Valve软件公司通过发行 Steam 客户端的 Linux 版把 Linux 带入游戏市场,希望是能够强制游戏工作室能在 Linux 系统上写本地代码。一些工作室这样做了,但 Valve 公司并没有成功的把 Linux 推为主要的平台,即使是 Valve 品牌的游戏电脑。并且大多数游戏工作室又转回仅在 windows 平台上开发游戏的旧方式。
|
||||
|
||||
有趣的是,最终的结果是有更多的开源代码被生产出来。 Valve 公司为 Linux 兼容创建了 Proton 工程,一个可以转换 windows 系统游戏到 Linux 的兼容层。在 Proton 的内核层面,它使用了WINE(WINE不是模拟器),好的令人难以置信的是重新实现的主要 windows 库是开源的。
|
||||
|
||||
游戏市场的打破结果成为了开源世界的宝藏。今天,来自主流工作室的大多数游戏都可以在 Linux 上运行就好像他们在 windows 上运行一样。
|
||||
|
||||
当然,如果你是必须要有最新版的游戏的这类玩家,你可定会遇到令人不愉快的惊喜。尽管那不是惊喜,很少有主流的游戏发行时毫无漏洞,那需要一周后大量的补丁。这些漏洞在Proton和WINE上更糟糕,因此 Linux 游戏者经常从使用早期版本中获益。这种妥协可能是值得的。我玩过一些游戏,它们在 Proton 平台运行完美,后来从愤怒的论坛邮件中发现它在最新版的 windows 上运行有明显的谜一般的致命错误。总之,似乎来自主流工作室的游戏并不完美,但你可能在 Linux 上遇到相似但不同的问题正如你在 windows 上遇到的。
|
||||
|
||||
### Flatpak
|
||||
|
||||
最近 Linux 历史上最令人激动的发展就是 Flatpak 了,跨越了本地容器和包,它和游戏无关(或者它和游戏息息相关),它使得 Linux 应用能基本上被分发到任意的 Linux 发行版上。这也适用游戏,因为有相当多次要的技术在游戏中使用。并且它可以很好地对给定的游戏要求发行维护者来保持和所有最新版要求一致
|
||||
|
||||
Flapak 从发行中为应用库抽象出一种公共的 Flatpak 特定的层。Flatpak 的发行者知道 如果一个库不在 Flatpak SDK 中,那么它必须要包含在 Flatpak 中,简单而直接。
|
||||
|
||||
多亏了 Flatpak , Steam 客户端可以运行在一些像 Fedora, RHEL, Slackware 等从传统角度看并不面向游戏市场的操作系统
|
||||
|
||||
### Lutris
|
||||
|
||||
如果你不渴望注册 steam 账号,那么可以用我比较偏爱的游戏客户端 Lutris 。表面上看,Lutris 是一个简单的游戏启动器,当你想玩游戏但还没决定玩什么的时候你可以去的地方。有了Lutris,你可以添加你系统上的所有游戏到你的游戏库,然后从 Lutris 界面启动并立即玩起来。更好的是,Lutris 贡献者(像我一样),可以正常的发布安装脚本来使安装你拥有的游戏变得容易。这并不是必须的,但它可以是一个很好的捷径来免除乏味的配置。
|
||||
Lutris 也可以支持运行者或者子系统来运行那些不能从应用菜单直接启动的游戏。比如你想玩控制台游戏像开源的魔兽争霸,你必须运行模拟器。如果你已经安装过模拟器的话, Lutris 可以帮你处理。除此以外,如果你有一些老旧的游戏账号, Lutris 可以访问它,并可以把游戏导入你的游戏库中。
|
||||
|
||||
没有比 Lutris 更容易的方式来管理你的游戏了。
|
||||
|
||||
### 玩游戏
|
||||
|
||||
Linux 游戏是一个充实且给人力量的体验。我过去避免玩电脑游戏因为我没有觉得我有很多的选择。似乎有很多昂贵的游戏在发行并且不可避免的获得好或者不好的体验,然后很快有转向下一个。另一方面,开源游戏把我引入了游戏的王国。我见到过其他玩家和开发者。我见到过艺术家和音乐家,粉丝以及发起人。我玩过各种各样的游戏但我从来都没认识到他们的确存在过。他们仅仅够我玩一下午,然而其他的却让我长久的着迷于游戏,改进,关卡设计和乐趣。
|
||||
|
||||
如果你准备好来从各个角度体验下游戏的话,在 Linux 上开始游戏吧。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/2/linux-gaming
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/godgithubf)
|
||||
校对:[校对者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/alternatives/minecraft
|
||||
[3]: https://itch.io/jam/open-jam-2020
|
||||
[4]: https://opensource.com/article/20/5/open-source-fps-games
|
||||
[5]: https://hyperparticle.itch.io/nodulus
|
||||
[6]: https://www.openttd.org/
|
||||
[7]: https://rcorre.itch.io/jethook
|
||||
[8]: http://sauerbraten.org/
|
||||
[9]: https://opensource.com/article/18/9/open-jam-announcement
|
||||
[10]: https://opensource.com/sites/default/files/game_0.png
|
||||
[11]: http://flathub.org
|
||||
[12]: https://github.com/ValveSoftware/Proton
|
||||
[13]: http://winehq.org
|
||||
[14]: https://opensource.com/business/16/8/flatpak
|
||||
[15]: https://www.redhat.com/en/enterprise-linux-8
|
||||
[16]: http://lutris.net
|
||||
[17]: https://opensource.com/article/18/10/lutris-open-gaming-platform
|
||||
[18]: https://ndswtd.wordpress.com/download
|
||||
@@ -0,0 +1,138 @@
|
||||
[#]: subject: (How to Convert File Formats With Pandoc in Linux [Quick Guide])
|
||||
[#]: via: (https://itsfoss.com/pandoc-convert-file/)
|
||||
[#]: author: (Bill Dyer https://itsfoss.com/author/bill/)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (lkxed)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
How to Convert File Formats With Pandoc in Linux [Quick Guide]
|
||||
如何在 Linux 中使用 Pandoc 转换文件格式(快速指南)
|
||||
======
|
||||
|
||||
在之前的一篇文章中,我介绍了 [使用 pandoc 将少量 Markdown 文件批量转换为 HTML 的过程][1]。在那篇文章中,我创建了多个 HTML 文件,但 Pandoc 可以做的更多。它被称为文档转换的“瑞士军刀” —— 这是有充分理由的。很少有它做不到的事情。
|
||||
|
||||
[Pandoc][2] 可以将 .docx、.odt、.html、.epub、LaTeX、DocBook 等格式互相转换,或者转换为其他格式,例如 JATS、TEI Simple、AsciiDoc 等。
|
||||
|
||||
是的,这意味着 Pandoc 可以将 .docx 文件转换为 .pdf 和 .html 文件,但你可能会想:“Word 也可以将文件导出为 .pdf 和 .html。为什么我需要 Pandoc 呢?”
|
||||
|
||||
嗯,本来呢,你这个说法也没错,但考虑到 Pandoc 可以转换这么多格式,它很可能成为你所有转换任务的首选工具。例如,我们中的许多人都知道 [Markdown 编辑器][3] 可以将其 Markdown 文件导出为 .html。而使用 Pandoc 文件也可以转换为许多其他格式。
|
||||
|
||||
我很少将 Markdown 导出为 HTML。我通常让 Pandoc 来做这件事。
|
||||
|
||||
### 使用 Pandoc 转换文件格式
|
||||
|
||||
![][4]
|
||||
|
||||
本文中,我会将 Markdown 文件转换成几种不同的格式。我几乎所有的写作都使用 Markdown 语法,但我经常需要转换为另一种格式:学校作业通常需要的 .docx 格式;我创建的网页通常需要的 .html 格式;工作需要的 .epub 格式;传单和讲义需要的 .pdf 格式;甚至包括大学数字人文项目偶尔需要的 TEI Simple 格式。Pandoc 可以轻松处理所有这些格式,甚至更多。
|
||||
|
||||
首先,你需要 [安装 pandoc][5]。此外,要创建 .pdf 文件,还需要 LaTeX。我最喜欢的套件是 [TeX Live][6]。
|
||||
|
||||
**注意**:如果你想在安装前试用 pandoc,这里有一个在线试用页面:<http://pandoc.org/try/>。
|
||||
|
||||
#### 安装 pandoc 和 texlive
|
||||
|
||||
Ubuntu 和其他 Debian 发行版的用户可以在终端中输入以下命令:
|
||||
|
||||
```
|
||||
sudo apt-get update
|
||||
sudo apt-get install pandoc texlive
|
||||
```
|
||||
|
||||
请注意第二行,你将一次性安装 `pandoc` 和 `texlive`。[apt-get 命令][7] 支持你这样做。不过,我建议你先去喝杯咖啡,因为这可能需要几分钟的时间。
|
||||
|
||||
#### 开始转换
|
||||
|
||||
安装完成 `pandoc` 和 `texlive` 后,你就可以尝试用它们来完成一些工作了!
|
||||
|
||||
该项目的示例文档将是一篇文章,该文章于 1894 年 12 月首次发表在《北美评论》上,标题为“如何击退火车劫匪”。我将使用的 Markdown 文件是前一段时间创建的,它是该文章的恢复项目的一部分(LCTT 译注:这是篇一百多年前发表的文章,我想“恢复”指的就是把它数字化吧)。
|
||||
|
||||
我把这篇文章保存为 `how_to_repel_train_robbers.md`,它位于我的 `Documents` 目录下,名为 `samples` 的子目录中。它在 Ghostwriter 中看起来是这样的:
|
||||
|
||||
![在 Ghostwriter 中查看原始的 Markdown 文件][8]
|
||||
|
||||
我想创建此文件的 .docx、.pdf 和 .html 版本。
|
||||
|
||||
#### 第一次转换
|
||||
|
||||
首先,我将制作一个 .pdf 副本,因为我在安装 LaTeX 包时遇到了些麻烦。
|
||||
、
|
||||
在 `~/Documents/samples/` 目录中,我输入以下,以创建一个 .pdf 文件:
|
||||
|
||||
```
|
||||
pandoc -o htrtr.pdf how_to_repel_train_robbers.md
|
||||
```
|
||||
|
||||
上述命令将基于 `how_to_repel_train_robbers.md` 文件,创建一个名为 `htrtr.pdf` 的文件。我使用 `htrtr` 作为名称的原因是:嗯,它比 `how_to_repel_train_robbers` 短。`htrtr` 其实是长标题中的单词首字母排列。
|
||||
|
||||
这是 .pdf 文件制作完成后的一个截图:
|
||||
|
||||
![在 Ocular 中查看的转换后的 PDF 文件][9]
|
||||
|
||||
#### 第二次转换
|
||||
|
||||
接下来,我想创建一个 .docx 文件。该命令与我用来创建 .pdf 的命令几乎相同,它是:
|
||||
|
||||
```
|
||||
pandoc -o htrtr.docx how_to_repel_train_robbers.md
|
||||
```
|
||||
|
||||
很快,一个 .docx 文件就创建好了。这是它在 Libre Writer 中的样子:
|
||||
|
||||
![在 Libre Writer 中查看转换后的 DOCX 文件][10]
|
||||
|
||||
#### 第三次转换
|
||||
|
||||
我可能会想在网上发布这个,所以再多一个支持网页的格式也不错。我将使用以下命令创建一个 .html 文件:
|
||||
|
||||
```
|
||||
pandoc -o htrtr.html how_to_repel_train_robbers.md
|
||||
```
|
||||
|
||||
同样,创建它的命令与前两次转换非常相似。这是该 .html 文件在浏览器中的样子:
|
||||
|
||||
![在 Firefox 中查看的转换后的 HTML 文件][11]
|
||||
|
||||
#### 注意到什么了吗?
|
||||
|
||||
让我们再看看之前的命令。它们是:
|
||||
|
||||
```
|
||||
pandoc -o htrtr.pdf how_to_repel_train_robbers.md
|
||||
pandoc -o htrtr.docx how_to_repel_train_robbers.md
|
||||
pandoc -o htrtr.html how_to_repel_train_robbers.md
|
||||
```
|
||||
|
||||
这三个命令唯一不同的是 `htrtr` 后的扩展名。这提示你 pandoc 会依赖于你提供的输出文件扩展名(来决定目标转换格式)。
|
||||
|
||||
### 总结
|
||||
|
||||
Pandoc 可以做的远不止这里完成的三个小转换。如果你选择使用一个首选格式编写文件,但时不时又需要将文件转换为另一种格式,pandoc 很大概率都能为你完成。
|
||||
|
||||
现在,既然你已经学会了,你会用它做什么呢?你会把它自动化吗?如果你的网站上有文章供读者下载怎么办?你可以修改这些小命令,把它们编写成一个脚本,你的读者可以决定他们想要哪种格式。你可以提供 .docx、.pdf、.odt、.epub 或更多格式。你的读者只需要选择一种格式,然后对应的转换脚本就会执行,最后,你的读者下载他们想要的文件。这是完全可以做到的。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/pandoc-convert-file/
|
||||
|
||||
作者:[Bill Dyer][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[lkxed](https://github.com/lkxed)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/bill/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/convert-markdown-files/
|
||||
[2]: https://pandoc.org/
|
||||
[3]: https://itsfoss.com/best-markdown-editors-linux/
|
||||
[4]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/06/pandoc-quick-guide.png?resize=800%2C450&ssl=1
|
||||
[5]: https://pandoc.org/installing.html
|
||||
[6]: https://www.tug.org/texlive/
|
||||
[7]: https://itsfoss.com/apt-get-linux-guide/
|
||||
[8]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/06/convert_with_pandoc_ghostwriter.png?resize=800%2C516&ssl=1
|
||||
[9]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/06/convert_with_pandoc_ocular.png?resize=800%2C509&ssl=1
|
||||
[10]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/06/convert_with_pandoc_libre_writer.png?resize=800%2C545&ssl=1
|
||||
[11]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/06/convert_with_pandoc_firefox.png?resize=800%2C511&ssl=1
|
||||
@@ -0,0 +1,197 @@
|
||||
[#]: subject: (9 reasons I love to use the Qt Creator IDE)
|
||||
[#]: via: (https://opensource.com/article/21/6/qtcreator)
|
||||
[#]: author: (Stephan Avenwedde https://opensource.com/users/hansic99)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (hadisi1993)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
9个我爱用Qt Creator IDE的原因
|
||||
======
|
||||
Qt Creator 就是丰富的Qt库和程序员之间的胶水。
|
||||
![坐在窗前用笔记本电脑的商务女性][1]
|
||||
|
||||
Qt Creator 是Ot框架默认的集成开发环境(IDE),同时也是丰富的Qt库和用户之前的胶水。除了如智能代码补全,调试,项目管理等基础功能外,Qt Creator还提供了很多让软件开发变得更简单的特性。
|
||||
|
||||
在这篇文章中,我会重点介绍一些我最喜欢的[Qt Creator][2]特性。
|
||||
### 黑暗模式
|
||||
|
||||
当我使用一个新的应用时,我的第一个问题是:_这里有黑暗模式吗?_ Qt Creator的回答是:_你更喜欢哪一种黑暗模式呢?_
|
||||
|
||||
你可以在选项菜单中激活黑暗模式。在顶部的菜单栏中,点击**工具**,选择**选项**,然后转到**环境**部分。下面是你能选择的常用外观:
|
||||
|
||||
![ QT Creator 黑暗模式][3]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
### 定制外观
|
||||
|
||||
像每一个Qt应用一样,借助样式表,Qt Creator的外观是高度可定制化的。下面,你可以按照我的做法给Qt Creator一个想要的外观。
|
||||
|
||||
将下面这些内容写入`mycustomstylesheet.css`文件中:
|
||||
|
||||
```
|
||||
QMenuBar { background-color: olive }
|
||||
QMenuBar::item { background-color: olive }
|
||||
QMenu { background-color : beige; color : black }
|
||||
QLabel { color: green }
|
||||
```
|
||||
|
||||
然后使用命令行开启Qt Creator,将样式表作为参数传入:
|
||||
|
||||
|
||||
```
|
||||
`qtcreator -stylesheet=mycustomstylesheet.css`
|
||||
```
|
||||
|
||||
IDE现在看上去应该会变成这样:
|
||||
|
||||
![QT Creator 定制样式表][5]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
在这份[文档][6]中可以查阅更多的样式表
|
||||
|
||||
### 命令行参数
|
||||
Qt Creator 可接受很多命令行选项。例如,如果想在启动时自动加载当前项目,那么你可以将它的路径传递给`*.pro-file`:
|
||||
|
||||
```
|
||||
`qtcreator ~/MyProject/MyQtProject.pro`
|
||||
```
|
||||
|
||||
你甚至可以将默认应该打开的文件和行数作为参数传递。下面这个命令在20行处打开`main.cpp`:
|
||||
|
||||
```
|
||||
`qtcreator ~/MyProject/main.cpp:20`
|
||||
```
|
||||
|
||||
在这份[文档][7]中可以查阅更多Qt特有的命令行选项。
|
||||
|
||||
|
||||
Qt Creator和一般的Qt应用无二,所以,除了自己的命令行参数以外,它也接收[QApplication][8]和[QGuiApplication][9]的一般参数。
|
||||
### 交叉编译
|
||||
|
||||
Qt Creator allows you to define several toolchains, called **Kits**. A kit defines the binaries and SDK for building and running an application:
|
||||
Qt Creator允许你定义一些被称为**Kits**的toolchains。一个Kit定义构建和运行应用所需要的二进制库和SDK。
|
||||
![QT Creator kits][10]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
This allows you to switch between completely different toolchains with just two clicks:
|
||||
这使得你通过两次点击,就在完全不同的toolchains之间切换。
|
||||
|
||||
![在Qt Creator中切换Kits][11]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
在这份[手册][12]中可以查阅更多关于Kits的内容。
|
||||
### 分析工具
|
||||
|
||||
Qt Creator集成了一些最流行的性能分析工具,例如:
|
||||
|
||||
* [Linux Performance Analyzer][13] (需要特定的内核)
|
||||
* [Valgrind][14] memory profiler
|
||||
* [Clang-Tidy and Clazy][15], 一种检查C/C++的linter
|
||||
|
||||
|
||||
![Qt Creator性能分析工具][16]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
### 调试器
|
||||
|
||||
在调试方面,Qt Creator为GNU Debugger(GDB)配备了一个很好的界面。我喜欢它检查容器类型和创建条件断点的方式,很简易。
|
||||
|
||||
![Qt Creator 调试器][17]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
### FakeVim
|
||||
|
||||
如果你喜欢Vim,你可以开启在设置中开启FakeVim来像Vim一样控制Qt Creator。点击**工具**并选择**选项**。在**FakeVim**选项中,你可以找到许多开关来定制FakeVim。除了编辑器的功能外,你可以将自己设置的功能和命令关联起来,定制Vim命令。
|
||||
|
||||
举个例子,你可以将**创建项目**的功能和`build`命令关联到一起去:
|
||||
For example, you can map the function **Build Project** to the `build` command:
|
||||
|
||||
![Qt Creator中的FakeVim][18]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
回到编辑器中,当你按下冒号并输入build,Qt Creator利用配置的toolchain,开始进行构建:
|
||||
|
||||
![Qt Creator中的FakeVim][19]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
你可以中这份[文档][20]中找到FakeVim的更多信息。
|
||||
### 类检测器
|
||||
|
||||
当使用C++开发时,点击Qt Creator右下角的按钮可打开右边的窗口。然后在窗口顶部拉下的菜单中选择**轮廓**。如果你在左侧窗体中有头文件打开,你可以很好地纵览定义的类和类型。如果你切换到源文件中(`*.cpp`),右侧窗体会列出所有定义的方法,双击其中一个,你可以跳转到这个方法:
|
||||
![Qt Creator中的类列表][21]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
### 项目配置
|
||||
|
||||
Qt Creator 的项目建立在项目文件里的`*.pro-file`之上。你可以为你的项目在`*.pro-file`中添加你定制的配置。我向`*.pro-file`中添加了`my_special_config`,它向编译器的定义添加`MY_SPECIAL_CONFIG`。
|
||||
|
||||
```
|
||||
QT -= gui
|
||||
|
||||
CONFIG += c++11 console
|
||||
CONFIG -= app_bundle
|
||||
|
||||
CONFIG += my_special_config
|
||||
|
||||
my_special_config {
|
||||
DEFINES += MY_SPECIAL_CONFIG
|
||||
}
|
||||
```
|
||||
|
||||
Qt Creator 自动根据当前配置设置代码高亮:
|
||||
![Qt Creator的特殊配置][22]
|
||||
|
||||
(Stephan Avenwedde, [CC BY-SA 4.0][4])
|
||||
|
||||
`*.pro-file` 使用[qmake语言][23]进行编写
|
||||
### Summary
|
||||
这些特性仅仅是Qt Creators提供特性的冰山一角。初学者们应该不会感到被其众多的功能所淹没,Qt Creator是一款对初学者很友好的IDE。它甚至可能是开始C++开发最简单的方式。如果要获得QT Creator特性的全面概述,请参考它的[官方文档][24]。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/6/qtcreator
|
||||
|
||||
作者:[Stephan Avenwedde][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[hadisi1993](https://github.com/hadisi1993)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/hansic99
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/lenovo-thinkpad-laptop-concentration-focus-windows-office.png?itok=-8E2ihcF (Woman using laptop concentrating)
|
||||
[2]: https://www.qt.io/product/development-tools
|
||||
[3]: https://opensource.com/sites/default/files/uploads/qt_creator_dark_mode.png ( QT Creator dark mode)
|
||||
[4]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[5]: https://opensource.com/sites/default/files/uploads/qt_creator_custom_stylesheet2.png (QT Creator custom stylesheet)
|
||||
[6]: https://doc.qt.io/qt-5/stylesheet-reference.html
|
||||
[7]: https://doc.qt.io/qtcreator/creator-cli.html
|
||||
[8]: https://doc.qt.io/qt-5/qapplication.html#QApplication
|
||||
[9]: https://doc.qt.io/qt-5/qguiapplication.html#supported-command-line-options
|
||||
[10]: https://opensource.com/sites/default/files/uploads/qt_creator_cross_compiling.png (QT Creator kits)
|
||||
[11]: https://opensource.com/sites/default/files/uploads/qt_creator_select_kits.png (Switching between Kits in Qt Creator)
|
||||
[12]: https://doc.qt.io/qtcreator/creator-targets.html
|
||||
[13]: https://doc.qt.io/qtcreator/creator-cpu-usage-analyzer.html
|
||||
[14]: https://doc.qt.io/qtcreator/creator-valgrind-overview.html
|
||||
[15]: https://doc.qt.io/qtcreator/creator-clang-tools.html
|
||||
[16]: https://opensource.com/sites/default/files/uploads/qt_creator_analyzer.png (Qt Creator analyzer)
|
||||
[17]: https://opensource.com/sites/default/files/uploads/qt_creator_debugger2.png (Qt Creator debugger)
|
||||
[18]: https://opensource.com/sites/default/files/uploads/qt_creator_fakevim_ex_commands.png (FakeVim in Qt Creator)
|
||||
[19]: https://opensource.com/sites/default/files/uploads/qt_creator_fakevim_build_commands.png (FakeVim in Qt Creator)
|
||||
[20]: https://doc.qt.io/qtcreator/creator-editor-fakevim.html
|
||||
[21]: https://opensource.com/sites/default/files/uploads/qtcreator_class_overview.png (List of classes in Qt Creator)
|
||||
[22]: https://opensource.com/sites/default/files/uploads/qtcreater_special_config.png (Special configuration in Qt Creator)
|
||||
[23]: https://doc.qt.io/qt-5/qmake-language.html
|
||||
[24]: https://doc.qt.io/qtcreator/
|
||||
@@ -0,0 +1,88 @@
|
||||
[#]: subject: "How to Enable Minimize, Maximize Window Buttons in elementary OS"
|
||||
[#]: via: "https://www.debugpoint.com/2021/08/enable-minimize-maximize-elementary/"
|
||||
[#]: author: "Arindam https://www.debugpoint.com/author/admin1/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
如何在 elementary OS 中启用最小化、最大化窗口按钮
|
||||
======
|
||||
这就是如何在 elementary OS 中启用最小化、最大化窗口按钮的方法。
|
||||
|
||||
许多人(大多数是 elementary OS 的新用户)在各种论坛上问这些问题:
|
||||
|
||||
1. 我怎样才能在 elementary OS 中启用最小化按钮?
|
||||
2. 我如何启用还原、最小化、最大化?
|
||||
3. 有可能恢复最小化和最大化按钮吗?
|
||||
|
||||
这些都是完全有效的问题,而且问问题也是可以的。对吗?这个指南可以帮助他们在 elementary OS 中获得这些按钮。
|
||||
|
||||
Elementary OS 所使用的 Pantheon 桌面并没有默认的标准窗口按钮。其原因主要是通过 Dock 和应用菜单处理用户行为和活动的不同概念。可以说,这种设计或实现的行为模仿了macOS。
|
||||
|
||||
也就是说,许多用户更喜欢窗口按钮,因为这是一个“肌肉记忆”的东西,有些人是从其他桌面环境迁移过来的,甚至是 Windows。
|
||||
|
||||
尽管 Elementary 没有为你提供这个默认设置,你仍然可以启用它。下面是方法。
|
||||
|
||||
### 启用最小化最大化按钮 - elementary OS
|
||||
|
||||
打开终端,安装添加 PPA 所需的 software-properties-common。默认情况下,这个包在 elementary OS 中没有安装(不要问我为什么,真的么?)
|
||||
|
||||
```
|
||||
sudo apt install software-properties-common
|
||||
```
|
||||
|
||||
#### elementary OS 6 Odin
|
||||
|
||||
Tweak 工具被重新命名,并正在单独开发。它被称为 [Pantheon Tweaks][1]。使用以下命令,你可以安装它。
|
||||
|
||||
```
|
||||
sudo add-apt-repository -y ppa:philip.scott/pantheon-tweaks
|
||||
sudo apt install -y pantheon-tweaks
|
||||
```
|
||||
|
||||
#### elementary OS 5 Juno 及更低版本
|
||||
|
||||
如果你使用的是 elementary OS 5 June 及更低版本,你可以使用相同的 PPA 安装早期的 [elementary-tweaks][2]。在终端按照以下命令进行操作。
|
||||
|
||||
```
|
||||
sudo add-apt-repository -y ppa:philip.scott/elementary-tweaks
|
||||
sudo apt install -y elementary-tweaks
|
||||
```
|
||||
|
||||
#### 更改设置
|
||||
|
||||
* 安装后,点击顶部栏的应用,打开系统设置。在系统设置窗口中,点击“个人”下的 Tweaks。
|
||||
* 在 Tweaks 窗口中,进入“外观”。
|
||||
* 在窗口控制下,选择布局:Windows。
|
||||
|
||||
![enable minimize maximize buttons elementary OS][3]
|
||||
|
||||
* 然后在顶部窗口栏的右侧应该有最小化、最大化和关闭按钮了。
|
||||
|
||||
也有其他组合,如Ubuntu、macOS等。你可以选择任何你觉得合适的:
|
||||
|
||||
![Other Options of Window buttons in elementary][4]
|
||||
|
||||
这一步就完成了指南。gsettings 中还有其他选项,你可以尝试使用,但窗口管理器 gala 最近删除了这些选项。因此,它们目前可能无法工作。
|
||||
|
||||
我希望这个指南能帮助你启用 elementary OS 的最小化最大化按钮。如果你需要任何帮助,请在下面的评论栏告诉我。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.debugpoint.com/2021/08/enable-minimize-maximize-elementary/
|
||||
|
||||
作者:[Arindam][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.debugpoint.com/author/admin1/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://github.com/pantheon-tweaks/pantheon-tweaks
|
||||
[2]: https://github.com/elementary-tweaks/elementary-tweaks
|
||||
[3]: https://www.debugpoint.com/wp-content/uploads/2021/08/enable-minimize-maximize-buttons-elementary-OS.png
|
||||
[4]: https://www.debugpoint.com/wp-content/uploads/2021/08/Other-Options-of-Window-buttons-in-elementary.jpg
|
||||
188
translated/tech/20220214 A guide to Kubernetes architecture.md
Normal file
188
translated/tech/20220214 A guide to Kubernetes architecture.md
Normal file
@@ -0,0 +1,188 @@
|
||||
[#]: subject: "A guide to Kubernetes architecture"
|
||||
[#]: via: "https://opensource.com/article/22/2/kubernetes-architecture"
|
||||
[#]: author: "Nived Velayudhan https://opensource.com/users/nivedv"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "MjSeven"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Kubernetes 架构指南
|
||||
======
|
||||
学习 Kubernetes 架构的不同组件是如何组合在一起的,这样你就可以更好地诊断问题、维护健康的集群和优化你的工作流。
|
||||
![部件、模块、软件容器][1]
|
||||
|
||||
使用 Kubernetes 来编排容器,这是一个简单的描述,但理解它的实际含义和你如何实现它完全是另外一回事。如果你正在运行或管理 Kubernetes 集群,那么你就会知道 Kubernetes 由一台称为 _控制平面_ 的计算机和许多其他 _工作节点_ 计算机组成。每一个都有一个复杂但健壮的堆栈,这使编排成为可能,熟悉每个组件有助于理解它是如何工作的。
|
||||
|
||||
![Kubernetes 架构图][2]
|
||||
|
||||
(Nived Velayudhan, [CC BY-SA 4.0][3])
|
||||
|
||||
### 控制平面组件
|
||||
|
||||
Kubernetes 安装在一个称为控制平面的机器上,它会运行 Kubernetes 守护进程,并在启动容器和吊舱时与之通信。下面介绍控制平面的各个组件。
|
||||
|
||||
#### Etcd
|
||||
|
||||
Etcd 是一种快速、分布式且一致的键值存储器,用作持久存储 Kubernetes 对象数据,如吊舱、Replication Controller、密钥和服务的后台存储。Etcd 是 Kubernetes 存储集群状态和元数据的唯一地方。唯一直接与 etcd 对话的组件是 Kubernetes API 服务器。所有的其他组件都通过 API 服务器间接的从 etcd 读写数据。
|
||||
|
||||
Etcd 还实现了一个监控功能,它提供了一个基于事件的接口,用于异步监控密钥的更改。一旦你更改了一个密钥,它的监控者就会收到通知。API 服务器组件严重依赖于此来获得通知,并将 etcd 移动到所需状态。
|
||||
|
||||
_为什么 etcd 实例的数量应该是奇数?_
|
||||
|
||||
你通常会在高可用(HA)环境中运行三个、五个或七个 etcd 实例,但这是为什么呢?因为 etcd 是分布式数据存储,可以水平扩展它,但你需要确保每个实例中的数据是一致的。为此,系统需要当前状态是什么达成共识,Etcd 为此使用 [RAFT 共识算法][4]。
|
||||
|
||||
RAFT 算法需要多数(或仲裁)集群才能进入下一个状态。如果你只有两个 etcd 实例并且他们其中一个失败的话,那么 etcd 集群无法转换到新的状态,因为不存在多数这个概念。如果你有三个 etcd 实例,一个实例可能会失败,但仍有 2 个实例可用于达到仲裁。
|
||||
|
||||
#### API 服务器
|
||||
|
||||
API 服务器是 Kubernetes 中唯一直接与 etcd 交互的组件。Kubernetes 中的其他所有组件都必须通过 API 服务器来处理集群状态,包括客户端(kubectl)。API 服务器具有以下功能:
|
||||
|
||||
* 提供在 etcd 中存储对象的一致方式。
|
||||
* 对对象执行验证,方便客户端无法存储配置不正确的对象(如果它们直接写入 etcd 数据存储,可能会发生这种情况)。
|
||||
* 提供 RESTful API 来创建、更新、修改或删除资源。
|
||||
* 提供[乐观并发锁][5],在发生更新时,其他客户端永远不会有机会重写对象。
|
||||
* 对客户端发送的请求进行身份验证和授权。它使用插件提取客户端的用户名、ID、所属组,并确定通过身份验证的用户是否可以对请求的资源执行请求的操作。
|
||||
* 如果请求试图创建、修改或删除资源,则负责[权限控制][6]。例如,AlwaysPullImages、DefaultStorageClass 和 ResourceQuota。
|
||||
* 实现了一种监控机制(类似于 etcd),用户客户端监控更改。这允许调度器和控制器管理器等组件以松耦合的方式与 API 服务器交互。
|
||||
|
||||
#### 控制器管理器
|
||||
|
||||
在 Kubernetes 中,控制器是监控集群状态的控制循环,然后根据需要进行或请求更改。每个控制器都尝试将当前集群状态移动到所需状态。控制器至少跟踪一种 Kubernetes 资源类型,这些对象都有一个字段来表示所需的状态。
|
||||
|
||||
控制器示例:
|
||||
|
||||
* Replication Manager(ReplicationController 资源的控制器)
|
||||
* 复本控制器、DaemonSet 和 Job 控制器
|
||||
* 部署控制器
|
||||
* StatefulSet 控制器
|
||||
* 节点控制器
|
||||
* 服务控制器
|
||||
* 端点控制器
|
||||
* 命名空间控制器
|
||||
* 持久卷控制器
|
||||
|
||||
|
||||
控制器使用监控机制来获得更改通知。它们监视 API 服务器对资源的更改,对每次更改执行操作,无论是新建对象还是更新或删除现有对象。大多数时候,这些操作包括创建其他资源或更新监控的资源本身。不过,由于使用监控并不能保证控制器不会错过任何事件,它们还会定期执行一系列操作,确保没有错过任何事件。
|
||||
|
||||
控制器管理器还执行生命周期功能。例如命名空间创建和生命周期、事件垃圾收集、终止吊舱垃圾收集、[级联删除垃圾收集][7]和节点垃圾收集。有关更多信息,参考[云控制器管理器][8]。
|
||||
|
||||
#### 调度器
|
||||
|
||||
调度器是一个将吊舱分配给节点的控制平面进程。它会监视新创建没有分配节点的吊舱。调度器会给每个发现的吊舱分配运行它的最佳节点。
|
||||
|
||||
满足吊舱调度要求的节点称为可行节点。如果没有合适的节点,那么吊舱会一直处于未调度状态,直到调度器可以放置它。一旦找到可行节点,它就会运行一组函数来对节点进行评分,并选择得分最高的节点,然后它会告诉 API 服务器所选节点的信息。这个过程称为绑定。
|
||||
|
||||
节点的选择分为两步:
|
||||
|
||||
1. 过滤所有节点的列表,获得可以调度吊舱的可接受节点列表(例如,PodFitsResources 过滤器检查候选节点是否有足够的可用资源来满足吊舱的特定资源请求)。
|
||||
|
||||
2. 对第一步得到的节点列表进行评分和排序,选择最佳节点。如果得分最高的有多个节点,循环过程可确保吊舱会均匀地部署在所有节点上。
|
||||
|
||||
调度决策要考虑的因素包括:
|
||||
|
||||
* 吊舱是否请求硬件/软件资源?节点是否报告内存或磁盘压力情况?
|
||||
|
||||
* 节点是否有与吊舱规范中的节点选择器匹配的标签?
|
||||
|
||||
* 如果吊舱请求绑定到特定地主机端口,该端口是否可用?
|
||||
|
||||
* 吊舱是否容忍节点的污点?
|
||||
|
||||
* 吊舱是否指定节点亲和性或反亲和性规则?
|
||||
|
||||
|
||||
调度器不会指示所选节点运行吊舱。调度器所做的就是通过 API 服务器更新吊舱定义。然后 API 服务器通过监控机制通知 kubelet 吊舱已被调度,然后目标节点上的 kubelet 服务看到吊舱被调度到它的节点,它创建并运行吊舱的容器。
|
||||
|
||||
**[ 下一篇: [Kubernetes 如何创建和运行容器: 图解指南][9] ]**
|
||||
|
||||
### 工作节点组件
|
||||
|
||||
工作节点运行 kubelet 代理,这允许控制平面招募它们来处理作业。与控制平面类似,工作节点使用几个不同的组件来实现这一点。 以下部分描述了工作节点组件。
|
||||
|
||||
#### Kubelet
|
||||
|
||||
Kubelet 是一个运行在集群中每个节点上的代理,负责在工作节点上运行的所有事情。它确保容器在吊舱中运行。
|
||||
|
||||
kubelet服务的主要功能有:
|
||||
|
||||
* 通过在 API 服务器中创建节点资源来注册它正在运行的节点。
|
||||
|
||||
* 持续监控 API 服务器上调度到节点的吊舱。
|
||||
|
||||
* 使用配置的容器运行时启动吊舱的容器。
|
||||
|
||||
* 持续监控正在运行的容器,并将其状态、事件和资源消耗报告给 API 服务器。
|
||||
|
||||
* 运行容器存活探测,在探测失败时重启容器,当 API 服务器中删除吊舱时终止(通知服务器吊舱终止的消息)。
|
||||
|
||||
#### 服务代理
|
||||
|
||||
服务代理(kube-proxy)在每个节点上运行,确保一个吊舱可以与另一个吊舱对话,一个节点可以与另一个节点对话,一个容器可以与另一个容器对话。它负责监视 API 服务器对服务和吊舱定义的更改,以保持整个网络配置是最新的。当一项服务得到多个吊舱的支持时,代理会在这些吊舱之间执行负载平衡。
|
||||
|
||||
kube-proxy 之所以叫代理,是因为它最初实际上是一个代理服务器,用于接受连接并将它们代理到吊舱。当前的实现是使用 iptables 规则将数据包重定向到随机选择的后端吊舱,而无需通过实际的代理服务器。
|
||||
|
||||
它工作原理的高级视图:
|
||||
|
||||
* 当你创建一个服务时,会立即分配一个虚拟 IP 地址。
|
||||
|
||||
* API 服务器会通知在工作节点上运行的 kube-proxy 代理有一个新服务。
|
||||
|
||||
* 每个 kube-proxy 通过设置 iptables 规则使服务可寻址,确保截获每个服务 IP/端口对,并将目的地址修改为支持服务的一个吊舱。
|
||||
|
||||
* 监控 API 服务器对服务或其端点对象的更改。
|
||||
|
||||
#### 容器运行时
|
||||
|
||||
容器运行时有两类:
|
||||
|
||||
* **较低级别的容器运行时:** 它们主要关注运行中的容器并为容器设置命名空间和 cgroup。
|
||||
|
||||
* **更高级别的容器运行时(容器引擎):**它们专注于格式、解包、管理、共享镜像以及为开发人员提供 API。
|
||||
|
||||
容器运行时负责:
|
||||
|
||||
* 如果容器镜像本地没有,则从镜像仓库中提取。
|
||||
|
||||
* 将镜像解压到写时复制文件系统,所有容器层叠加创建一个合并的文件系统。
|
||||
|
||||
* 准备一个容器挂载点。
|
||||
|
||||
* 设置容器镜像的元数据,如覆盖命令、用户输入的入口命令,并设置 SECCOMP 规则,确保容器按预期运行。
|
||||
|
||||
* 提醒内核将进程、网络和文件系统等隔离分配给容器。
|
||||
|
||||
* 提醒内核分配一些资源限制,如 CPU 或内存限制。
|
||||
|
||||
* 将系统调用(syscall)传递给内核启动容器。
|
||||
|
||||
* 确保 SElinux/AppArmor 设置正确。
|
||||
|
||||
|
||||
### 协同
|
||||
|
||||
系统级组件协同工作,确保 Kubernetes 集群的每个部分都能实现其目和执行其功能。当你深入编辑 [YAML 文件][10]时,有时很难理解请求是如何在集群中通信的。现在你已经了解了各个部分是如何组合在一起的,你可以更好地理解 Kubernetes 内部发生了什么,这有助于诊断问题、维护健康的集群并优化你的工作流。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/22/2/kubernetes-architecture
|
||||
|
||||
作者:[Nived Velayudhan][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/nivedv
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/containers_modules_networking_hardware_parts.png?itok=rPpVj92- (Parts, modules, containers for software)
|
||||
[2]: https://opensource.com/sites/default/files/uploads/kubernetes-architecture-diagram.png (Kubernetes architecture diagram)
|
||||
[3]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[4]: https://www.geeksforgeeks.org/raft-consensus-algorithm/
|
||||
[5]: https://stackoverflow.com/questions/52910322/kubernetes-resource-versioning#:~:text=Optimistic%20concurrency%20control%20(sometimes%20referred,updated%2C%20the%20version%20number%20increases.
|
||||
[6]: https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/
|
||||
[7]: https://kubernetes.io/docs/concepts/architecture/garbage-collection/
|
||||
[8]: https://kubernetes.io/docs/concepts/architecture/cloud-controller/
|
||||
[9]: https://www.redhat.com/architect/how-kubernetes-creates-runs-containers
|
||||
[10]: https://www.redhat.com/sysadmin/yaml-beginners
|
||||
@@ -0,0 +1,143 @@
|
||||
[#]: subject: "Manage your Rust toolchain using rustup"
|
||||
[#]: via: "https://opensource.com/article/22/6/rust-toolchain-rustup"
|
||||
[#]: author: "Gaurav Kamathe https://opensource.com/users/gkamathe"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
使用 rustup 管理你的 Rust 工具链
|
||||
======
|
||||
Rustup 可用于安装 Rust 并保持更新。它还允许你在稳定版、测试版和每日 Rust 编译器和工具之间无缝切换。
|
||||
|
||||
![Tools illustration][1]
|
||||
|
||||
图片来源:Opensource.com
|
||||
|
||||
[Rust 编程语言][2] 如今变得越来越流行,受到爱好者和公司的一致好评。它受欢迎的原因之一是 Rust 提供的令人惊叹的工具使其成为开发人员使用的乐趣。 [Rustup][3] 是用于管理 Rust 工具的官方工具。它不仅可以用于安装 Rust 并保持更新,它还允许你在稳定、测试和每日 Rust 编译器和工具之间无缝切换。本文将向你介绍 rustup 和一些常用命令。
|
||||
|
||||
### 默认 Rust 安装方式
|
||||
|
||||
如果你想在 Linux 上安装 Rust,你可以使用你的包管理器。在 Fedora 或 CentOS Stream 上,你可以这样使用它,例如:
|
||||
|
||||
```
|
||||
$ sudo dnf install rust cargo
|
||||
```
|
||||
|
||||
这提供了一个稳定版本的 Rust 工具链,如果你是 Rust 的初学者并想尝试编译和运行简单的程序,它会非常有用。但是,由于 Rust 是一种新的编程语言,它变化很快,并且经常添加许多新功能。这些功能是 Rust 工具链的每日和之后测试版的一部分。要试用这些功能,你需要安装这些较新版本的工具链,而不会影响系统上的稳定版本。不幸的是,你的发行版的包管理器在这里无法为你提供帮助。
|
||||
|
||||
### 使用 rustup 安装 Rust 工具链
|
||||
|
||||
要解决上述问题,你可以下载安装脚本:
|
||||
|
||||
```
|
||||
$ curl --proto '=https' --tlsv1.2 \
|
||||
-sSf https://sh.rustup.rs > sh.rustup.rs
|
||||
```
|
||||
|
||||
检查它,然后运行它。它不需要 root 权限,并根据你的本地用户权限安装 Rust:
|
||||
|
||||
```
|
||||
$ file sh.rustup.rs
|
||||
sh.rustup.rs: POSIX shell script, ASCII text executable
|
||||
$ less sh.rustup.rs
|
||||
$ bash sh.rustup.rs
|
||||
```
|
||||
|
||||
出现提示时选择选项 1:
|
||||
|
||||
```
|
||||
1) Proceed with installation (default)
|
||||
2) Customize installation
|
||||
3) Cancel installation
|
||||
> 1
|
||||
```
|
||||
|
||||
安装后,你必须获取环境变量以确保 `rustup` 命令立即可供你使用:
|
||||
|
||||
```
|
||||
$ source $HOME/.cargo/env
|
||||
```
|
||||
|
||||
验证是否安装了 Rust 编译器 (rustc) 和 Rust 包管理器 (cargo):
|
||||
|
||||
```
|
||||
$ rustc --version
|
||||
$ cargo --version
|
||||
```
|
||||
|
||||
### 查看已安装和活动的工具链
|
||||
|
||||
你可以使用以下命令查看已安装的不同工具链以及哪个工具链是活动的:
|
||||
|
||||
```
|
||||
$ rustup show
|
||||
```
|
||||
|
||||
### 在工具链之间切换
|
||||
|
||||
你可以查看默认工具链并根据需要进行更改。如果你当前使用的是稳定的工具链,并希望尝试每日版本中提供的新功能,你可以轻松切换到每日工具链:
|
||||
|
||||
```
|
||||
$ rustup default
|
||||
$ rustup default nightly
|
||||
```
|
||||
|
||||
要查看 Rust 的编译器和包管理器的确切路径:
|
||||
|
||||
```
|
||||
$ rustup which rustc
|
||||
$ rustup which cargo
|
||||
```
|
||||
|
||||
### 检查和更新工具链
|
||||
|
||||
要检查是否有新的 Rust 工具链可用:
|
||||
|
||||
```
|
||||
$ rustup check
|
||||
```
|
||||
|
||||
假设一个新版本的 Rust 发布了,其中包含一些有趣的特性,并且你想要获取最新版本的 Rust。你可以使用 `update` 子命令来做到这一点:
|
||||
|
||||
```
|
||||
$ rustup update
|
||||
```
|
||||
|
||||
### 帮助和文档
|
||||
|
||||
以上命令对于日常使用来说绰绰有余。尽管如此,rustup 有多种命令,你可以参考帮助部分了解更多详细信息:
|
||||
|
||||
```
|
||||
$ rustup --help
|
||||
```
|
||||
|
||||
Rustup 在 GitHub 上有完整的[说明书][4],你可以将其用作参考。所有 Rust 文档都安装在你的本地系统上,不需要你连接到 Internet。你可以访问包括书籍、标准库等在内的本地文档:
|
||||
|
||||
```
|
||||
$ rustup doc
|
||||
$ rustup doc --book
|
||||
$ rustup doc --std
|
||||
$ rustup doc --cargo
|
||||
```
|
||||
|
||||
Rust 是一种正在积极开发中的令人兴奋的语言。如果你对编程的发展方向感兴趣,请关注 Rust!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/22/6/rust-toolchain-rustup
|
||||
|
||||
作者:[Gaurav Kamathe][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/gkamathe
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/tools_hardware_purple.png
|
||||
[2]: https://www.rust-lang.org/
|
||||
[3]: https://github.com/rust-lang/rustup
|
||||
[4]: https://rust-lang.github.io/rustup/
|
||||
Reference in New Issue
Block a user