mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-02-03 23:40:14 +08:00
Merge branch 'master' of https://github.com/LCTT/TranslateProject into translating
This commit is contained in:
commit
410ac80be6
@ -1,51 +1,47 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Donkey)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: translator: (Donkey-Hao)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-14773-1.html)
|
||||
[#]: 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 篇文章之类的事情。
|
||||
![](https://img.linux.net.cn/data/attachment/album/202206/29/145852zcqqw24v2svulswl.jpg)
|
||||
|
||||
本周开始,我先回顾我的日程安排,看看我需要或想要完成的事情。通常,列表上有些较大的项目。无论来自工作上的问题,还是一系列关于生产力的文章,或者改进我家的鸡舍,当作为一项工作时,这个任务真的很艰巨。很有可能我无法坐下来,在一个时间段内,甚至在一天内完成类似(请注意,只是举例)21 篇文章之类的事情。
|
||||
|
||||
![21 Days of Productivity project screenshot][2]
|
||||
|
||||
21 天的生产力 (Kevin Sonney, [CC BY-SA 4.0][3])
|
||||
|
||||
所以当我的清单上有这样的东西时,我做的第一件事就是把它分解成更小的部分。如著名的诺贝尔文学奖得主 [William Faulkner][4] 说的“移山的人,从小石头开始。”(译注:感觉与“千里之行,始于足下”是一个意思) 我们要解决大任务(山)并且需要完成各个步骤(小石头)。
|
||||
*21 天的生产力 (Kevin Sonney, [CC BY-SA 4.0][3])*
|
||||
|
||||
所以当我的清单上有这样的东西时,我做的第一件事就是把它分解成更小的部分。如著名的诺贝尔文学奖得主 [William Faulkner][4] 说的“移山的人,从小石头开始。”(LCTT 译注:感觉与“千里之行,始于足下”是一个意思) 我们要解决大任务(山)并且需要完成各个步骤(小石头)。
|
||||
|
||||
我使用下面的步骤将大任务分割为小步骤:
|
||||
|
||||
1. 我通常很清楚完成一项任务需要做什么。 如果没有,我会做一些研究来弄清楚这一点。
|
||||
1. 我通常很清楚完成一项任务需要做什么。如果没有,我会做一些研究来弄清楚这一点。
|
||||
2. 我会顺序的写下完成的步骤。
|
||||
3. 最后,我坐下来拿着我的日历和清单,开始将任务分散到几天(或几周或几个月),以了解我何时可以完成它。
|
||||
|
||||
现在我不仅有计划,还知道多久能完成。逐步完成,我可以看到这项大任务不仅变得更小,而且更接近完成。
|
||||
|
||||
现在我不仅有计划还知道多久能完成。逐步完成,我可以看到这项大任务不仅变得更小,而且更接近完成。
|
||||
|
||||
军队有句古话,“遇敌无计”。 几乎可以肯定的是,有一两点(或五点)我意识到像“截屏”这样简单的事情需要扩展到更复杂的事情。 事实上,在 [Easy!Appointments][5] 的截图中,竟然是:
|
||||
军队有句古话,“遇敌无计”。 几乎可以肯定的是,有一两点(或五点)我意识到像“截屏”这样简单的事情需要扩展到更复杂的事情。事实上,在 [Easy!Appointments][5] 的截图中,竟然是:
|
||||
|
||||
1. 安装和配置 Easy!Appointments
|
||||
2. 安装和配置 Easy!Appointments WordPress 插件
|
||||
3. 生成 API 密钥来同步日历
|
||||
4. 截屏
|
||||
|
||||
|
||||
|
||||
即便如此,我也不得不将这些任务分解成更小的部分——下载软件、配置 NGINX、验证安装……你明白了。 没关系。 一个计划或一组任务不是一成不变的,可以根据需要进行更改。
|
||||
即便如此,我也不得不将这些任务分解成更小的部分——下载软件、配置 NGINX、验证安装……你明白了吧。没关系。一个计划或一组任务不是一成不变的,可以根据需要进行更改。
|
||||
|
||||
![project completion pie chart][6]
|
||||
|
||||
今年的计划已经完成了 2/3 ! (Kevin Sonney, [CC BY-SA 4.0][3])
|
||||
*今年的计划已经完成了 2/3 ! (Kevin Sonney, [CC BY-SA 4.0][3])*
|
||||
|
||||
这是一项后天习得的技能,最初几次需要一些努力。学习如何将大任务分解成更小的步骤可以让您跟踪实现目标或完成大任务的进度,而不会在过程中不知所措。
|
||||
|
||||
@ -56,7 +52,7 @@ 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)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -3,42 +3,44 @@
|
||||
[#]: author: "Krishna Mohan Koyya https://www.opensourceforu.com/author/krishna-mohan-koyya/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "lkxed"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-14772-1.html"
|
||||
|
||||
Apache Kafka:为“无缝系统”提供异步消息支持
|
||||
======
|
||||
Apache Kafka 是最流行的开源消息代理之一。它已经成为了大数据操作的重要组成部分,你能够在几乎所有的微服务环境中找到它。本文对 Apache Kafka 进行了简要介绍,并提供了一个案例来展示它的使用方式。
|
||||
|
||||
![][1]
|
||||
> Apache Kafka 是最流行的开源消息代理之一。它已经成为了大数据操作的重要组成部分,你能够在几乎所有的微服务环境中找到它。本文对 Apache Kafka 进行了简要介绍,并提供了一个案例来展示它的使用方式。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202206/29/094326fbo6zzsrxiava661.jpg)
|
||||
|
||||
你有没有想过,电子商务平台是如何在处理巨大的流量时,做到不会卡顿的呢?有没有想过,OTT 平台是如何在同时向数百万用户交付内容时,做到平稳运行的呢?其实,关键就在于它们的分布式架构。
|
||||
|
||||
采用分布式架构设计的系统由多个功能组件组成。这些功能组件通常分布在许多个机器上,它们通过网络,异步地交换消息,从而实现相互协作。正是由于异步消息的存在,组件之间才能实现可伸缩、无阻塞的通信,整个系统才能够平稳运行。
|
||||
采用分布式架构设计的系统由多个功能组件组成。这些功能组件通常分布在多个机器上,它们通过网络,异步地交换消息,从而实现相互协作。正是由于异步消息的存在,组件之间才能实现可伸缩、无阻塞的通信,整个系统才能够平稳运行。
|
||||
|
||||
### 异步消息
|
||||
|
||||
异步消息的常见特性有:
|
||||
|
||||
* 消息的生产者和消费者都不知道彼此的存在。它们在不知道其他对象的情况下,加入和离开系统。
|
||||
* 消息代理充当了生产者和消费者之间的中介。
|
||||
* 生产者把每条消息,都与一个<ruby>“主题”<rt>topic</rt></ruby>相关联。每个主题只是一个简单的字符串。
|
||||
* 一个生产者可以把消息发往多个主题,不同生产者也可以把消息发送给同一主题。
|
||||
* 消息的<ruby>生产者<rt>producer</rt></ruby>和<ruby>消费者<rt>consumer</rt></ruby>都不知道彼此的存在。它们在不知道对方的情况下,加入和离开系统。
|
||||
* 消息<ruby>代理<rt>broker</rt></ruby>充当了生产者和消费者之间的中介。
|
||||
* 生产者把每条消息,都与一个“<ruby>主题<rt>topic</rt></ruby>”相关联。主题是一个简单的字符串。
|
||||
* 生产者可以在多个主题上发送消息,不同的生产者也可以在同一主题上发送消息。
|
||||
* 消费者向代理订阅一个或多个主题的消息。
|
||||
* 生产者只将消息发送给代理,而不发送给消费者。
|
||||
* 代理会把消息发送给订阅该主题的所有消费者。
|
||||
* 代理将消息传递给针对该主题注册的所有消费者。
|
||||
* 生产者并不期望得到消费者的任何回应。换句话说,生产者和消费者不会相互阻塞。
|
||||
|
||||
市场上的消息代理有很多,而 Apache Kafka 是其中最受欢迎的一种(之一)。
|
||||
市场上的消息代理有很多,而 Apache Kafka 是其中最受欢迎的之一。
|
||||
|
||||
### Apache Kafka
|
||||
|
||||
Apache Kafka 是一个支持流处理的、开源的分布式消息系统,它由 Apache 软件基金会开发。在架构上,它是多个代理组成的集群,这些代理间通过 Apache ZooKeeper 服务来协调。在接收、持久化和发送消息时,这些代理共享集群上的负载。
|
||||
Apache Kafka 是一个支持流式处理的、开源的分布式消息系统,它由 Apache 软件基金会开发。在架构上,它是多个代理组成的集群,这些代理间通过 Apache ZooKeeper 服务来协调。在接收、持久化和发送消息时,这些代理分担集群上的负载。
|
||||
|
||||
#### 分区
|
||||
|
||||
Kafka 将消息写入称为<ruby>“分区”<rt>partitions</rt></ruby>的桶中。一个特定分区只保存一个主题上的消息。例如,Kafka 会把 `heartbeats` 主题上的消息写入名为 “heartbeats-0” 的分区(假设它是个单分区主题),这个过程和生产者无关。
|
||||
Kafka 将消息写入称为“<ruby>分区<rt>partition</rt></ruby>”的桶中。一个特定分区只保存一个主题上的消息。例如,Kafka 会把 `heartbeats` 主题上的消息写入名为 `heartbeats-0` 的分区(假设它是个单分区主题),这个过程和生产者无关。
|
||||
|
||||
![图 1:异步消息][2]
|
||||
|
||||
@ -50,21 +52,21 @@ Kafka 将消息写入称为<ruby>“分区”<rt>partitions</rt></ruby>的桶中
|
||||
|
||||
#### 领导者和同步副本
|
||||
|
||||
Kafka 在(由多个代理组成的)集群中维护了多个分区。其中,负责维护分区的那个代理被称为<ruby>“领导者”<rt>leader</rt></ruby>。只有领导者能够在它的分区上接收和发送消息。
|
||||
Kafka 在(由多个代理组成的)集群中维护了多个分区。其中,负责维护分区的那个代理被称为“<ruby>领导者<rt>leader</rt></ruby>”。只有领导者能够在它的分区上接收和发送消息。
|
||||
|
||||
可是,万一分区的领导者发生故障了,又该怎么办呢?为了确保业务连续性,每个领导者(代理)都会把它的分区复制到其他代理上。此时,这些其他代理就称为该分区的<ruby>同步副本<rt>in-sync-replicas</rt></ruby>(ISR)。一旦分区的领导者发生故障,ZooKeeper 就会发起一次选举,把选中的那个同步副本任命为新的领导者。此后,这个新的领导者将承担该分区的消息接受和发送任务。管理员可以指定分区需要维护的同步副本的大小。
|
||||
|
||||
![图 3:命令行生产者][4]
|
||||
![图 3:生产者命令行工具][4]
|
||||
|
||||
#### 消息持久化
|
||||
|
||||
代理会将每个分区都映射到一个指定的磁盘文件,从而实现持久化。默认情况下,消息会在磁盘上保留一个星期。当消息写入分区后,它们的内容和顺序就不能更改了。管理员可以配置一些策略,如消息的保留时长、压缩算法等。
|
||||
|
||||
![图 4:命令行消费者][5]
|
||||
![图 4:消费者命令行工具][5]
|
||||
|
||||
#### 消费消息
|
||||
|
||||
与大多数其他消息系统不同,Kafka 不会主动将消息发送给消费者。相反,消费者应该监听主题,并主动读取消息。一个消费者可以某个主题的多个分区中读取消息。多个消费者也可以读取来自同一个分区的消息。Kafka 保证了同一条消息不会被同一个消费者重复读取。
|
||||
与大多数其他消息系统不同,Kafka 不会主动将消息发送给消费者。相反,消费者应该监听主题,并主动读取消息。一个消费者可以从某个主题的多个分区中读取消息。多个消费者也可以读取来自同一个分区的消息。Kafka 保证了同一条消息不会被同一个消费者重复读取。
|
||||
|
||||
Kafka 中的每个消费者都有一个组 ID。那些组 ID 相同的消费者们共同组成了一个消费者组。通常,为了从 N 个主题分区读取消息,管理员会创建一个包含 N 个消费者的消费者组。这样一来,组内的每个消费者都可以从它的指定分区中读取消息。如果组内的消费者比可用分区还要多,那么多出来的消费者就会处于闲置状态。
|
||||
|
||||
@ -116,9 +118,9 @@ listeners=PLAINTEXT://:9092
|
||||
|
||||
上述命令还同时指定了<ruby>复制因子<rt>replication factor</rt></ruby>,它的值不能大于集群中代理的数量。我们使用的是单代理集群,因此,复制因子只能设置为 1。
|
||||
|
||||
当主题创建完成后,生产者和消费者就可以在上面交换消息了。Kafka 的发行版内附带了命令行工具生产者和消费者,供测试时用。
|
||||
当主题创建完成后,生产者和消费者就可以在上面交换消息了。Kafka 的发行版内附带了生产者和消费者的命令行工具,供测试时用。
|
||||
|
||||
打开第三个终端,运行下面的命令,启动命令行生产者:
|
||||
打开第三个终端,运行下面的命令,启动生产者:
|
||||
|
||||
```
|
||||
./bin/kafka-console-producer.sh --broker-list localhost:9092 --topic topic-1
|
||||
@ -126,7 +128,7 @@ listeners=PLAINTEXT://:9092
|
||||
|
||||
上述命令显示了一个提示符,我们可以在后面输入简单文本消息。由于我们指定的命令选项,生产者会把 `topic-1` 上的消息,发送到运行在本机的 9092 端口的 Kafka 中。
|
||||
|
||||
打开第四个终端,运行下面的命令,启动命令行消费者:
|
||||
打开第四个终端,运行下面的命令,启动消费者:
|
||||
|
||||
```
|
||||
./bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic topic-1 –-from-beginning
|
||||
@ -146,7 +148,7 @@ listeners=PLAINTEXT://:9092
|
||||
|
||||
![图 5:基于 Kafka 的架构][6]
|
||||
|
||||
在这种架构下,客车上的设备扮演了消息生产者的角色。它们会周期性地把当前位置发送到 Kafka 的 `abc-bus-location` 主题上。ABC 公司选择以客车的<ruby>行程码<rt>trip code</rt></ruby>作为消息键,以处理来自不同客车的消息。例如,对于从 Bengaluru 到 Hubballi 的客车,它的行程码就会是 `BLRHL003`,那么在这段旅程中,对于所有来自该客车的消息,它们的消息键都会是 `BLRHL003`。
|
||||
在这种架构下,客车上的设备扮演了消息生产者的角色。它们会周期性地把当前位置发送到 Kafka 的 `abc-bus-location` 主题上。ABC 公司选择以客车的<ruby>行程编号<rt>trip code</rt></ruby>作为消息键,以处理来自不同客车的消息。例如,对于从 Bengaluru 到 Hubballi 的客车,它的行程编号就会是 `BLRHL003`,那么在这段旅程中,对于所有来自该客车的消息,它们的消息键都会是 `BLRHL003`。
|
||||
|
||||
仪表盘应用扮演了消息消费者的角色。它在代理上注册了同一个主题 `abc-bus-location`。如此,这个主题就成为了生产者(客车)和消费者(仪表盘)之间的虚拟通道。
|
||||
|
||||
@ -166,7 +168,7 @@ listeners=PLAINTEXT://:9092
|
||||
|
||||
##### Java 生产者
|
||||
|
||||
下面的 `Fleet` 类模拟了在 ABC 公司的 6 辆客车上运行的 Kafka 生产者应用。它会把位置更新发送到指定代理的 `abc-bus-location` 主题上。请注意,简单起见,主题名称、消息键、消息内容和代理地址等,都在代码里写死了。
|
||||
下面的 `Fleet` 类模拟了在 ABC 公司的 6 辆客车上运行的 Kafka 生产者应用。它会把位置更新发送到指定代理的 `abc-bus-location` 主题上。请注意,简单起见,主题名称、消息键、消息内容和代理地址等,都在代码里硬编码的。
|
||||
|
||||
```
|
||||
public class Fleet {
|
||||
@ -205,7 +207,7 @@ public class Fleet {
|
||||
|
||||
##### Java 消费者
|
||||
|
||||
下面的 `Dashboard` 类实现了一个 Kafka 消费者应用,运行在 ABC 公司的操作中心。它会监听 `abc-bus-location` 主题,并且它的消费者组 ID 是 `abc-dashboard`。当收到消息后,它会立即显示来自客车的详细位置信息。我们本该配置这些详细位置信息,但简单起见,它们也是在代码里写死的:
|
||||
下面的 `Dashboard` 类实现了一个 Kafka 消费者应用,运行在 ABC 公司的操作中心。它会监听 `abc-bus-location` 主题,并且它的消费者组 ID 是 `abc-dashboard`。当收到消息后,它会立即显示来自客车的详细位置信息。我们本该配置这些详细位置信息,但简单起见,它们也是在代码里硬编码的:
|
||||
|
||||
```
|
||||
public static void main(String[] args) {
|
||||
@ -241,7 +243,7 @@ public static void main(String[] args) {
|
||||
|
||||
##### 依赖
|
||||
|
||||
为了编译和运行这些代码,我们需要 JDK 8 及以上版本。看到下面的 `pom.xml` 文件中的 Maven 依赖了吗?它们会把所需的 Kafka 客户端库,下载并添加到类路径中:
|
||||
为了编译和运行这些代码,我们需要 JDK 8 及以上版本。看到下面的 `pom.xml` 文件中的 Maven 依赖了吗?它们会把所需的 Kafka 客户端库下载并添加到类路径中:
|
||||
|
||||
```
|
||||
<dependency>
|
||||
@ -283,7 +285,7 @@ via: https://www.opensourceforu.com/2021/11/apache-kafka-asynchronous-messaging-
|
||||
作者:[Krishna Mohan Koyya][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,29 +3,30 @@
|
||||
[#]: author: "John Paul https://itsfoss.com/author/john/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-14774-1.html"
|
||||
|
||||
Minetest,一个开源的 Minecraft 替代品
|
||||
Minetest:一个开源的 Minecraft 替代品
|
||||
======
|
||||
早在 2009 年,Minecraft 就被介绍给了世界。从那时起,它已经成为一种文化现象。在这段时间里,一些开发者发布了具有类似想法和机制的开源游戏。今天,我们将看看其中最大的一个:Minetest。
|
||||
|
||||
早在 2009 年,Minecraft 就来到了这个世界。从那时起,它已经成为一种文化现象。在这段时间里,一些开发者发布了具有类似想法和机制的开源游戏。今天,我们将看看其中最大的一个:Minetest。
|
||||
|
||||
### 什么是 Minetest?
|
||||
|
||||
![minetest start][1]
|
||||
![](https://img.linux.net.cn/data/attachment/album/202206/29/151524eem52oyatm2tz2dr.jpg)
|
||||
|
||||
[Minetest][2],简单地说,是一个基于体素的沙盒游戏,与 Minecraft 非常相似。与 Minecraft 不同的是,Minetest 是用 C++ 编写的,并被设计成可以在大多数系统上原生运行。它也有一个非常大的地图区域。地图大小为 “62,000 × 62,000 × 62,000 块”,“你可以向下开采 31,000 块,或向上建造 31,000 块”。
|
||||
[Minetest][2],简单地说,是一个基于<ruby>体素<rt>voxel</rt></ruby>的沙盒游戏,与 Minecraft 非常相似。与 Minecraft 不同的是,Minetest 是用 C++ 编写的,并被设计成可以在大多数系统上原生运行。它也有一个非常大的地图区域。地图大小为 “62,000 × 62,000 × 62,000 块”,“你可以向下开采 31,000 块,或向上建造 31,000 块”。
|
||||
|
||||
有趣的是,Minetest 最初是以专有许可证发布的,但后来被重新授权为 GPL。此后,它又被重新授权为 LGPL。
|
||||
|
||||
Minetest 有几种模式。你可以建造并发挥创意,或者你可以尝试在各种元素中生存。你并不局限于这些模式。Minetest 有大量的[可用的额外内容][3],包括 mods、纹理包和在 Minetest 中建立的游戏。这主要是通过 Minetest 的 [modding API][4] 和 Lua 完成的。
|
||||
Minetest 有几种模式。你可以建造并发挥创意,或者你可以尝试在各种元素中生存。你并不局限于这些模式。Minetest 有大量的 [额外内容][3],包括 <ruby>模组<rt>mod</rt></ruby>、纹理包和在 Minetest 中建立的游戏。这主要是通过 Minetest 的 [模组 API][4] 和 Lua 完成的。
|
||||
|
||||
![minetest packages][5]
|
||||
|
||||
对于那些玩过 Minecraft 的人来说,你会发现 Minetest 中的体验非常相似。你可以挖掘资源,建造结构,并结合材料来制作工具。我在 Minetest 中没有注意到的一件事是怪物。我认为 Minetest 中没有任何生物,但话说回来,我只在创意模式中玩过。我还没有玩过生存模式。
|
||||
|
||||
Minetest 也被用于[教育][6]。例如,瑞士 CERN 的人用 Minetest 创造了一个游戏,以[展示互联网是如何工作的][7]以及它是如何被创造出来的。Minetest 还被[用于教授][8]编程、地球科学以及微积分和三角学。
|
||||
Minetest 也被用于 [教育][6]。例如,瑞士 CERN 的人用 Minetest 创造了一个游戏,以 [展示互联网是如何工作的][7] 以及它是如何被创造出来的。Minetest 还被用于 [教授][8] 编程、地球科学以及微积分和三角学。
|
||||
|
||||
![minetes map1][9]
|
||||
|
||||
@ -73,8 +74,6 @@ FreeBSD 用户很幸运。他们可以用这个命令安装 Mintest:
|
||||
pkg install minetest minetest_game
|
||||
```
|
||||
|
||||
![minetest map2][10]
|
||||
|
||||
#### Snap
|
||||
|
||||
要安装 Minetest 的 Snap 包,请在终端输入以下命令:
|
||||
@ -91,13 +90,13 @@ sudo snap install minetest
|
||||
flatpak install flathub net.minetest.Minetest
|
||||
```
|
||||
|
||||
你可以在[这里][11]下载 Windows 的可移植执行文件。你也可以在 Android 上安装 Minetest,可以通过 [Google Play][12] 或[下载 APK][13]。
|
||||
你可以在 [这里][11] 下载 Windows 的可移植执行文件。你也可以在 Android 上安装 Minetest,可以通过 [Google Play][12] 或 [下载 APK][13]。
|
||||
|
||||
### 最后的想法
|
||||
### 总结
|
||||
|
||||
![minetest about][14]
|
||||
|
||||
我已经在 Minetest 中花了几个小时在我的本地系统上进行构建和探索。它非常有趣。我还没来得及尝试任何额外的内容,因为我对我玩过的相对较少的游戏部分非常满意。我遇到的唯一麻烦是,由于某种原因,它在 Fedora 上运行缓慢。我可能有一些配置上的错误。
|
||||
我已经在 Minetest 中花了几个小时在我的本地系统上进行构建和探索。它非常有趣。我还没来得及尝试任何额外的内容,因为我对我玩过的相对较少的游戏部分非常满意。我遇到的唯一麻烦是,由于某种原因,它在 Fedora 上运行缓慢。我可能存在一些配置上的错误。
|
||||
|
||||
如果你曾经认为 Minecraft 看起来很有趣,但不想花钱,那就去看看 Minetest。你会很高兴你这么做。
|
||||
|
||||
@ -110,7 +109,7 @@ via: https://itsfoss.com/minetest/
|
||||
作者:[John Paul][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,102 @@
|
||||
[#]: subject: "Thunderbird 102 Releases with Matrix Support and New Address Book"
|
||||
[#]: via: "https://news.itsfoss.com/thunderbird-102-release/"
|
||||
[#]: author: "Ankush Das https://news.itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Thunderbird 102 Releases with Matrix Support and New Address Book
|
||||
======
|
||||
Thunderbird 102 steps up a notch in terms of user experience, and customization features.
|
||||
|
||||
![thunderbird 102][1]
|
||||
|
||||
We have already talked about the [features coming to Thunderbird 102][2]. And, if you have read that, it is time to experience those exciting features!
|
||||
|
||||
Yes, Thunderbird 102 is now available to download (right around the time of the [Mozilla Firefox 102][3] release).
|
||||
|
||||
### Thunderbird 102: What’s New?
|
||||
|
||||
Thunderbird 102 comes packed with refreshed icons, color folders, and several meaningful upgrades.
|
||||
|
||||
![thunderbird 102][4]
|
||||
|
||||
**Ryan Lee Sipes**, Thunderbird Product Manager mentions:
|
||||
|
||||
“With features like timezone tracking and relationship management, our new address book allows you to better keep track of all the important people in your life.”
|
||||
|
||||
If you are hearing about the update for the first time, let us look at the key highlights of this release.
|
||||
|
||||
#### Brand New Address Book
|
||||
|
||||
![thunderbird 102][5]
|
||||
|
||||
Thunderbird 102 takes a good step towards a modern user experience with a much-needed makeover to its address book.
|
||||
|
||||
You get all the important information at a glance while being compatible with the vCard format.
|
||||
|
||||
#### Central Spaces Toolbar
|
||||
|
||||
![][6]
|
||||
|
||||
A new toolbar to make things more convenient! You can enable the toolbar to get access to the address book, calendar, tasks, chat, and any other add-ons.
|
||||
|
||||
You can customize the toolbar’s look (sidebar) as per your preferences.
|
||||
|
||||
#### New Import/Export Wizard
|
||||
|
||||
![][7]
|
||||
|
||||
Import/Export in Thunderbird required making use of an add-on. While it worked, it wasn’t an out-of-the-box solution.
|
||||
|
||||
Now, with Thunderbird 102, you get this feature built-in. The step-by-step wizard should help users import/export essential data quickly.
|
||||
|
||||
It also ensures you do not duplicate the data with an import for your user profile.
|
||||
|
||||
#### Matrix Support
|
||||
|
||||
It looks like adding support for the Matrix protocol, and enabling decentralized communication is the trend now!
|
||||
|
||||
[Rocket.Chat also added support][8] for it, if you did not know.
|
||||
|
||||
With Thunderbird 102, the chat feature uses Matrix to provide you with a secure messaging experience.
|
||||
|
||||
#### Redesigned Message Header
|
||||
|
||||
The message header usually makes navigation easier when reading a message before responding to it.
|
||||
|
||||
With the new update, you can customize what to highlight, and you also get to hide the labels column if you need. Also, you can “star” an important message and convert them into a calendar event or task, pretty neat!
|
||||
|
||||
In addition to these changes, there are many other refinements that you can explore in the [release notes][9].
|
||||
|
||||
### Download Thunderbird 102
|
||||
|
||||
You can download the latest Thunderbird 102 update from the [official website][10]. Or, you can wait for the update to arrive through your package manager.
|
||||
|
||||
*Have you tried Thunderbird 102 yet? What do you think about it?*
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/thunderbird-102-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/thunderbird-102-release.jpg
|
||||
[2]: https://news.itsfoss.com/thunderbird-102-features/
|
||||
[3]: https://news.itsfoss.com/firefox-102-release/
|
||||
[4]: https://news.itsfoss.com/wp-content/uploads/2022/06/TB-102-icons-and-folders.png
|
||||
[5]: https://news.itsfoss.com/wp-content/uploads/2022/06/thunderbird-102-address-book.png
|
||||
[6]: https://news.itsfoss.com/wp-content/uploads/2022/06/thunderbird-102-spaces-toolbar.jpg
|
||||
[7]: https://news.itsfoss.com/wp-content/uploads/2022/06/import-export-thunderbird102.jpg
|
||||
[8]: https://news.itsfoss.com/rocket-chat-matrix/
|
||||
[9]: https://www.thunderbird.net/en-US/thunderbird/102.0/releasenotes/
|
||||
[10]: https://www.thunderbird.net/en-US/
|
@ -0,0 +1,89 @@
|
||||
[#]: subject: "Vim 9.0 is Here With a New Script Language Promising Performance Boost"
|
||||
[#]: via: "https://news.itsfoss.com/vim-9-0-release/"
|
||||
[#]: author: "Ankush Das https://news.itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Vim 9.0 is Here With a New Script Language Promising Performance Boost
|
||||
======
|
||||
Vim 9.0 update brings a new script language, promises a performance boost, and gets closer to common programming languages.
|
||||
|
||||
![][1]
|
||||
|
||||
Vim, the terminal text editor is back with a major update.
|
||||
|
||||
The Vim 9.0 release includes several tiny improvements along with a new script language (Vim9 script).
|
||||
|
||||
Here, let me highlight the key changes.
|
||||
|
||||
### Vim 9.0: What’s New?
|
||||
|
||||
Vim 9.0 is a significant upgrade after almost three years. And, the release announcement mentions that Vim 9.0 is more reliable than any before, which is a good thing to hear.
|
||||
|
||||
Some of the refinements include:
|
||||
|
||||
#### A New Vim9 Script
|
||||
|
||||
Vim script always ensures backwards compatibility, but that changes a bit with this update.
|
||||
|
||||
The backwards compatibility always comes with slower execution performance. So, with the Vim9 script, they aim to drastically improve performance.
|
||||
|
||||
The release note explains:
|
||||
|
||||
> This is accomplished by compiling commands into instructions that can be efficiently executed. An increase in execution speed of 10 to 100 times can be expected.
|
||||
|
||||
Sounds incredible, isn’t it?
|
||||
|
||||
However, what’s the catch for these performance improvements? Here’s what they say:
|
||||
|
||||
> The performance improvements can only be achieved by not being 100% backwards compatible. For example, making function arguments available by creating an “a:” dictionary involves quite a lot of overhead. In a Vim9 function this dictionary is not available. Other differences are more subtle, such as how errors are handled.
|
||||
|
||||
So, you no longer get 100% backwards compatibility, but the legacy scripts should work as usual.
|
||||
|
||||
In addition to the performance improvements, the new script language also aims to get closer to commonly used programming languages, including JavaScript, TypeScript, and Java.
|
||||
|
||||
The developers also plan to add support for **classes** in the script language.
|
||||
|
||||
You can learn more about the new script in the [official help page][2].
|
||||
|
||||
#### New Features
|
||||
|
||||
You will also find some technical feature additions like:
|
||||
|
||||
* Function must be defined with def, if you want to benefit from the speedup.
|
||||
* The arguments and return types must be specificed.
|
||||
* Line continuation does not require using a backlash.
|
||||
* It now simpler to split large scripts. You can use export to make functions/variables available to other scripts, and import to use exported items.
|
||||
* Comments now start with # replacing double quote syntax.
|
||||
|
||||
In either case, you can always refer to the [official announcement][3] to explore all the technical details with the update.
|
||||
|
||||
### Download Vim 9.0
|
||||
|
||||
If you are going to try Vim for the first, you might want to check out our [Vim vs Nano comparison article][4] (keeping in mind the changes for this release).
|
||||
|
||||
You can download the latest version directly from the [official website][5]. Packages should be available for Debian-based/Ubuntu-based systems. For other Linux distributions, you might want to explore the documentations.
|
||||
|
||||
You can build it from sources and apply the latest patches as well.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/vim-9-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/vim-9.0.jpg
|
||||
[2]: https://vimhelp.org/vim9.txt.html
|
||||
[3]: https://www.vim.org/vim90.php
|
||||
[4]: https://itsfoss.com/vim-vs-nano/
|
||||
[5]: https://www.vim.org/download.php
|
@ -1,261 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (hanszhao80)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Djinn: A Code Generator and Templating Language Inspired by Jinja2)
|
||||
[#]: via: (https://theartofmachinery.com/2021/01/01/djinn.html)
|
||||
[#]: author: (Simon Arneaud https://theartofmachinery.com)
|
||||
|
||||
Djinn: A Code Generator and Templating Language Inspired by Jinja2
|
||||
======
|
||||
|
||||
Code generators can be useful tools. I sometimes use the command line version of [Jinja2][1] to generate highly redundant config files and other text files, but it’s feature-limited for transforming data. Obviously the author of Jinja2 thinks differently, but I wanted something like list comprehensions or D’s composable range algorithms.
|
||||
|
||||
I decided to make a tool that’s like Jinja2, but lets me generate complex files by transforming data with range algorithms. The idea was dead simple: a templating language that gets rewritten directly to D code. That way it supports everything D does, simply because it _is_ D. I wanted a standalone code generator, but thanks to [D’s `mixin` feature][2], the same templating language works as an embedded templating language (for HTML in a web app, for example). (For more on that trick, see [this post about translating Brainfuck to D to machine code all at compile time using `mixin`s][3].)
|
||||
|
||||
As usual, [it’s on GitLab][4]. [The examples in this post can be found there, too.][5]
|
||||
|
||||
### Hello world example
|
||||
|
||||
Here’s an example to demonstrate the idea:
|
||||
|
||||
```
|
||||
Hello [= retro("dlrow") ]!
|
||||
[: enum one = 1; :]
|
||||
1 + 1 = [= one + one ]
|
||||
```
|
||||
|
||||
`[= some_expression ]` is like `{{ some_expression }}` in Jinja2, and it renders a value to the output. `[: some_statement; :]` is like `{% some_statement %}` and causes full code statements to be executed. I changed the syntax because D also uses curly braces a lot, and mixing the two made templates hard to read. (There are also special non-D directives, like `include`, that get wrapped in `[<` and `>]`.)
|
||||
|
||||
If you save the above to a file called `hello.txt.dj` and run the `djinn` command line tool against it, you’ll get a file called `hello.txt` containing what you might guess:
|
||||
|
||||
```
|
||||
Hello world!
|
||||
1 + 1 = 2
|
||||
```
|
||||
|
||||
If you’ve used Jinja2, you might be wondering what happened to the second line. Djinn has a special rule that simplifies formatting and whitespace handling: if a source line contains `[:` statements or `[<` directives but doesn’t contain any non-whitespace output, the whole line is ignored for output purposes. Blank lines are still rendered.
|
||||
|
||||
### Generating data
|
||||
|
||||
Okay, now for something a bit more practical: generating CSV data.
|
||||
|
||||
```
|
||||
x,f(x)
|
||||
[: import std.mathspecial;
|
||||
foreach (x; iota(-1.0, 1.0, 0.1)) :]
|
||||
[= "%0.1f,%g", x, normalDistribution(x) ]
|
||||
```
|
||||
|
||||
A `[=` and `]` pair can contain multiple expressions separated by commas. If the first expression is a double-quoted string, it’s interpreted as a [format string][6]. Here’s the output:
|
||||
|
||||
```
|
||||
x,f(x)
|
||||
-1.0,0.158655
|
||||
-0.9,0.18406
|
||||
-0.8,0.211855
|
||||
-0.7,0.241964
|
||||
-0.6,0.274253
|
||||
-0.5,0.308538
|
||||
-0.4,0.344578
|
||||
-0.3,0.382089
|
||||
-0.2,0.42074
|
||||
-0.1,0.460172
|
||||
0.0,0.5
|
||||
0.1,0.539828
|
||||
0.2,0.57926
|
||||
0.3,0.617911
|
||||
0.4,0.655422
|
||||
0.5,0.691462
|
||||
0.6,0.725747
|
||||
0.7,0.758036
|
||||
0.8,0.788145
|
||||
0.9,0.81594
|
||||
```
|
||||
|
||||
### Making an image
|
||||
|
||||
This example is just for the heck of it. [The classic netpbm image library defined a bunch of image formats][7], some of which are text-based. For example, here’s an image of a 3x3 cross:
|
||||
|
||||
```
|
||||
P2 # identifier for Portable GrayMap
|
||||
3 3 # width and height
|
||||
7 # value for pure white (0 is black)
|
||||
7 0 7
|
||||
0 0 0
|
||||
7 0 7
|
||||
```
|
||||
|
||||
You can save the above text to a file named something like `cross.pgm` and many image tools will understand it. Here’s some Djinn code that generates a [Mandelbrot set][8] fractal in the same format:
|
||||
|
||||
```
|
||||
[:
|
||||
import std.complex;
|
||||
enum W = 640;
|
||||
enum H = 480;
|
||||
enum kMaxIter = 20;
|
||||
ubyte mb(uint x, uint y)
|
||||
{
|
||||
const c = complex(3.0 * (x - W / 1.5) / W, 2.0 * (y - H / 2.0) / H);
|
||||
auto z = complex(0.0);
|
||||
ubyte ret = kMaxIter;
|
||||
while (abs(z) <= 2 && --ret) z = z * z + c;
|
||||
return ret;
|
||||
}
|
||||
:]
|
||||
P2
|
||||
[= W ] [= H ]
|
||||
[= kMaxIter ]
|
||||
[: foreach (y; 0..H) :]
|
||||
[= "%(%s %)", iota(W).map!(x => mb(x, y)) ]
|
||||
```
|
||||
|
||||
The resulting file is about 800kB, but it compresses nicely as a PNG:
|
||||
|
||||
```
|
||||
$ # Converting with GraphicsMagick
|
||||
$ gm convert mandelbrot.pgm mandelbrot.png
|
||||
```
|
||||
|
||||
And here it is:
|
||||
|
||||
![][9]
|
||||
|
||||
### Solving a puzzle
|
||||
|
||||
Here’s a puzzle:
|
||||
|
||||
![][10]
|
||||
|
||||
The 5x5 grid needs to be filled in with numbers from 1 to 5, using each number once in each row, and once in each column. (I.e., to make a 5x5 Latin square.) The numbers in neighbouring cells must also satisfy the inequalities indicated by any `>` greater-than signs.
|
||||
|
||||
[I used linear programming (LP) some months ago.][11] LP problems are systems of continuous variables with linear constraints. This time I’ll use mixed integer linear programming (MILP), which generalises LP by also allowing integer-constrained variables. It turns out that’s enough to be NP complete, and MILP happens to be reasonably good for modelling this puzzle.
|
||||
|
||||
In that previous post, I used the Julia library JuMP to help spec the problem. This time I’ll use the [CPLEX text-based format][12], which is supported by several LP and MILP solvers (and can be easily converted to other formats by off-the-shelf tools if needed). Here’s the LP from the previous post in CPLEX format:
|
||||
|
||||
```
|
||||
Minimize
|
||||
obj: v
|
||||
Subject To
|
||||
ptotal: pr + pp + ps = 1
|
||||
rock: 4 ps - 5 pp - v <= 0
|
||||
paper: 5 pr - 8 ps - v <= 0
|
||||
scissors: 8 pp - 4 pr - v <= 0
|
||||
Bounds
|
||||
0 <= pr <= 1
|
||||
0 <= pp <= 1
|
||||
0 <= ps <= 1
|
||||
End
|
||||
```
|
||||
|
||||
CPLEX format is nice to read, but non-trivial problems take a lot of variables and constraints to model, making it painful and error-prone to write out manually. There are domain-specific languages like [ZIMPL][13] for speccing MILPs and LPs in a high-level way. They’re pretty cool for many problems, but ultimately they’re not as expressive as a general-purpose language with a good library like JuMP — or as a code generator with D.
|
||||
|
||||
I’ll model the puzzle using two sets of variables: (v_{r,c}) and (i_{r,c,v}). (v_{r,c}) will hold the value (1-5) of the cell at row (r) and column (c). (i_{r,c,v}) will be an indicator binary that’s 1 if the cell at row (r) and column (c) has value (v), and 0 otherwise. These two sets of variables are redundant representations of the grid, but the first representation makes it easier to model the inequality constraints, while the second representation makes it easier to model the uniqueness constraints. I just need to add some extra constraints to force the two representations to be consistent. But first, let’s start with the basic constraint that each cell must have exactly one value. Mathematically, that means all the indicators for a given row and column must be 0, except for one that is 1. That can be enforced by this equation:
|
||||
|
||||
[i_{r,c,1} + i_{r,c,2} + i_{r,c,3} + i_{r,c,4} + i_{r,c,5} = 1]
|
||||
|
||||
The CPLEX constraints for all rows and columns can be generated with this Djinn code:
|
||||
|
||||
```
|
||||
\ Cell has one value
|
||||
[:
|
||||
foreach (r; iota(N))
|
||||
foreach (c; iota(N))
|
||||
:]
|
||||
[= "%-(%s + %)", vs.map!(v => ivar(r, c, v)) ] = 1
|
||||
[::]
|
||||
```
|
||||
|
||||
`ivar()` is a helper function that gives us the string identifier for an (i) variable, and `vs` stores the numbers 1-5 for convenience. The constraints for uniqueness within rows and columns are exactly the same, but iterating over the other two dimensions of (i).
|
||||
|
||||
To make the (i) vars consistent with the (v) vars, we need constraints like this (remember, only one of the (i) vars is non-zero):
|
||||
|
||||
[i_{r,c,1} + 2i_{r,c,2} + 3i_{r,c,3} + 4i_{r,c,4} + 5i_{r,c,5} = v_{r,c}]
|
||||
|
||||
CPLEX requires all variables to be on the left, so the Djinn code looks like this:
|
||||
|
||||
```
|
||||
\ Link i vars with v vars
|
||||
[:
|
||||
foreach (r; iota(N))
|
||||
foreach (c; iota(N))
|
||||
:]
|
||||
[= "%-(%s + %)", vs.map!(v => text(v, ' ', ivar(r, c, v))) ] - [= vvar(r,c) ] = 0
|
||||
[::]
|
||||
```
|
||||
|
||||
The constraints for the neighouring cell inequalities and for the bottom left corner being 4 are all trivial to write. All that’s left is to declare the indicator variables to be binary, and set the bounds for the (v) vars. All up, there are 150 variables and 111 constraints, plus bounds for the variables. [You can see the full code in the repo.][14]
|
||||
|
||||
The [GNU Linear Programming Kit][15] has a command line tool that can solve this CPLEX MILP. Unfortunately, its output is a big dump of everything, so I used awk to pull out what’s needed:
|
||||
|
||||
```
|
||||
$ time glpsol --lp inequality.lp -o /dev/stdout | awk '/v[0-9][0-9]/ { print $2, $4 }' | sort
|
||||
v00 1
|
||||
v01 3
|
||||
v02 2
|
||||
v03 5
|
||||
v04 4
|
||||
v10 2
|
||||
v11 5
|
||||
v12 4
|
||||
v13 1
|
||||
v14 3
|
||||
v20 3
|
||||
v21 1
|
||||
v22 5
|
||||
v23 4
|
||||
v24 2
|
||||
v30 5
|
||||
v31 4
|
||||
v32 3
|
||||
v33 2
|
||||
v34 1
|
||||
v40 4
|
||||
v41 2
|
||||
v42 1
|
||||
v43 3
|
||||
v44 5
|
||||
|
||||
real 0m0.114s
|
||||
user 0m0.106s
|
||||
sys 0m0.005s
|
||||
```
|
||||
|
||||
Here’s the solution written out in the original grid:
|
||||
|
||||
![][16]
|
||||
|
||||
These examples are just for playing around, but I’m sure you get the idea. The `README.md` for the Djinn repo is itself generated using a Djinn template, by the way.
|
||||
|
||||
As I said, Djinn can also be used as a compile-time templating language embedded inside D code. I primarily wanted a code generator, but that’s a bonus thanks to D’s metaprogramming features.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://theartofmachinery.com/2021/01/01/djinn.html
|
||||
|
||||
作者:[Simon Arneaud][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[hanszhao80](https://github.com/hanszhao80)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://theartofmachinery.com
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://jinja2docs.readthedocs.io/en/stable/
|
||||
[2]: https://dlang.org/articles/mixin.html
|
||||
[3]: https://theartofmachinery.com/2017/12/31/compile_time_brainfuck.html
|
||||
[4]: https://gitlab.com/sarneaud/djinn
|
||||
[5]: https://gitlab.com/sarneaud/djinn/-/tree/v0.1.0/examples
|
||||
[6]: https://dlang.org/phobos/std_format.html#format-string
|
||||
[7]: http://netpbm.sourceforge.net/doc/#formats
|
||||
[8]: https://en.wikipedia.org/wiki/Mandelbrot_set
|
||||
[9]: https://theartofmachinery.com/images/djinn/mandelbrot.png
|
||||
[10]: https://theartofmachinery.com/images/djinn/inequality.svg
|
||||
[11]: https://theartofmachinery.com/2020/05/21/glico_weighted_rock_paper_scissors.html
|
||||
[12]: http://lpsolve.sourceforge.net/5.0/CPLEX-format.htm
|
||||
[13]: https://zimpl.zib.de/
|
||||
[14]: https://gitlab.com/sarneaud/djinn/-/tree/v0.1.0/examples/inequality.lp.dj
|
||||
[15]: https://www.gnu.org/software/glpk/
|
||||
[16]: https://theartofmachinery.com/images/djinn/inequality_solution.svg
|
@ -2,7 +2,7 @@
|
||||
[#]: via: (https://opensource.com/article/21/5/fog-computing)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (hanszhao80)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
@ -54,7 +54,7 @@ via: https://opensource.com/article/21/5/fog-computing
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
译者:[hanszhao80](https://github.com/hanszhao80)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,95 +0,0 @@
|
||||
[#]: subject: (What is the OSI model?)
|
||||
[#]: via: (https://jvns.ca/blog/2021/05/11/what-s-the-osi-model-/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
What is the OSI model?
|
||||
======
|
||||
|
||||
Today I tweeted something about how the OSI model doesn’t correspond well to the reality of how TCP/IP works and it made me think – what is the OSI model, exactly? From reading some of the replies on Twitter, it seems like there are at least 3 different ways to think about it:
|
||||
|
||||
1. A literal description of how TCP/IP works
|
||||
2. An abstract model that you can use to describe and compare a lot of different networking protocols
|
||||
3. A literal description of some computer networking protocols from the 1980s that are mostly no longer used today
|
||||
|
||||
|
||||
|
||||
In this post I’m not going to try to argue that any one of these is “really” what the OSI model is – it seems like different people think about the OSI model in all of these ways, and that’s okay.
|
||||
|
||||
### the OSI model has 7 layers
|
||||
|
||||
Before we talk about what the OSI model means, let’s very briefly discuss what it is: it’s an abstract model for how networking works with 7 numbered layers:
|
||||
|
||||
* Layer 1: physical layer
|
||||
* Layer 2: data link
|
||||
* Layer 3: network
|
||||
* Layer 4: transport
|
||||
* Layer 5: session
|
||||
* Layer 6: presentation
|
||||
* Layer 7: application
|
||||
|
||||
|
||||
|
||||
I won’t say more about what each of those is supposed to mean, there are a thousand explanations of it online.
|
||||
|
||||
### the OSI model as a literal description of how TCP/IP works
|
||||
|
||||
First, I want to talk about one common way people use the OSI model in practice: as a literal description of how TCP/IP works. Some layers of the OSI model are really easy to map to TCP/IP:
|
||||
|
||||
* Layer 2 corresponds to Ethernet
|
||||
* Layer 3 corresponds to IP
|
||||
* Layer 4 corresponds to TCP or UDP (or ICMP etc)
|
||||
* Layer 7 corresponds to whatever is inside the TCP or UDP packet (for example a DNS query)
|
||||
|
||||
|
||||
|
||||
This mapping makes a lot of sense for layers 2, 3, and 4 – TCP packets have 3 headers corresponding to these 3 layers (the Ethernet header, the IP header, and the TCP header).
|
||||
|
||||
Having numbers to describe the different headers in a TCP packet is pretty useful – if you say “layer 2”, it’s clear that that lives “underneath” layer 3, because 2 is a smaller number than 3.
|
||||
|
||||
The weird thing about “OSI model as literal description” is that layers 5 and 6 don’t really correspond to anything in TCP/IP – I’ve heard a lot of different interpretations of what layers 5 or 6 could be (you could say layer 5 is TLS or something!) but they don’t have a clear correspondence like “every layer has a corresponding header in the TCP packet” the way layers 2, 3, and 4 do.
|
||||
|
||||
Also, some parts of TCP/IP don’t fit well into the OSI model even around layers 2-4 – for example, what layer is an ARP packet? ARP packets send some data with an Ethernet header, so does that mean they’re layer 3? Layer 2? The Wikipedia article listing different OSI layers categorizes it under “layer 2.5” which is pretty unsatisfying.
|
||||
|
||||
This is only really a problem because the OSI model is sometimes used to teach TCP/IP, and it’s confusing if it’s not made clear which parts of the model map well to TCP/IP and which don’t.
|
||||
|
||||
### the OSI model as an abstraction for comparing networking protocols
|
||||
|
||||
Another way of thinking of OSI that I’ve heard is that it’s an abstraction you can use to draw analogies between lots of different networking protocols. For example, if you want to understand how Bluetooth works, maybe you can use the OSI model to help you – here’s an diagram I found on [this page][1] showing how Bluetooth fits into the OSI model.
|
||||
|
||||
![][2]
|
||||
|
||||
As another example of this, [this Wikipedia article][3] has a list of OSI layers and which specific networking protocols correspond to those OSI layers.
|
||||
|
||||
### the OSI model as a literal description of some obsolete protocols
|
||||
|
||||
Some very brief research on Wikipedia says that in addition to an abstract description of 7 layers, the OSI model also contained a [bunch of specific protocols implementing those layers][4]. Apparently this happened during the [Protocol Wars][5] in the 70s and 80s, where the OSI model lost and TCP/IP won.
|
||||
|
||||
This explains why the OSI model doesn’t really correspond that well to TCP/IP, since if the OSI protocols had “won” then the OSI model _would_ correspond exactly to how internet networking actually works.
|
||||
|
||||
### that’s all!
|
||||
|
||||
I’m writing this because when I originally learned about the OSI model I found it super confusing (what are all these layers? are they real? is this actually how networking works? what’s happening?) and I wish someone had told me that (as someone who does not work with any networking protocols other than TCP/IP) I could just learn how layers 2, 3, 4, and 7 relate to TCP/IP and then ignore everything else about it. So hopefully this will help clear things up for somebody!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2021/05/11/what-s-the-osi-model-/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://flylib.com/books/en/4.215.1.116/1/
|
||||
[2]: https://jvns.ca/images/bluetooth.gif
|
||||
[3]: https://en.wikipedia.org/wiki/List_of_network_protocols_(OSI_model)
|
||||
[4]: https://en.wikipedia.org/wiki/OSI_protocols
|
||||
[5]: https://en.wikipedia.org/wiki/Protocol_Wars
|
@ -0,0 +1,480 @@
|
||||
[#]: subject: "Notes on running containers with bubblewrap"
|
||||
[#]: via: "https://jvns.ca/blog/2022/06/28/some-notes-on-bubblewrap/"
|
||||
[#]: author: "Julia Evans https://jvns.ca/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Notes on running containers with bubblewrap
|
||||
======
|
||||
Hello! About a year ago I got mad about Docker container startup time. This was
|
||||
because I was building an [nginx playground][1]
|
||||
where I was starting a new “container” on every HTTP request, and so for it to
|
||||
feel reasonably snappy, nginx needed to start quickly.
|
||||
|
||||
Also, I was running this project on a pretty small cloud machine (256MB RAM), a
|
||||
small CPU, so I really wanted to avoid unnecessary overhead.
|
||||
|
||||
I’ve been looking for a way to run containers faster since then, but I couldn’t
|
||||
find one until last week when I discovered
|
||||
[bubblewrap][2]!! It’s very fast and I
|
||||
think it’s super cool, but I also ran into a bunch of fun problems that I
|
||||
wanted to write down for my future self.
|
||||
|
||||
#### some disclaimers
|
||||
|
||||
* I’m not sure if the way I’m using bubblewrap in this post is maybe not how it’s intended to be used
|
||||
* there are a lot of sharp edges when using bubblewrap in this way, you need to
|
||||
think a lot about Linux namespaces and how containers work
|
||||
* bubblewrap is a security tool but I am not a security person and I am only
|
||||
doing this for weird tiny projects. you should definitely not take security
|
||||
advice from me.
|
||||
|
||||
Okay, all of that said, let’s talk about I’m trying to use bubblewrap to run
|
||||
containers fast and in a relatively secure way :)
|
||||
|
||||
#### Docker containers take ~300ms to start on my machine
|
||||
|
||||
I ran a quick benchmark to see how long a Docker container takes to run a
|
||||
simple command (`ls` ). For both Docker and Podman, it’s about 300ms.
|
||||
|
||||
```
|
||||
$ time docker run --network none -it ubuntu:20.04 ls / > /dev/null
|
||||
Executed in 378.42 millis
|
||||
$ time podman run --network none -it ubuntu:20.04 ls / > /dev/null
|
||||
Executed in 279.27 millis
|
||||
```
|
||||
|
||||
Almost all of this time is overhead from docker and podman – just running `ls`
|
||||
by itself takes about 3ms:
|
||||
|
||||
```
|
||||
$ time ls / > /dev/null
|
||||
Executed in 2.96 millis
|
||||
```
|
||||
|
||||
I want to stress that, while I’m not sure exactly what the slowest part of
|
||||
Docker and podman startup time is (I spent 5 minutes trying to profile them and
|
||||
gave up), I’m 100% sure it’s something important.
|
||||
|
||||
The way we’re going to run containers faster with bubblewrap has a lot of
|
||||
limitations and it’s a lower level interface which is a lot trickier to use.
|
||||
|
||||
#### goal 1: containers that start quickly
|
||||
|
||||
I felt like it *should* be possible to have containers that start essentially
|
||||
instantly or at least in less than 5ms. My thought process:
|
||||
|
||||
* creating a new namespace with `unshare` is basically instant
|
||||
* [containers are basically just a bunch of namespaces][3]
|
||||
* what’s the problem?
|
||||
|
||||
#### container startup time is (usually) not that important
|
||||
|
||||
Most of the time when people are using containers, they’re running some
|
||||
long-running process inside the container like a webserver, so it doesn’t
|
||||
really matter if it takes 300ms to start.
|
||||
|
||||
So it makes sense to me that there aren’t a lot of container tools that
|
||||
optimize for startup time. But I still wanted to optimize for startup time :)
|
||||
|
||||
#### goal 2: run the containers as an unprivileged user
|
||||
|
||||
Another goal I had was to be able to run my containers as an unprivileged user
|
||||
instead of root.
|
||||
|
||||
I was surprised the first time I learned that Docker actually runs containers
|
||||
as root – even though I run `docker run ubuntu:20.04` as an unprivileged user (`bork` ), that
|
||||
message is actually sent to a daemon running as root, and the Docker container
|
||||
process itself also runs as root (albeit a `root` that’s stripped of all its
|
||||
capabilities).
|
||||
|
||||
That’s fine for Docker (they have lots of very smart people making sure that
|
||||
they get it right!), but if I’m going to do container stuff *without* using
|
||||
Docker (for the speed reasons mentioned above), I’d rather not do it as root to
|
||||
keep everything a bit more secure.
|
||||
|
||||
#### podman can run containers as an non-root user
|
||||
|
||||
Before we start talking about how to do weird stuff with bubblewrap, I want to
|
||||
quickly talk about a much more normal tool to run containers: podman!
|
||||
|
||||
Podman, unlike Docker, can run containers as an unprivileged user!
|
||||
|
||||
If I run this from my normal user:
|
||||
|
||||
```
|
||||
$ podman run -it ubuntu:20.04 ls
|
||||
```
|
||||
|
||||
it doesn’t secretly run as root behind the scenes! It just starts the container
|
||||
as my normal user, and then uses something called “user namespaces” so that
|
||||
*inside the container* I appear to be root.
|
||||
|
||||
The other cool thing aboud podman is that it has exactly the same interface as
|
||||
Docker, so you can just take a Docker command and replace `docker` with
|
||||
`podman` and it’ll Just Work. I’ve found that sometimes I need to do some extra
|
||||
work to get podman to work in practice, but it’s still pretty nice that it has
|
||||
the same command line interface.
|
||||
|
||||
This “run containers as a non-root user” feature is normally called “rootless
|
||||
containers”. (I find that name kind of counterintuitive, but that’s what people call it)
|
||||
|
||||
#### failed attempt 1: write my own tool using runc
|
||||
|
||||
```
|
||||
runc
|
||||
```
|
||||
|
||||
I knew that Docker and podman use
|
||||
[runc][4] under the hood, so I thought –
|
||||
well, maybe I can just use `runc` directly to make my own tool that starts
|
||||
containers faster than Docker does!
|
||||
|
||||
I tried to do this 6 months ago and I don’t remember most of the details, but basically
|
||||
I spent 8 hours working on it, got frustrated because I couldn’t get anything
|
||||
to work, and gave up.
|
||||
|
||||
One specific detail I remember struggling with was setting up a working `/dev`
|
||||
for my programs to use.
|
||||
|
||||
#### enter bubblewrap
|
||||
|
||||
Okay, that was a very long preamble so let’s get to the point! Last week, I
|
||||
discovered a tool called `bubblewrap` that was basically exactly the thing I
|
||||
was trying to build with `runc` in my failed attempt, except that it actually
|
||||
works and has many more features and it’s built by people who know things about
|
||||
security! Hooray!
|
||||
|
||||
The interface to bubblewrap is pretty different than the interface to Docker –
|
||||
it’s much lower level. There’s no concept of a container image – instead you
|
||||
map a bunch of directories on your host to directories in the container.
|
||||
|
||||
For example, here’s how to run a container with the same root directory as your
|
||||
host operating system, but with only read access to that root directory, and only write access to `/tmp`.
|
||||
|
||||
```
|
||||
bwrap \
|
||||
--ro-bind / / \
|
||||
--bind /tmp /tmp \
|
||||
--proc /proc --dev /dev \
|
||||
--unshare-pid \
|
||||
--unshare-net \
|
||||
bash
|
||||
```
|
||||
|
||||
For example, you could imagine running some untrusted process under bubblewrap
|
||||
this way and then putting all the files you the process to access in `/tmp`.
|
||||
|
||||
#### bubblewrap runs containers as an unprivileged (non-root) user
|
||||
|
||||
Like podman, bubblewrap runs containers as a non-root user, using user
|
||||
namespaces. It can also run containers as root, but in this post we’re just
|
||||
going to be talking about using it as an unprivileged user.
|
||||
|
||||
#### bubblewrap is fast
|
||||
|
||||
Let’s see how long it takes to run `ls` in a bubblewrap container!
|
||||
|
||||
```
|
||||
$ time bwrap --ro-bind / / --proc /proc --dev /dev --unshare-pid ls /
|
||||
Executed in 8.04 millis
|
||||
```
|
||||
|
||||
That’s a big difference! 8ms is a lot faster than 279ms.
|
||||
|
||||
Of course, like we said before, the reason bubblewrap is faster is that it does
|
||||
a lot less. So let’s talk about some things bubblewrap doesn’t do.
|
||||
|
||||
#### some things bubblewrap doesn’t do
|
||||
|
||||
Here are some things that Docker/podman do that bubblewrap doesn’t do:
|
||||
|
||||
* set up overlayfs mounts for you, so that your changes to the filesystem don’t affect the base image
|
||||
* set up networking bridges so that you can connect to a webserver inside the container
|
||||
* probably a bunch more stuff that I’m not thinking of
|
||||
|
||||
In general, bubblewrap is a much lower level tool than something like Docker.
|
||||
|
||||
Also, bubblewrap seems to have pretty different goals than Docker – the README
|
||||
seems to say that it’s intended as a tool for sandboxing desktop software (I
|
||||
think it comes from [flatpak][5]).
|
||||
|
||||
#### running a container image with bubblewrap
|
||||
|
||||
I couldn’t find instructions for running a Docker container image with
|
||||
bubblewrap, so here they are. Basically I just use Docker to download the
|
||||
container image and put it into a directory and then run it with `bwrap` :
|
||||
|
||||
There’s also a tool called [bwrap-oci][6] which looks cool but I
|
||||
couldn’t get it to compile.
|
||||
|
||||
```
|
||||
mkdir rootfs
|
||||
docker export $(docker create frapsoft/fish) | tar -C rootfs -xf -
|
||||
bwrap \
|
||||
--bind $PWD/rootfs / \
|
||||
--proc /proc --dev /dev \
|
||||
--uid 0 \
|
||||
--unshare-pid \
|
||||
--unshare-net \
|
||||
fish
|
||||
```
|
||||
|
||||
One important thing to note is that this doesn’t create a temporary overlay
|
||||
filesystem for the container’s file writes, so it’ll let the container edit
|
||||
files in the image.
|
||||
|
||||
I wrote a post about [overlay filesystems][7] if
|
||||
you want to see how you could do that yourself though.
|
||||
|
||||
#### running “containers” with bubblewrap isn’t the same as with podman
|
||||
|
||||
I just gave an example of how to “run a container” with bubblewrap, and you
|
||||
might think “cool, this is just like podman but faster!”. It is not, and it’s
|
||||
actually unlike using podman in even more ways than I expected.
|
||||
|
||||
I put “container” in scare quotes because there are two ways to define “container”:
|
||||
|
||||
* something that implements [OCI runtime specification][8]
|
||||
* any way of running a process in a way that’s somehow isolated from the host system
|
||||
|
||||
bubblewrap is a “container” tool in the second sense. It definitely provides
|
||||
isolation, and it does that using the same features – Linux namespaces – as
|
||||
Docker.
|
||||
|
||||
But it’s not a container tool in the first sense. And it’s a lower level tool
|
||||
so you can get into a bunch of weird states and you really need to think about
|
||||
all the weird details of how container work while using it.
|
||||
|
||||
For the rest of the post I’m going to talk about some weird things that can
|
||||
happen with bubblewrap that would not happen with podman/Docker.
|
||||
|
||||
#### weird thing 1: processes that don’t exist
|
||||
|
||||
Here’s an example of a weird situation I got into with bubblewrap that confused
|
||||
me for a minute:
|
||||
|
||||
```
|
||||
$ bwrap --ro-bind / / --unshare-all bash
|
||||
$ ps aux
|
||||
... some processes
|
||||
root 390073 0.0 0.0 2848 124 pts/9 S 14:28 0:00 bwrap --ro-bind / / --unshare-all --uid 0 bash
|
||||
... some other processes
|
||||
$ kill 390073
|
||||
bash: kill: (390073) - No such process
|
||||
$ ps aux | grep 390073
|
||||
root 390073 0.0 0.0 2848 124 pts/9 S 14:28 0:00 bwrap --ro-bind / / --unshare-all --uid 0 bash
|
||||
```
|
||||
|
||||
Here’s what happened
|
||||
|
||||
* I started a bash shell inside bubblewrap
|
||||
* I ran `ps aux`, and saw a process with PID `390073`
|
||||
* I try to kill the process. It fails with the error `no such process`. What?
|
||||
* I ran `ps aux`, and still see the process with PID `390073`
|
||||
|
||||
What’s going on? Why doesn’t the process `390073` exist, even though `ps` says it does? Isn’t that impossible?
|
||||
|
||||
Well, the problem is that `ps` doesn’t actually list all the processes in your
|
||||
current PID namespace. Instead, it iterates through all the entries in `/proc`
|
||||
and prints those out. Usually, what’s in `/proc` is actually the same as the processes on your system.
|
||||
|
||||
But with Linux containers these things can get out of sync. What’s happening in
|
||||
this example is that we have the `/proc` from the host PID namespace, but those
|
||||
aren’t actually the processes that we have access to in our PID namespace.
|
||||
|
||||
Passing `--proc /proc` to bwrap fixes the issue – `ps` then actually lists the correct processes.
|
||||
|
||||
```
|
||||
$ bwrap --ro-bind / / --unshare-all --dev /dev --proc /proc ps aux
|
||||
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
|
||||
bork 1 0.0 0.0 3644 136 ? S+ 16:21 0:00 bwrap --ro-bind / / --unshare-all --dev /dev --proc /proc ps au
|
||||
bork 2 0.0 0.0 21324 1552 ? R+ 16:21 0:00 ps aux
|
||||
```
|
||||
|
||||
Just 2 processes! Everything is normal!
|
||||
|
||||
#### weird thing 2: trying to listen on port 80
|
||||
|
||||
Passing `--uid 0` to bubblewrap makes the user inside the container `root`. You
|
||||
might think that this means that the root user has administrative privileges
|
||||
inside the container, but that’s not true!
|
||||
|
||||
For example, let’s try to listen on port 80:
|
||||
|
||||
```
|
||||
$ bwrap --ro-bind / / --unshare-all --uid 0 nc -l 80
|
||||
nc: Permission denied
|
||||
```
|
||||
|
||||
What’s going on here is that the new root user actually doesn’t have the
|
||||
**capabilities** it needs to listen on port 80. (you need special permissions
|
||||
to listen on ports less than 1024, and 80 is less than 1024)
|
||||
|
||||
There’s actually a capability specifically for listening on privileged ports
|
||||
called `CAP_NET_BIND_SERVICE`.
|
||||
|
||||
So to fix this all we need to do is to tell bubblewrap to give our user that
|
||||
capability.
|
||||
|
||||
```
|
||||
$ bwrap --ro-bind / / --unshare-all --uid 0 --cap-add cap_net_bind_service nc -l 80
|
||||
(no output, success!!!)
|
||||
```
|
||||
|
||||
This works! Hooray!
|
||||
|
||||
#### finding the right capabilities is pretty annoying
|
||||
|
||||
bubblewrap doesn’t give out any capabilities by default, and I find that
|
||||
figuring out all the right capabilities and adding them manually is kind of
|
||||
annoying. Basically my process is
|
||||
|
||||
* run the thing
|
||||
* see what fails
|
||||
* read `man capabilities` to figure out what capabilities I’m missing
|
||||
* add the capability with `--cap-add`
|
||||
* repeat until everything is running
|
||||
|
||||
But that’s the price I pay for wanting things to be fast I guess :)
|
||||
|
||||
#### weird thing 2b: --dev /dev makes listening on privileged ports not work
|
||||
|
||||
```
|
||||
--dev /dev
|
||||
```
|
||||
|
||||
One other strange thing is that if I take the exact same command above (which
|
||||
worked!) and add `--dev /dev` (to set up the `/dev/` directory), it causes it to not work again:
|
||||
|
||||
```
|
||||
$ bwrap --ro-bind / / --dev /dev --unshare-all --uid 0 --cap-add cap_net_bind_service nc -l 80
|
||||
nc: Permission denied
|
||||
```
|
||||
|
||||
I think this might be a bug in bubblewrap, but I haven’t mustered the courage
|
||||
to dive into the bubblewrap code and start investigating yet. Or maybe there’s
|
||||
something obvious I’m missing!
|
||||
|
||||
#### weird thing 3: UID mappings
|
||||
|
||||
Another slightly weird thing was – I tried to run `apt-get update` inside a bubblewrap Ubuntu container and everything went very poorly.
|
||||
|
||||
Here’s how I ran `apt-get update` inside the Ubuntu container:
|
||||
|
||||
```
|
||||
mkdir rootfs
|
||||
docker export $(docker create ubuntu:20.04) | tar -C rootfs -xf -
|
||||
bwrap \
|
||||
--bind $PWD/rootfs / \
|
||||
--proc /proc\
|
||||
--uid 0 \
|
||||
--unshare-pid \
|
||||
apt-get update
|
||||
```
|
||||
|
||||
And here are the error messages:
|
||||
|
||||
```
|
||||
E: setgroups 65534 failed - setgroups (1: Operation not permitted)
|
||||
E: setegid 65534 failed - setegid (22: Invalid argument)
|
||||
E: seteuid 100 failed - seteuid (22: Invalid argument)
|
||||
E: setgroups 0 failed - setgroups (1: Operation not permitted)
|
||||
.... lots more similar errors
|
||||
```
|
||||
|
||||
At first I thought “ok, this is a capabilities problem, I need to set
|
||||
`CAP_SETGID` or something to give the container permission to change groups. But I did that and it didn’t help at all!
|
||||
|
||||
I think what’s going on here is a problem with UID maps. What are UID maps?
|
||||
Well, every time you run a container using “user namespaces” (which podman is
|
||||
doing), it creates a mapping of UIDs inside the container to UIDs on the host.
|
||||
|
||||
Let’s look that the UID maps! Here’s how do that:
|
||||
|
||||
````
|
||||
[[email protected]][9]:/# cat /proc/self/uid_map
|
||||
0 1000 1
|
||||
[[email protected]][10]:/# cat /proc/self/gid_map
|
||||
1000 1000 1
|
||||
|
||||
```
|
||||
This is saying that user 0 in the container is mapped to user 1000 on in the
|
||||
host, and group 1000 is mapped to group 1000. (My normal user's UID/GID is 1000, so this makes sense). You can find out
|
||||
about this `uid_map` file in `man user_namespaces`.
|
||||
|
||||
All other users/groups that aren't 1000 are mapped to user 65534 by default, according
|
||||
to `man user_namespaces`.
|
||||
|
||||
### what's going on: non-mapped users can't be used
|
||||
|
||||
The only users and groups that have been mapped are `0` and `1000`. But `man user_namespaces` says:
|
||||
|
||||
> After the uid_map and gid_map files have been written, only the mapped values may be used in system calls that change user and group IDs.
|
||||
|
||||
`apt` is trying to use users 100 and 65534. Those aren't on the list of mapped
|
||||
users! So they can't be used!
|
||||
|
||||
This works fine in podman, because podman sets up its UID and GID mappings differently:
|
||||
```
|
||||
|
||||
$ podman run -it ubuntu:20.04 bash
|
||||
[[email protected]][11]:/# cat /proc/self/uid_map
|
||||
0 1000 1
|
||||
1 100000 65536
|
||||
[[email protected]][12]:/# cat /proc/self/gid_map
|
||||
0 1000 1
|
||||
1 100000 65536
|
||||
```
|
||||
|
||||
All the users get mapped, not just 1000.
|
||||
|
||||
I don’t quite know how to fix this, but I think it’s probably possible in
|
||||
bubblewrap to set up the uid mappings the same way as podman does – there’s an
|
||||
[issue about it here that links to a workaround][13].
|
||||
|
||||
But this wasn’t an actual problem I was trying to solve so I didn’t dig further
|
||||
into it.
|
||||
|
||||
#### it works pretty great!
|
||||
|
||||
I’ve talked about a bunch of issues, but the things I’ve been trying to do in bubblewrap
|
||||
have been very constrained and it’s actually been pretty simple. For example, I
|
||||
was working on a git project where I really just want to run `git` inside a
|
||||
container and map a git repository from the host.
|
||||
|
||||
That’s very simple to get to work with bubblewrap! There were basically no weird problems!
|
||||
It’s really fast!
|
||||
|
||||
So I’m pretty excited about this tool and I might use it for more stuff in the
|
||||
future.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2022/06/28/some-notes-on-bubblewrap/
|
||||
|
||||
作者:[Julia Evans][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://jvns.ca/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://jvns.ca/blog/2021/09/24/new-tool--an-nginx-playground/
|
||||
[2]: https://github.com/containers/bubblewrap
|
||||
[3]: https://jvns.ca/blog/2016/10/10/what-even-is-a-container/
|
||||
[4]: https://github.com/opencontainers/runc
|
||||
[5]: https://flatpak.org/
|
||||
[6]: https://github.com/projectatomic/bwrap-oci
|
||||
[7]: https://jvns.ca/blog/2019/11/18/how-containers-work--overlayfs/
|
||||
[8]: https://opencontainers.org/about/overview/
|
||||
[9]: https://jvns.ca/cdn-cgi/l/email-protection
|
||||
[10]: https://jvns.ca/cdn-cgi/l/email-protection
|
||||
[11]: https://jvns.ca/cdn-cgi/l/email-protection
|
||||
[12]: https://jvns.ca/cdn-cgi/l/email-protection
|
||||
[13]: https://github.com/containers/bubblewrap/issues/468
|
@ -0,0 +1,556 @@
|
||||
[#]: subject: "ABCs of FreeDOS: 26 commands I use all the time"
|
||||
[#]: via: "https://opensource.com/article/22/6/26-freedos-commands"
|
||||
[#]: author: "Jim Hall https://opensource.com/users/jim-hall"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
ABCs of FreeDOS: 26 commands I use all the time
|
||||
======
|
||||
On its 28th anniversary, I'm pleased to share my top 26 favorite FreeDOS commands.
|
||||
|
||||
![FreeDOS fish logo and command prompt on computer][1]
|
||||
|
||||
Image by: Jim Hall, CC BY-SA 4.0.
|
||||
|
||||
One of my family's first computers ran a command-line operating system called DOS, the "Disk Operating System." I grew up with DOS, and learned to leverage the command line to make my work easier. And so did a lot of other people. We loved DOS so much that in 1994, we created the FreeDOS Project. Today on June 29, we celebrate 28 years of FreeDOS.
|
||||
|
||||
If you're new to FreeDOS, you may be confused about how to use the different command line programs that come with it. Let's get started with 26 of my favorite FreeDOS commands. To learn more, add the /? option after most commands to get more information:
|
||||
|
||||
```
|
||||
C:\>attrib /?
|
||||
ATTRIB v2.1 - Displays or changes file attributes.
|
||||
Copyright (c) 1998-2003, licensed under GPL2.
|
||||
|
||||
Syntax: ATTRIB { options | [path][file] | /@[list] }
|
||||
|
||||
Options:
|
||||
|
||||
+H Sets the Hidden attribute. -H Clears the Hidden attribute.
|
||||
+S Sets the System attribute. -S Clears the System attribute.
|
||||
+R Sets the Read-only attribute. -R Clears the Read-only attribute.
|
||||
+A Sets the Archive attribute. -A Clears the Archive attribute.
|
||||
|
||||
/S Process files in all directories in the specified path(es).
|
||||
/D Process directory names for arguments with wildcards.
|
||||
/@ Process files, listed in the specified file [or in stdin].
|
||||
|
||||
Examples:
|
||||
|
||||
attrib file -rhs
|
||||
attrib +a -r dir1 dir2*.dat /s
|
||||
attrib -hs/sd /@list.txt *.*
|
||||
```
|
||||
|
||||
### A is for ATTRIB
|
||||
|
||||
The `ATTRIB` program displays or changes a file's *attributes*. An attribute can be one of four values: Hidden (H), System (S), Read-only (R), and Archive (A).
|
||||
|
||||
Files marked as Hidden don't display in a directory listing. For example, suppose you want to "hide" a file called `SECRET.TXT` so no one would know it was there. First, you can show the attributes on that file to see its current settings:
|
||||
|
||||
```
|
||||
C:\FILES>attrib secret.txt
|
||||
[----A] SECRET.TXT
|
||||
```
|
||||
|
||||
To hide this file, turn on the Hidden attribute by using the plus (`+` ) operator, like this:
|
||||
|
||||
```
|
||||
C:\FILES>attrib +h secret.txt
|
||||
[----A] -> [-H--A] SECRET.TXT
|
||||
C:\FILES>dir
|
||||
Volume in drive C is FREEDOS2022
|
||||
Volume Serial Number is 333D-0B18
|
||||
|
||||
Directory of C:\FILES
|
||||
|
||||
. <DIR> 05-27-2022 9:22p
|
||||
.. <DIR> 05-27-2022 9:22p
|
||||
0 file(s) 0 bytes
|
||||
2 dir(s) 279,560,192 bytes free
|
||||
```
|
||||
|
||||
Another common way to use `ATTRIB` is by manipulating the Read-only attribute, so you don't accidentally overwrite an important file. Suppose you want to protect the `SECRET.TXT` file so you can't delete or change it. Turn on the Read-only attribute like this, with the `+R` modifier:
|
||||
|
||||
```
|
||||
C:\FILES>attrib +r secret.txt
|
||||
[----A] -> [---RA] SECRET.TXT
|
||||
C:\FILES>del secret.txt
|
||||
C:\FILES\SECRET.TXT: Permission denied
|
||||
no file removed.
|
||||
```
|
||||
|
||||
### B is for BEEP
|
||||
|
||||
If you need to add a little pizzazz to a batch file, you can use the `BEEP` command to get the user's attention. `BEEP` doesn't display anything to the screen, but simply generates a classic “beep” tone.
|
||||
|
||||
Note that `BEEP` uses the PC's built-in speaker to make the “beep” sound. If you boot FreeDOS using a virtual machine, check that your system is set up to correctly emulate the PC speaker. Otherwise, you will not hear anything.
|
||||
|
||||
### C is for CD
|
||||
|
||||
Like Linux, FreeDOS supports directories, which allow you to organize your files in a way that makes sense to you. For example, you might keep all of your files in a directory called `FILES`, and you might have other directories inside `FILES` for certain kinds of files, such as `DOCS` for word processor files, or `SPRDSHT` for spreadsheet files.
|
||||
|
||||
You can navigate into a directory using the `CD` or *change directory* command. The `CHDIR` command is the same as `CD`, if you prefer to use that syntax.
|
||||
|
||||
To change into a new directory, use the `CD` command with the destination directory:
|
||||
|
||||
```
|
||||
C:\>cd files
|
||||
C:\FILES>cd sprdsht
|
||||
C:\FILES\SPRDSHT>dir
|
||||
Volume in drive C is FREEDOS2022
|
||||
Volume Serial Number is 333D-0B18
|
||||
|
||||
Directory of C:\FILES\SPRDSHT
|
||||
|
||||
. <DIR> 05-27-2022 9:59p
|
||||
.. <DIR> 05-27-2022 9:59p
|
||||
FIB WKS 2,093 05-27-2022 10:07p
|
||||
LAB1 WKS 2,087 05-27-2022 10:10p
|
||||
MIS100 WKS 2,232 05-27-2022 10:05p
|
||||
3 file(s) 6,412 bytes
|
||||
2 dir(s) 279,527,424 bytes free
|
||||
```
|
||||
|
||||
You don't have to navigate one directory at a time. You can instead provide the full directory path you want to change to, with one `CD` command:
|
||||
|
||||
```
|
||||
C:\>cd \files\sprdsht
|
||||
C:\FILES\SPRDSHT>dir
|
||||
Volume in drive C is FREEDOS2022
|
||||
Volume Serial Number is 333D-0B18
|
||||
|
||||
Directory of C:\FILES\SPRDSHT
|
||||
|
||||
. <DIR> 05-27-2022 9:59p
|
||||
.. <DIR> 05-27-2022 9:59p
|
||||
FIB WKS 2,093 05-27-2022 10:07p
|
||||
LAB1 WKS 2,087 05-27-2022 10:10p
|
||||
MIS100 WKS 2,232 05-27-2022 10:05p
|
||||
3 file(s) 6,412 bytes
|
||||
2 dir(s) 279,527,424 bytes free
|
||||
```
|
||||
|
||||
### D is for DELTREE
|
||||
|
||||
If you need to delete a single file, you can use the `DEL` command. To remove an empty directory, you can use the `RMDIR` or `RD` commands. But what if you want to delete a directory that has lots of files and subdirectories inside it?
|
||||
|
||||
A directory with other directories inside it is called a *directory tree*. You can delete an entire directory tree with the `DELTREE` command. For example, to delete your `FILES` directory, including all the files and directories it contains, type this command:
|
||||
|
||||
```
|
||||
C:\>deltree files
|
||||
|
||||
[DEFAULT-BUILD v1.02g] of DELTREE. The "ROOT-SAFETY-CHECK" is enabled.
|
||||
|
||||
Delete directory "C:\FILES"
|
||||
and all its subdirectories?
|
||||
|
||||
[Y] [N] [Q], [ENTER] ? Y
|
||||
|
||||
==> Deleting "C:\FILES" ...
|
||||
```
|
||||
|
||||
You can easily and quickly wipe out a lot of work with a single `DELTREE` command, so the FreeDOS `DELTREE` prompts you to ask if this is really something you want to do. Use this command carefully.
|
||||
|
||||
### E is for EDIT
|
||||
|
||||
If you need to edit a text file on FreeDOS, the `EDIT` program lets you do that quickly and easily. For example, to start editing a file called `HELLO.TXT`, type `EDIT HELLO.TXT`. If the `HELLO.TXT` file already exists, `EDIT` opens the file for editing. If `HELLO.TXT` doesn't exist yet, then `EDIT` starts a new file for you.
|
||||
|
||||
![Image of edit][3]
|
||||
|
||||
FreeDOS `EDIT` uses a friendly interface that should be easy for most people to use. Use the menus to access the various features of EDIT, including saving a file, opening a new file, or exiting the editor. To access the menus, tap the Alt key on your keyboard, then use the arrow keys to get around and Enter to select an action.
|
||||
|
||||
![Image of save menu][4]
|
||||
|
||||
### F is for FIND
|
||||
|
||||
If you need to find text in a file, the `FIND` command does the job. Similar to `fgrep` on Linux, `FIND` prints lines that contain a string. For example, to check the "Menu Default" entry in the `FDCONFIG.SYS` file, use `FIND` like this:
|
||||
|
||||
```
|
||||
C:\>find "MENUDEFAULT" fdconfig.sys
|
||||
|
||||
---------------- FDCONFIG.SYS
|
||||
MENUDEFAULT=2,5
|
||||
```
|
||||
|
||||
If you aren't sure if the string you want to find uses uppercase or lowercase letters, add the `/I` option to ignore the letter case:
|
||||
|
||||
```
|
||||
C:\>find /i "menudefault" fdconfig.sys
|
||||
---------------- FDCONFIG.SYS
|
||||
MENUDEFAULT=2,5
|
||||
```
|
||||
|
||||
### G is for GRAPHICS
|
||||
|
||||
If you want to capture a screen, you might use the **PrtScr** (Print Screen) key on your keyboard to print the text on your monitor directly to a printer. However, this only works for plain text. If you want to print graphic screens, you need to load the `GRAPHICS` program.
|
||||
|
||||
`GRAPHICS` supports different printer types, including HP PCL printers, Epson dot matrix printers, and PostScript-compatible printers. For example, if you have an HP laser printer connected to your computer, you can load support for that printer by typing this command:
|
||||
|
||||
```
|
||||
C:\>graphics hpdefault
|
||||
Running in MS GRAPHICS compatibility mode...
|
||||
Using HPPCL type for type hpdefault
|
||||
If you think this is not correct, mail me (see help text).
|
||||
Printing black as white and white as black
|
||||
which internally uses /I of this GRAPHICS.
|
||||
You can use the following command directly instead of
|
||||
GRAPHICS [your options] in the future:
|
||||
LH GRAPH-HP /I
|
||||
Note that GRAPH-HP allows extra options:
|
||||
/E economy mode, /1 use LPT1, /2 use LPT2, /3 use LPT3,
|
||||
/R for random instead of ordered dither
|
||||
/C for 300dpi instead of 600dpi
|
||||
Driver to make 'shift PrtScr' key work
|
||||
even in CGA, EGA, VGA, MCGA graphics
|
||||
modes loaded, in HP PCL mode.
|
||||
```
|
||||
|
||||
### H is for HELP
|
||||
|
||||
If you're new to FreeDOS, you can get hints on how to use the different commands by typing `HELP`. This brings up the FreeDOS Help system, with documentation on all the commands:
|
||||
|
||||
![Image of FreeDos help system][6]
|
||||
|
||||
### I is for IF
|
||||
|
||||
You can add conditional statements to your command line or *batch file* using the `IF` statement. `IF` makes a simple test, then executes a single command. For example, to print the result "It's there" if a certain file exists, you can type:
|
||||
|
||||
```
|
||||
C:\>if exist kernel.sys echo It's there
|
||||
It's there
|
||||
```
|
||||
|
||||
If you want to test the opposite, use the `NOT` keyword before the test. For example, to print "Not equal" if two strings are not the same value, type this:
|
||||
|
||||
```
|
||||
C:\>if not "a"=="b" echo Not equal
|
||||
Not equal
|
||||
```
|
||||
|
||||
### J is for JOIN
|
||||
|
||||
Early DOS versions were fairly simple; the first version of DOS didn't even support directories. To provide backwards compatibility for those older programs, we have the `JOIN` program as a neat workaround. `JOIN` replaces a path with a drive letter, so you can put an old program in its own subdirectory, but access it using a single drive letter.
|
||||
|
||||
Let's say you had an old application called `VC` that doesn't understand directories. To keep working with `VC`, you can "join" its path to a drive letter. For example:
|
||||
|
||||
```
|
||||
JOIN V: D:\VC
|
||||
```
|
||||
|
||||
FreeDOS implements `JOIN` as `SWSUBST`, which also combines features from the similar `SUBST` command. To join the `D:\VC` path to a new drive letter called `V:`, type:
|
||||
|
||||
```
|
||||
C:\>swsubst v: d:\vc
|
||||
C:\>dir v:
|
||||
Volume in drive V is DATA
|
||||
Volume Serial Number is 212C-1DF8
|
||||
|
||||
Directory of V:\
|
||||
|
||||
. <DIR> 02-21-2022 10:35p
|
||||
.. <DIR> 02-21-2022 10:35p
|
||||
VC COM 27,520 07-14-2019 4:48p
|
||||
|
||||
1 file(s) 27,520 bytes
|
||||
2 dir(s) 48,306,176 bytes free
|
||||
```
|
||||
|
||||
### K is for KEYB
|
||||
|
||||
DOS assumes a US keyboard layout by default. If your keyboard is different, you can use the `KEYB` command to load a new keyboard language layout. For example, to load a German keyboard layout, type:
|
||||
|
||||
```
|
||||
C:\>keyb gr
|
||||
FreeDOS KEYB 2.01 - (c) Aitor Santamaría Merino - GNU GPL 2.0
|
||||
Keyboard layout : C:\FREEDOS\BIN\KEYBOARD.SYS:GR [858] (3)
|
||||
```
|
||||
|
||||
### L is for LABEL
|
||||
|
||||
FreeDOS names each floppy drive and hard drive with a *label*. These labels provide a handy way to identify what a disk might contain. The `LABEL` command was immensely useful when you needed store files across a number of different floppy disks, where you might label one floppy "Data" and another floppy as "Games."
|
||||
|
||||
To assign a new label to a drive, or to change the existing label on a drive, use LABEL like this:
|
||||
|
||||
```
|
||||
D:\>label d: data
|
||||
D:\>dir /w
|
||||
Volume in drive D is DATA
|
||||
Volume Serial Number is 212C-1DF8
|
||||
|
||||
Directory of D:\
|
||||
|
||||
[123] [ABILITY] [ASEASY] [GAMES2] [QUATTRO]
|
||||
[SRC] [TEMP] [THE] [VC] [WORD]
|
||||
[WS400] EDLIN16.EXE EDLIN32.EXE MYENV.BAT
|
||||
3 file(s) 113,910 bytes
|
||||
11 dir(s) 48,306,176 bytes free
|
||||
```
|
||||
|
||||
### M is for MEM
|
||||
|
||||
Running programs and loading drivers takes memory. To see how much memory your system has, and how much memory is free for running DOS programs, use the `MEM` command:
|
||||
|
||||
```
|
||||
C:\>mem
|
||||
|
||||
Memory Type Total Used Free
|
||||
---------------- -------- -------- --------
|
||||
Conventional 639K 11K 628K
|
||||
Upper 104K 18K 86K
|
||||
Reserved 281K 281K 0K
|
||||
Extended (XMS) 15,224K 537K 14,687K
|
||||
---------------- -------- -------- --------
|
||||
Total memory 16,248K 847K 15,401K
|
||||
|
||||
Total under 1 MB 743K 29K 714K
|
||||
|
||||
Total Expanded (EMS) 8,576K (8,781,824 bytes)
|
||||
Free Expanded (EMS) 8,192K (8,388,608 bytes)
|
||||
|
||||
Largest executable program size 628K (643,104 bytes)
|
||||
Largest free upper memory block 84K ( 85,728 bytes)
|
||||
FreeDOS is resident in the high memory area.
|
||||
```
|
||||
|
||||
### N is for NANSI
|
||||
|
||||
If you want to add a little color to the FreeDOS command line, you can use ANSI escape sequences. These sequences are so named because each starts with code 33 (the `ESC` character) and a special sequence of characters, as defined by the American National Standards Institute, or ANSI.
|
||||
|
||||
FreeDOS supports ANSI escape sequences through the `NANSI.SYS` driver. With `NANSI` loaded, your FreeDOS console interprets the ANSI escape sequences, such as setting the text colors.
|
||||
|
||||
![Image of Nansi][8]
|
||||
|
||||
### O is for oZone
|
||||
|
||||
FreeDOS is a command line operating system, but some folks prefer to use a graphical user interface instead. That's why FreeDOS 1.3 includes several graphical desktops. One desktop I like is called oZone, which provides a sleek, modern-looking interface.
|
||||
|
||||
![Image of Ozone GUI][9]
|
||||
|
||||
Note that oZone has a few annoying bugs, and could use some love from a developer out there. If you're interested in making oZone even better, feel free to download the source code.
|
||||
|
||||
### P is for PROMPT
|
||||
|
||||
The standard FreeDOS command-line prompt tells you where you are in the filesystem. When you first boot FreeDOS, your prompt looks like `C:\>`, which means the "\" (root) directory on the "C:" drive. The ">" character indicates where you can type a command.
|
||||
|
||||
If you prefer different information on your prompt, use the `PROMPT` command to change it. You can represent different information with a special code preceded with `$`, such as `$D` for the date and `$T` for the time. For example, you can make your FreeDOS command line look like a Linux prompt with the `$$` instruction, to print a single dollar sign:
|
||||
|
||||
```
|
||||
C:\>prompt $$
|
||||
$
|
||||
```
|
||||
|
||||
Type `PROMPT /?` to see a list of all special codes.
|
||||
|
||||
### Q is for QBASIC
|
||||
|
||||
FreeDOS doesn't actually have QBASIC. That was a proprietary BASIC programming environment for MS-DOS. Instead, we provide several open source compilers, including some for BASIC programming.
|
||||
|
||||
The FreeBASIC Compiler should compile most QBASIC programs out there. Here's a simple "guess the number" example:
|
||||
|
||||
```
|
||||
dim number as integer
|
||||
dim guess as integer
|
||||
randomize timer
|
||||
number = int( 10 * rnd() ) + 1
|
||||
print "Guess the number from 1 to 10:"
|
||||
do
|
||||
input guess
|
||||
if guess < number then print "Too low"
|
||||
if guess > number then print "Too high"
|
||||
loop while guess <> number
|
||||
print "That's right!"
|
||||
```
|
||||
|
||||
Use the `FBC` command to compile the program with FreeBASIC:
|
||||
|
||||
```
|
||||
C:\DEVEL\FBC>fbc guess.bas
|
||||
```
|
||||
|
||||
Here's a quick demonstration of that simple game:
|
||||
|
||||
```
|
||||
C:\DEVEL\FBC>guess
|
||||
Guess the number from 1 to 10:
|
||||
? 5
|
||||
Too high
|
||||
? 3
|
||||
Too low
|
||||
? 4
|
||||
That's right!
|
||||
```
|
||||
|
||||
### R is for REM
|
||||
|
||||
Comments are great when writing programs; comments help us understand what the program is supposed to do. You can do the same in batch files using the `REM` command. Anything after the `REM` is ignored in a batch file.
|
||||
|
||||
```
|
||||
REM this is a comment
|
||||
```
|
||||
|
||||
### S is for SET
|
||||
|
||||
The FreeDOS command line uses a set of variables called *environment variables* that let you customize your system. You can set these variables with the `SET` command. For example, use the `DIRCMD` variable to control how `DIR` arranges directory listings. To set the `DIRCMD` variable, use the `SET` command:
|
||||
|
||||
```
|
||||
SET DIRCMD=/O:GNE
|
||||
```
|
||||
|
||||
This tells `DIR` to order (O) the output by grouping (G) directories first, then sorting the results by name (N) and extension (E).
|
||||
|
||||
### T is for TYPE
|
||||
|
||||
The `TYPE` command is one of the most-often used DOS commands. `TYPE` displays the contents of a file, similar to `cat` on Linux.
|
||||
|
||||
```
|
||||
C:\DEVEL>type hello.c
|
||||
#include
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
puts("Hello world");
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### U is for UNZIP
|
||||
|
||||
On Linux, you may be familiar with the standard Unix archive command: `tar`. There's a version of tar on FreeDOS too (and a bunch of other popular archive programs), but the de facto standard archiver on DOS is `ZIP` and `UNZIP`. Both are installed in FreeDOS 1.3 by default.
|
||||
|
||||
Let's say I had a zip archive of some files. If I want to extract the entire Zip file, I could just use the `UNZIP` command and provide the Zip file as a command-line option. That extracts the archive starting at my current working directory. Unless I'm restoring a previous version of something, I usually don't want to overwrite my current files. In that case, I will want to extract the archive to a new directory. You can specify the destination path with the `-d` ("destination") command-line option:
|
||||
|
||||
```
|
||||
D:\SRC>unzip monkeys.zip -d monkeys.new
|
||||
Warning: TZ environment variable not found, cannot use UTC times!!
|
||||
Archive: monkeys.zip
|
||||
creating: monkeys.new/monkeys/
|
||||
inflating: monkeys.new/monkeys/banana.c
|
||||
inflating: monkeys.new/monkeys/banana.obj
|
||||
inflating: monkeys.new/monkeys/banana.exe
|
||||
creating: monkeys.new/monkeys/putimg/
|
||||
inflating: monkeys.new/monkeys/putimg/putimg.c
|
||||
inflating: monkeys.new/monkeys/putimg/putimg.obj
|
||||
inflating: monkeys.new/monkeys/putimg/putimg.exe
|
||||
```
|
||||
|
||||
To learn more about the `ZIP` and `UNZIP` commands, read [How to archive files on FreeDOS][11].
|
||||
|
||||
### V is for VER
|
||||
|
||||
In the old days of DOS, the `VER` command reported the DOS distribution you were running, such as "MS-DOS 5.0.D" With FreeDOS, the `VER` command gives you additional details, such as the version of the FreeDOS Shell:
|
||||
|
||||
```
|
||||
C:\DEVEL>ver
|
||||
FreeCom version 0.85a - WATCOMC - XMS_Swap [Jul 10 2021 19:28:06]
|
||||
```
|
||||
|
||||
If you also want to see the FreeDOS kernel version and the DOS compatibility level, add the `/R` option:
|
||||
|
||||
```
|
||||
C:\DEVEL>ver /r
|
||||
|
||||
FreeCom version 0.85a - WATCOMC - XMS_Swap [Jul 10 2021 19:28:06]
|
||||
|
||||
DOS version 7.10
|
||||
FreeDOS kernel 2043 (build 2043 OEM:0xfd) [compiled May 14 2021]
|
||||
```
|
||||
|
||||
### W is for WHICH
|
||||
|
||||
The FreeDOS command line can run programs from a list of different directories, identified in a `PATH` variable. You can use the `WHICH` command to identify exactly where a program is located. Just type `WHICH` plus the name of the program you want to locate:
|
||||
|
||||
```
|
||||
C:\>which xcopy
|
||||
xcopy C:\FREEDOS\BIN\XCOPY.EXE
|
||||
```
|
||||
|
||||
### X is for XCOPY
|
||||
|
||||
The `COPY` command copies only files from one place to another. If you want to extend the copy to include any directories, use the `XCOPY` command instead. I usually add the `/E` option to include all subdirectories, including empty ones, so I can copy the entire directory tree. This makes an effective backup of any project I am working on:
|
||||
|
||||
```
|
||||
D:\SRC>xcopy /e monkeys monkeys.bak
|
||||
Does MONKEYS.BAK specify a file name
|
||||
or directory name on the target (File/Directory)? d
|
||||
Copying D:\SRC\MONKEYS\PUTIMG\PUTIMG.C
|
||||
Copying D:\SRC\MONKEYS\PUTIMG\PUTIMG.OBJ
|
||||
Copying D:\SRC\MONKEYS\PUTIMG\PUTIMG.EXE
|
||||
Copying D:\SRC\MONKEYS\BANANA.C
|
||||
Copying D:\SRC\MONKEYS\BANANA.OBJ
|
||||
Copying D:\SRC\MONKEYS\BANANA.EXE
|
||||
6 file(s) copied
|
||||
```
|
||||
|
||||
### Y is for Yellow
|
||||
|
||||
This isn't a command, but interesting trivia about how DOS displays colors. If you've looked carefully at FreeDOS, you've probably noticed that text only comes in a limited range of colors—sixteen text colors, and eight background colors.
|
||||
|
||||
The IBM 5153 color display presented color to the user by lighting up tiny red, green, and blue phosphor dots at different brightness levels to create a palette of 16 text colors and 8 background colors. Early PCs could only display the background color in the "normal intensity" level; only text colors could use bright colors.
|
||||
|
||||
If you look at the text colors, you have black, blue, green, cyan, red, magenta, orange, and white. The "bright" versions of these colors are bright black (a dull gray), bright blue, bright green, bright cyan, bright red, bright magenta, yellow, and bright white. The "bright" version of orange is actually yellow. There is no "bright orange."
|
||||
|
||||
If you want to learn more about text colors, read our article about [Why FreeDOS has 16 colors][12].
|
||||
|
||||
### Z is for ZIP
|
||||
|
||||
You can use `ZIP` at the DOS command line to create archives of files and directories. This is a handy way to make a backup copy of your work or to release a "package" to use in a future FreeDOS distribution. For example, let's say I wanted to make a backup of my project source code, which contains these source files:
|
||||
|
||||
```
|
||||
D:\SRC>zip -9r monkeys.zip monkeys
|
||||
zip warning: TZ environment variable not found, cannot use UTC times!!
|
||||
adding: monkeys/ (stored 0%)
|
||||
adding: monkeys/banana.c (deflated 66%)
|
||||
adding: monkeys/banana.obj (deflated 26%)
|
||||
adding: monkeys/banana.exe (deflated 34%)
|
||||
adding: monkeys/putimg/ (stored 0%)
|
||||
adding: monkeys/putimg/putimg.c (deflated 62%)
|
||||
adding: monkeys/putimg/putimg.obj (deflated 29%)
|
||||
adding: monkeys/putimg/putimg.exe (deflated 34%)
|
||||
```
|
||||
|
||||
ZIP sports a ton of command-line options to do different things, but the command line options I use most are `-r` to process directories and subdirectories recursively, and `-9` to provide the maximum compression possible. `ZIP` and `UNZIP` use a Unix-like command line, so you can combine options behind the dash: `-9r` gives maximum compression and include subdirectories in the Zip file.
|
||||
|
||||
For more details about how to use the `ZIP` and `UNZIP` commands, read [How to archive files on FreeDOS][13].
|
||||
|
||||
### New FreeDOS guides
|
||||
|
||||
Ready for the next step in your FreeDOS journey? Check out our new eBooks and start experimenting with FreeDOS now!
|
||||
|
||||
**[A guide to using FreeDOS][14]**
|
||||
|
||||
**[An advanced guide to FreeDOS internals][15]**
|
||||
|
||||
Image by: (Jim Hall, CC BY-SA 40)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/22/6/26-freedos-commands
|
||||
|
||||
作者:[Jim Hall][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/jim-hall
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/freedos-fish-laptop-color.png
|
||||
[2]: https://opensource.com/article/22/6/linux-attr-command
|
||||
[3]: https://opensource.com/sites/default/files/2022-06/FREEDedit_0.png
|
||||
[4]: https://opensource.com/sites/default/files/2022-06/Freededit-save.png
|
||||
[5]: https://opensource.com/Linux%20find%20cheat%20sheet
|
||||
[6]: https://opensource.com/sites/default/files/2022-06/Freedhelp.system.png
|
||||
[7]: https://opensource.com/article/22/6/linux-cheat-command
|
||||
[8]: https://opensource.com/sites/default/files/2022-06/FreeDnansi.png
|
||||
[9]: https://opensource.com/sites/default/files/2022-06/FreeDozone.png
|
||||
[10]: https://opensource.com/article/21/1/fortran
|
||||
[11]: https://opensource.com/article/21/6/archive-files-freedos
|
||||
[12]: https://opensource.com/article/21/6/freedos-sixteen-colors
|
||||
[13]: https://opensource.com/article/21/6/archive-files-freedos
|
||||
[14]: https://opensource.com/downloads/guide-using-freedos
|
||||
[15]: https://opensource.com/downloads/advanced-freedos
|
@ -0,0 +1,105 @@
|
||||
[#]: subject: "AI: Some History and a Lot More about Matrices"
|
||||
[#]: via: "https://www.opensourceforu.com/2022/06/ai-some-history-and-a-lot-more-about-matrices/"
|
||||
[#]: author: "Deepu Benson https://www.opensourceforu.com/author/deepu-benson/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
AI: Some History and a Lot More about Matrices
|
||||
======
|
||||
|
||||
![AI-Some-History-and-a-Lot-More-about-Matrices][1]
|
||||
|
||||
*In the first article on this series on AI (published in OSFY, June 2022), we discussed how fields like AI, machine learning, deep learning, data science, etc, are related yet distinct from each other. We also made a few difficult choices regarding the programming language, tools, etc, which will be used throughout this series. Finally, we started discussing matrices. In this article, we will discuss more about matrix theory, the heart of AI. But before we proceed any further, let us discuss the history of AI.*
|
||||
|
||||
first of all, why is a discussion on the history of AI essential? Well, there were a few times in history when there was great enthusiasm around research on AI, but on many of those occasions the huge expectations about the potential of AI went wrong. So, we need to learn some history of AI to understand whether this time we really are going to do wonders with AI or is it yet another bubble that is about to burst.
|
||||
|
||||
One important question that needs to be answered is: when did our fascination for artificial intelligence start? Was it after the invention of digital computers or did it start even before? I believe the quest for an omniscient being capable of answering all questions dates back to the beginning of civilisation. The Oracle of Delphi in the ancient times was one such supposedly divine being capable of answering all the queries asked by people. The quest for creative machines outwitting human intelligence was also fascinating to us from ancient times. There were several failed attempts to make machines capable of playing chess. For example, Mechanical Turk was an infamous fake chess playing machine constructed in the late 18th century. The inventions of logarithm by John Napier, the Pascal’s calculator by Blaise Pascal, difference engine by Charles Babbage, etc, were all predecessors to the development of artificial intelligence. Further, if you go through the history of mankind, you will find countless other real and imaginary (fake) moments hoping to achieve intelligence beyond the reach of the human brain. However, irrespective of all these achievements, the search for true AI began with the invention of digital computers.
|
||||
|
||||
However, if that is the case, the important question is: what were some of the milestones in the history of AI up until today? As mentioned earlier, the invention of digital computers is the single most significant event in the search for artificial intelligence. Unlike electro-mechanical devices where scalability was dependent on power requirements, digital devices simply benefited technological advancement like the transition from vacuum tubes to transistors to integrated circuits to present day very large-scale integration (VLSI) technology.
|
||||
|
||||
Another important phase in the development of AI could be traced back to the first theoretical analysis of AI by Allan Turing. The Turing test proposed by him suggests one of the earliest methods to test artificial intelligence. The test may not be relevant today but it was one of the first attempts to define artificial intelligence. It can be summarised as follows. Behind a curtain, there is either a person named A or a machine named B. You can talk with him/it for say 30 minutes, after which you should be able to identify whether you were conversing with a person or a machine. With the powerful chatbots of today, it is easy to see that such a test will not identify true AI. But in the early 1950s this did give a theoretical framework to understand AI.
|
||||
|
||||
In the late 1950s, a programming language called Lisp was developed by John McCarthy. This was one of the earliest high-level programming languages. Until then, machine languages and assembly languages (notoriously difficult to use) were used for computer programming. A very powerful machine, a very powerful language to communicate with it, and computer scientists being the optimists and dreamers made the hope for artificially intelligent machines reasonable for the first time in the history of humanity. In the early 1960s, the hopes for artificially intelligent machines were at their peak. Of course, there were a lot of developments in the computing world, but were there any wonders? Sadly, no. So, the 1960s saw hope and despair about AI for the first time. However, computer science was developing at a pace that is unparalleled in any field of human endeavour.
|
||||
|
||||
Then came the 70s and the 80s, where algorithms played a major role. A lot of new and efficient algorithms were developed during this period. The famous textbook ‘The Art of Computer Programming’ written by Donald Knuth (I request you to read about this person, in the world of computer science he is either Gauss or Euler) had its first volume published in the late 1960s marking the beginning of the algorithmic era. A lot of general and graph algorithms were developed during these years. Further, programming based on artificial neural networks was also introduced during this time. Though McCulloch and Pitts were the pioneers in proposing artificial neural networks as far back as the 1940s, it took decades to become a mainstream technique. Today, deep learning is almost exclusively based on artificial neural networks. Such developments in the field of algorithms led to a resurgence in research in the field of artificial intelligence in the 1980s. However, this time, limitations in communication and computing powers derailed progress in this area. For a second time, AI couldn’t live up to the huge expectations it had generated. Then came the 90s, Y2K, and the present day. Once again there is a lot of enthusiasm and hope about the positive impact of AI based applications.
|
||||
|
||||
Based on our discussion, it is easy to see that there were at least two other occasions in the digital era when AI was promising. On both those occasions AI didn’t live up to its expectations. Is the current enthusiasm around AI a similar one? Of course, this is a very difficult question to answer. But in my personal opinion, this time AI is going to make a huge impact. But what are the factors that made me make such a prediction? First, very powerful computing devices are cheaply available nowadays. Unlike in the 1960s or 1980s, when a handful of such powerful machines were available, we now have them in the millions and billions. Second, there are large data sets available today for training AI and machine learning based applications. Imagine an AI engineer working in the field of digital image processing in the 90s. How many digital images were available for training his/her algorithms? Well, maybe a few thousands or tens of thousands. A cursory search on the Internet will tell you that the data science platform Kaggle (a subsidiary of Google) itself has more than ten thousand data sets. The large amount of data produced on the Internet every day makes training of algorithms a lot easier. Third, high speed connectivity has made it easy to collaborate with large groups. Imagine the difficulty of computer scientists collaborating with each other until the first decade of the 21st century. The present day speed of the Internet has made collaborative AI based projects like Google Colab, Kaggle, Project Jupyter, etc, a reality. Owing to these three factors, I believe this time AI is here for good and will have some excellent applications.
|
||||
|
||||
![Matrices A, B, C and D][2]
|
||||
|
||||
### More about matrices
|
||||
|
||||
Now that we are somewhat familiar with the history of AI, it is time to revisit one of the main themes of this tutorial on AI — matrices and vectors. In the last article, we began discussing these. This time we are going to dive a little deeper into the world of matrix theory. I will begin by pointing your attention to Figures 1 and 2, which show eight matrices (A, B, C and D, and matrices E, F, G and H). Why so many matrices in a tutorial on AI and machine learning? First, as mentioned in the previous article in this series, matrices are the core of linear algebra, and linear algebra is the heart of machine learning, if not the brain. Second, each of these matrices does serve a specific purpose in the following discussion.
|
||||
|
||||
![Matrices E, F, G and H][3]
|
||||
|
||||
Let us see how matrices can be represented and how some details about them can be obtained. Figure 3 shows how matrix A is represented with NumPy. Though they are not equivalent, we use the terms matrix and array as if they are synonyms.
|
||||
|
||||
![Matrix A with NumPy][4]
|
||||
|
||||
I urge you to carefully learn how a matrix is created using the function array of NumPy. There is also a function matrix offered by NumPy to create two-dimensional arrays and matrices. However, this function will be deprecated in the future and its use is no longer encouraged. We have created matrix A and Figure 3 also shows some details about it. The line of code A.size tells us about the number of elements in the array. In this case, it is 9. The line of code A.nidm tells the dimension of the array. In this case, it is easy to see that matrix A is two-dimensional. The line of code A.shape gives us the order of matrix A. The order of a matrix is the number of rows and columns of that matrix. Notice that A is a 3 x 3 matrix (3 rows and 3 columns). Though I am not explaining any further, knowing the size, dimension, and shape of an array is a little tricky with NumPy. Figure 4 shows you why the size, dimension and shape of a matrix should be identified carefully. Minor changes while defining an array could lead to changes in its size, shape, and dimension. Hence, from Figure 4, it is clear that a programmer should be extra careful while defining matrices.
|
||||
|
||||
![Size, dimension and shape of an array][5]
|
||||
|
||||
Now let us perform some basic matrix operations. Figure 5 shows how two matrices A and B are added. Indeed, there are two distinct Pythonic ways to add the two matrices, either using the function add of NumPy or the operator plus (+) for matrix addition. A very important point to remember is that two matrices can be added only if they are of the same order. For example, two 4 x 3 matrices can be added whereas a 3 x 4 matrix and a 2 x 3 matrix cannot be added. However, since programming is different from mathematics, NumPy does not follow this rule in practice. Figure 5 also shows how matrices A and D are added. Remember that, in the mathematical world, this sort of matrix addition is not valid. A rule called broadcasting decides how matrices of different orders should be added. We won’t be discussing broadcasting at this point but if you are familiar with C or C++, then typecasting of variables might give you a hint as to what happens when broadcasting rules are applied in Python. So, if you want to make sure that you are performing matrix addition in the true mathematical sense, it would be safe if the following test is performed and the answer is True:
|
||||
|
||||
![Matrix addition][6]
|
||||
|
||||
```
|
||||
A.shape == B.shape
|
||||
```
|
||||
|
||||
It can be verified that if you try to add matrices D and H, then it will give you an error.
|
||||
|
||||
Please don’t think that matrix addition is the only operation we are going to spend time on. Of course, there are a lot more matrix operations. Matrix subtraction and multiplication are illustrated in Figure 6. Notice that subtraction and multiplication also have two distinct Pythonic ways to perform the required operations. The function subtract or the operator for matrix subtraction (-) and the function matmul or the operator for matrix multiplication (@), can be used for performing matrix subtraction and multiplication, respectively. Execution of the operator * is also shown in Figure 3. Notice that the function matmul of NumPy and the operator @ perform matrix multiplication in the mathematical sense. So, be careful with the operator * while dealing with matrices.
|
||||
|
||||
![More matrix operations][7]
|
||||
|
||||
Two matrices of order (m x n) and (p x q) can be multiplied if and only if n is equal to p. Further, the product matrix will be of order (m x q). Figure 7 shows more examples of matrices being multiplied. Notice that E@A is possible whereas A@E leads to an error. Carefully go through the examples of D@G and G@D. Using the shape attribute, identify which among the eight matrices can be multiplied with each other. Though by the strict mathematical definition, a matrix is two-dimensional, we will be dealing with arrays of higher dimensions. So, just to give an example, let us see how a three-dimensional array is represented using NumPy. The following line of code creates a three-dimensional array named T.
|
||||
|
||||
![More examples of matrix multiplication][8]
|
||||
|
||||
```
|
||||
T = np.arr ay([[[11,22],[33,44]],[[55,66],[77,88]]])
|
||||
```
|
||||
|
||||
### An introduction to Pandas
|
||||
|
||||
So far, we were entering matrices from the keyboard. What if we want to read a large matrix from a text file or a data set (very large for that matter) and process it? Here comes another powerful Python library to our rescue, Pandas. Let us begin by reading a small CSV (comma-separated value) file, which is a type of text file (don’t worry, soon we will read Microsoft Excel and LibreOffice/OpenOffice Calc files). Figure 8 shows how a CSV file called cricket.csv is read, and the first three lines in it are printed on the terminal. More features of Pandas will be discussed in the coming articles in this series.
|
||||
|
||||
![Reading a CSV file with Pandas][9]
|
||||
|
||||
### Rank of a matrix
|
||||
|
||||
The rank of a matrix is the dimension of the vector space spanned by its rows (columns). The three italicised words, dimension, vector space and spanned, may not be familiar to you unless you remember your college level linear algebra. If you fully understand what is meant by the rank of a matrix, I am happy and no further explanation is required. However, if you are not familiar with the terms, think of it as the amount of information contained in the matrix. Again, this is a gross oversimplification and I am not proud of it. Figure 9 shows how the ranks of matrices are found out. Matrix A has rank 3 because none of its rows can be obtained from any other rows in it. Matrix B’s rank is just 1, because the second and third rows can be obtained by multiplying the first row ([1, 2, 3]) with 2 and 3, respectively. Matrix C only has one non-zero row and hence has rank 1. Similarly, the ranks of the other matrices can also be understood. Rank is very relevant in our discussion and we will revisit this topic in later articles in this series.
|
||||
|
||||
![Finding the rank of a matrix][10]
|
||||
|
||||
Now it is time for us to wind up our discussion for this month. In the next article in this series, we will add more tools to our arsenal so that they can be used for developing AI and machine learning based applications. We will also discuss terms like neural networks, supervised learning, unsupervised learning, etc, in more detail. Further, from the next article onwards, we will use JupyterLab in place of the Linux terminal.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.opensourceforu.com/2022/06/ai-some-history-and-a-lot-more-about-matrices/
|
||||
|
||||
作者:[Deepu Benson][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/deepu-benson/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://www.opensourceforu.com/wp-content/uploads/2022/06/AI-Some-History-and-a-Lot-More-about-Matrices-1.jpg
|
||||
[2]: https://www.opensourceforu.com/wp-content/uploads/2022/06/Figure-1-Matrices-A-B-C-and-D.jpg
|
||||
[3]: https://www.opensourceforu.com/wp-content/uploads/2022/06/Figure-2-Matrices-E-F-G-and-H.jpg
|
||||
[4]: https://www.opensourceforu.com/wp-content/uploads/2022/06/Figure-3-Matrix-A-with-NumPy-350x167.jpg
|
||||
[5]: https://www.opensourceforu.com/wp-content/uploads/2022/06/Figure-4-Size-dimension-and-shape-of-an-array-350x292.jpg
|
||||
[6]: https://www.opensourceforu.com/wp-content/uploads/2022/06/Figure-5-Matrix-addition-350x314.jpg
|
||||
[7]: https://www.opensourceforu.com/wp-content/uploads/2022/06/Figure-6-More-matrix-operations-1-350x375.jpg
|
||||
[8]: https://www.opensourceforu.com/wp-content/uploads/2022/06/Figure-7-More-examples-of-matrix-multiplication-590x293.jpg
|
||||
[9]: https://www.opensourceforu.com/wp-content/uploads/2022/06/Figure-8-Reading-a-CSV-file-with-Pandas-350x123.jpg
|
||||
[10]: https://www.opensourceforu.com/wp-content/uploads/2022/06/Figure-9-Finding-the-rank-of-a-matrix-350x366.jpg
|
@ -0,0 +1,253 @@
|
||||
[#]: subject: "DIY Embroidery with Inkscape and Ink/Stitch"
|
||||
[#]: via: "https://fedoramagazine.org/diy-embroidery-with-inkscape-and-ink-stitch/"
|
||||
[#]: author: "Benson Muite https://fedoramagazine.org/author/fed500/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
DIY Embroidery with Inkscape and Ink/Stitch
|
||||
======
|
||||
![][1]
|
||||
|
||||
Picture http://commons.wikimedia.org/wiki/User:Ryj, CC BY-SA 3.0 http://creativecommons.org/licenses/by-sa/3.0/, via Wikimedia Commons
|
||||
|
||||
### Introduction
|
||||
|
||||
Embroidered shirts are great custom gifts and can also be a great way to show your love for open source. This tutorial will demonstrate how to design your own custom embroidered polo shirt using [Inkscape][2] and [Ink/Stitch][3]. Polo shirts are often used for embroidery because they do not tear as easily as t-shirts when pierced by embroidery needles, though with care t-shirts can also be embroidered. This tutorial is a follow on article to [Make More with Inkscape and Ink/Stitch][4] and provides complete steps to create your design.
|
||||
|
||||
### Logo on Front of Shirt
|
||||
|
||||
Pictures with only a few colors work well for embroidery. Let us use a public domain black and white [SVG][5] image of [Tux][6] created by [Ryan Lerch][7] and [Garret LeSage][8].
|
||||
|
||||
![Black and white image of Tux][9]
|
||||
|
||||
Download this public domain image, [tux-bw.svg][10], to your computer, and import it into your document as an editable SVG image using File>Import...
|
||||
|
||||
![Image of Tux with text to be embroidered][11]
|
||||
|
||||
### Use a Transparent Background
|
||||
|
||||
It is helpful to have a checkerboard background to distinguish background and foreground colors. Click File>Document Properties… and then check the box to enable a checkerboard background.
|
||||
|
||||
![Dialog box to enable checkerboard document background][12]
|
||||
|
||||
Then close the document properties dialog box. You can now distinguish between colors used on Tux and the background color.
|
||||
|
||||
![Tux can be distinguished from the document background][13]
|
||||
|
||||
### Use a Single Color For Tux
|
||||
|
||||
Type s to use the Select and Transform objects tool, and click on the image of Tux to select it. Then click on Object>Fill and Stroke, in the menu. Type n to use the Edit paths by Nodes tool and click on a white portion of Tux. Within the Fill and Stroke pane change the fill to No paint to make this portion of Tux transparent.
|
||||
|
||||
![Tux in one color][14]
|
||||
|
||||
Thi leaves the black area to be embroidered.
|
||||
|
||||
### Enable Embroidering of Tux
|
||||
|
||||
Now convert the image for embroidery. Type s to use the Select and Transform objects tool and click on the image of Tux to select it again. Choose Extensions>Ink/Stitch>Fill Tools>Break Apart Fill Objects … In the resulting pop up, choose Complex, click Apply, and wait for the operation to complete.
|
||||
|
||||
![Dialog to Break Apart Fill Objects][15]
|
||||
|
||||
For further explanation of this operation, see the [Ink/Stitch documentation][16].
|
||||
|
||||
### Resize Document
|
||||
|
||||
Now resize the area to be embroidered. A good size is about 2.75 inches by 2.75 inches. Press s to use the Select and Transform objects tool, and select Tux, hold down the shift key, and also select any text area. Then choose Object>Transform …, click on Scale in the dialogue box, change the measurements to inches, check the Scale proportionally box and choose a width of 2.75 inches, and click Apply.
|
||||
|
||||
![Resized drawing][17]
|
||||
|
||||
Before saving the design, reduce the document area to just fit the image. Press s to use the Select and Transform objects tool, then select Tux.
|
||||
|
||||
![Objects selected to determine resize area][18]
|
||||
|
||||
Choose File>Document Properties… then choose Resize to content: or press Ctrl+Shift+R
|
||||
|
||||
![Dialog to resize page][19]
|
||||
|
||||
The document is resized.
|
||||
|
||||
![Resized document][20]
|
||||
|
||||
### Save Your Design
|
||||
|
||||
You now need to convert your file to an embroidery file. A very portable format is the [DST (Tajima Embroidery Format)][21] format, which unfortunately does not have color information, so you will need to indicate color information for the embroidery separately. First save your design as an Inkscape SVG file so that you retain a format that you can easily edit again. Choose File>Save As, then select the Inkscape SVG format and enter a name for your file, for example AnotherAwesomeFedoraLinuxUserFront.svg and save your design. Then choose File>Save As and select the DST file format and save your design. Generating this file requires calculation of stitch locations, this may take a few seconds. You can preview the DST file in Inkscape, but another very useful tool is [vpype-embroidery][22]
|
||||
|
||||
Install vpype-embroidery on the command line using a [Python virtual environment][23] via the following commands:
|
||||
|
||||
```
|
||||
virtualenv test-vpype
|
||||
source test-vpype/bin/activate
|
||||
pip install matplotlib
|
||||
pip install vpype-embroidery
|
||||
pip install vpype[all]
|
||||
```
|
||||
|
||||
Preview your DST file (in this case named AnotherAwesomeFedoraLinuxUserFront.dst which should be replaced by the filename you choose if it is different), using this command:
|
||||
|
||||
```
|
||||
vpype eread AnotherAwesomeFedoraLinuxUserFront.dst show
|
||||
```
|
||||
|
||||
![Image of Tux created from the DST file and shown using Vpype-embroider][24]
|
||||
|
||||
Check the dimensions of your design, if you need to resize it, you should resize the SVG design file before exporting it as a DST file. Resizing the DST file is not recommended since it contains stitch placement information, regenerate this placement information from the resized SVG file to obtain a high quality embroidered result.
|
||||
|
||||
### Text on the Back of the Shirt
|
||||
|
||||
Now create a message to put on the back of your polo shirt. Create a new Inkscape document using File>New. Then choose Extensions>Ink/Stitch>Lettering.Choose a font, for example Geneva Simple Sans created by [Daniel K. Schneider][25] in Geneva. If you want to resize your text, do so at this point using the scale section of the dialog box since resizing it once it is in Inkscape will distort the resulting embroidered pattern. Add your text,
|
||||
|
||||
```
|
||||
Another Awesome
|
||||
Fedora Linux User
|
||||
```
|
||||
|
||||
![Image showing the text, Another Awesome Fedora Linux User, in a dialog box along with the choosen embroidery font, Geneva Simple Sans][26]
|
||||
|
||||
A preview will appear, click on Quit
|
||||
|
||||
![Preview of stitches for the text, Another Awesome Fedora Linux User, created by Ink/Stitch][27]
|
||||
|
||||
Then click on Apply and Quit in the lettering creation dialog box. Your text should appear in your Inkscape document.
|
||||
|
||||
![Text to be embroidered in the top left corner of an otherwise empty Inkscape document][28]
|
||||
|
||||
Create a checkered background and resize the document to content by opening up the document properties dialog box File>Document Properties…
|
||||
|
||||
![Document properties dialog box to resize a document][29]
|
||||
|
||||
Your document should now be a little larger than your text.
|
||||
|
||||
![Document is a little larger than the text][30]
|
||||
|
||||
#### Clean Up Stitches
|
||||
|
||||
Many commercial embroidery machines support jump instructions which can save human time in finishing the embroidered garment. Examine the text preview image. A single continuous thread sews all the letters. Stitches joining the letters are typically removed. These stitches can either be cut by hand after the embroidery is done, or they can be cut by the embroidery machine if it supports jump instructions. Ink/Stitch can add these jump instructions.
|
||||
|
||||
Add jump instructions by selecting View>Zoom>Zoom Page to enlarge the view of the drawing. Press s to choose the Select and transform objects tool. Choose Extensions>Ink/Stitch>Commands>Attach Commands to Selected Objects. A dialog box should appear, check just the Trim thread after sewing this object option.
|
||||
|
||||
![Attach commands dialog][31]
|
||||
|
||||
Then click in the drawing area and select the first letter of the text
|
||||
|
||||
![Select first letter of the text][32]
|
||||
|
||||
Then click Apply, and some cut symbols should appear above the letter.
|
||||
|
||||
![Scissor symbols above first letter][33]
|
||||
|
||||
Repeat this process for all letters.
|
||||
|
||||
![Separately embroidered letters][34]
|
||||
|
||||
Now save your design, as before, in both SVG and DST formats. Check the likely quality of the embroidered text by previewing your DST file (in this case named AnotherAwesomeFedoraLinuxUserBack.dst – replaced this by the filename you chose), using
|
||||
|
||||
```
|
||||
vpype eread AnotherAwesomeFedoraLinuxUserBack.dst show
|
||||
```
|
||||
|
||||
![Illustration showing a green stitch pattern that forms the txt, Another Awesome Fedora Linux User][35]
|
||||
|
||||
Check the dimensions of your design, if you need to resize it, you should resize the SVG design file before exporting it as a DST file.
|
||||
|
||||
### Create a Mockup
|
||||
|
||||
To show the approximate placement of your design on the polo shirt create a mockup. You can then send this to an embroidery company with your DST file. The Fedora Design Team has a wiki [page][36] with examples of mockups. An example mockup made using [Kolourpaint][37] is below.
|
||||
|
||||
![Mockup image of polo shirt with design][38]
|
||||
|
||||
You can also use an appropriately licensed drawing of a polo shirt, for example from [Wikimedia Commons][39].
|
||||
|
||||
### Example Shirt
|
||||
|
||||
Pictures of a finished embroidered polo shirt are below
|
||||
|
||||
![Embroidered black polo shirt front with white thread used to embroider Tux][40]
|
||||
|
||||
![Back of black polo shirt, with white embroidered text][41]
|
||||
|
||||
![Closeup of the front left of a person wearing a black polo shirt with Tux embroidered on it with white thread.][42]
|
||||
|
||||
![Back of person wearing a polo shirt with the text, Another Awesome Fedora Linux User, embroidered on the shirt][43]
|
||||
|
||||
### Further Information
|
||||
|
||||
A three color image of Tux is also [available][44], but single colors are easiest to achieve good embroidered results with. Adaptation of this shaded multiple color image is required to use it for embroidery. Additional tutorial information is available on the [Ink/Stitch website][45].
|
||||
|
||||
Some companies that can do embroidery given a DST file include:
|
||||
|
||||
* [Pappagallo Clothing Industry][46] based in Cyprus
|
||||
* [Target Solutions][47] based in Ghana
|
||||
* [Marvel Ark][48] based in Kenya
|
||||
* [Core Digital][49] based in South Africa
|
||||
* [Embroidery Your Way][50] based in the USA
|
||||
|
||||
Search the internet for machine embroidery services close to you or a hackerspace with an embroidery machine you can use.
|
||||
|
||||
This article has benefited from many helpful suggestions from Michael Njuguna of Marvel Ark and Brian Lee of Embroidery Your Way.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/diy-embroidery-with-inkscape-and-ink-stitch/
|
||||
|
||||
作者:[Benson Muite][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://fedoramagazine.org/author/fed500/
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2022/06/DIY-Embroidery-with-Inkscape-and-InkStitch-816x345.jpg
|
||||
[2]: https://inkscape.org
|
||||
[3]: https://inkstitch.org/
|
||||
[4]: https://fedoramagazine.org/make-more-with-inkscape-ink-stitch/
|
||||
[5]: https://en.wikipedia.org/wiki/Scalable_Vector_Graphics
|
||||
[6]: https://github.com/garrett/Tux/blob/main/tux-bw.svg
|
||||
[7]: https://github.com/ryanlerch
|
||||
[8]: https://github.com/garrett
|
||||
[9]: https://fedoramagazine.org/wp-content/uploads/2022/06/tux-bw.svg
|
||||
[10]: https://raw.githubusercontent.com/garrett/Tux/main/tux-bw.svg
|
||||
[11]: https://fedoramagazine.org/wp-content/uploads/2022/06/TuxInDocument-1.png
|
||||
[12]: https://fedoramagazine.org/wp-content/uploads/2022/06/ResizeDialog-2.png
|
||||
[13]: https://fedoramagazine.org/wp-content/uploads/2022/06/TuxCheckeredBackground-1.png
|
||||
[14]: https://fedoramagazine.org/wp-content/uploads/2022/06/TuxOneColor-1.png
|
||||
[15]: https://fedoramagazine.org/wp-content/uploads/2022/06/BreakApartFill.png
|
||||
[16]: https://inkstitch.org/docs/fill-tools/
|
||||
[17]: https://fedoramagazine.org/wp-content/uploads/2022/06/ResizedDrawing-1.png
|
||||
[18]: https://fedoramagazine.org/wp-content/uploads/2022/06/DetermineResizeArea-1.png
|
||||
[19]: https://fedoramagazine.org/wp-content/uploads/2022/06/ResizeDialog-1.png
|
||||
[20]: https://fedoramagazine.org/wp-content/uploads/2022/06/ResizedDocument-1.png
|
||||
[21]: https://edutechwiki.unige.ch/en/Embroidery_format_DST
|
||||
[22]: https://github.com/embroidepy/vpype-embroidery/
|
||||
[23]: https://docs.python.org/3/library/venv.html
|
||||
[24]: https://fedoramagazine.org/wp-content/uploads/2022/06/VpypePreviewFront.png
|
||||
[25]: https://edutechwiki.unige.ch/en/InkStitch_-_Geneva-simple_typefaces
|
||||
[26]: https://fedoramagazine.org/wp-content/uploads/2022/06/LetteringCreationDialog-1.png
|
||||
[27]: https://fedoramagazine.org/wp-content/uploads/2022/06/LetteringPreview-1.png
|
||||
[28]: https://fedoramagazine.org/wp-content/uploads/2022/06/LetteringInDocument-1.png
|
||||
[29]: https://fedoramagazine.org/wp-content/uploads/2022/06/DocumentPropertiesAgain.png
|
||||
[30]: https://fedoramagazine.org/wp-content/uploads/2022/06/ResizedDocumentWithText.png
|
||||
[31]: https://fedoramagazine.org/wp-content/uploads/2022/06/AttachCommandsDialog.png
|
||||
[32]: https://fedoramagazine.org/wp-content/uploads/2022/06/SelectFirstLetter-1.png
|
||||
[33]: https://fedoramagazine.org/wp-content/uploads/2022/06/CutSymbols-1.png
|
||||
[34]: https://fedoramagazine.org/wp-content/uploads/2022/06/SeparatelyEmbroideredLetters-1.png
|
||||
[35]: https://fedoramagazine.org/wp-content/uploads/2022/06/VpypePreviewBack-1024x512.png
|
||||
[36]: https://fedoraproject.org/wiki/Artwork/T-Shirt
|
||||
[37]: http://www.kolourpaint.org/
|
||||
[38]: https://fedoramagazine.org/wp-content/uploads/2022/06/ShirtMockup2.png
|
||||
[39]: https://commons.wikimedia.org/wiki/File:Shirt-type_Polo.svg
|
||||
[40]: https://fedoramagazine.org/wp-content/uploads/2022/06/Front-768x1024.jpg
|
||||
[41]: https://fedoramagazine.org/wp-content/uploads/2022/06/Back-768x1024.jpg
|
||||
[42]: https://fedoramagazine.org/wp-content/uploads/2022/06/FrontCloseupHDR-1024x859.jpg
|
||||
[43]: https://fedoramagazine.org/wp-content/uploads/2022/06/BackCloseupHDR-1024x441.jpg
|
||||
[44]: https://raw.githubusercontent.com/garrett/Tux/main/tux.svg
|
||||
[45]: https://inkstitch.org/docs/basic-usage/
|
||||
[46]: http://www.pappagallo.com.cy
|
||||
[47]: https://targetsolutionsgh.business.site/
|
||||
[48]: https://marvelark.co.ke/
|
||||
[49]: https://coredigital.co.za/
|
||||
[50]: https://embroideryyourway.com/
|
@ -0,0 +1,109 @@
|
||||
[#]: subject: "Finding Your Router’s IP Address (Default Gateway) in Ubuntu and Other Linux"
|
||||
[#]: via: "https://itsfoss.com/router-ip-address-linux/"
|
||||
[#]: author: "Abhishek Prakash https://itsfoss.com/author/abhishek/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Finding Your Router’s IP Address (Default Gateway) in Ubuntu and Other Linux
|
||||
======
|
||||
You probably already know how to get your system’s IP address in Linux.
|
||||
|
||||
But how do you know the IP address of your router?
|
||||
|
||||
I am not talking about the public-facing IP which you can get by connecting to websites like [Show My IP][1] or simply [searching for ‘what is my ip’][2] in [DuckDuckGo][3].
|
||||
|
||||
I am talking about the default gateway IP which your Linux desktop uses to connect to it.
|
||||
|
||||
Why do you need it? Well, if you need to change the SSID, password, or other configuration of your wi-fi/network, you have to connect to it. And the simples way is to type the IP address of the router in a web browser and then use the router’s username and password.
|
||||
|
||||
While I cannot help you with the username and password of your router, I can surely tell you how to get its IP.
|
||||
|
||||
As always, I’ll show both GUI and command-line methods.
|
||||
|
||||
### Method 1: Get the router’s IP address in Linux using GUI
|
||||
|
||||
It’s quite simple actually. I am using GNOME desktop with Ubuntu here. If you use some [other desktop environments][4], screenshots may look different.
|
||||
|
||||
Open System Settings:
|
||||
|
||||
![go to settings][5]
|
||||
|
||||
Now go to Wi-Fi or Network (if you are using a wired, Ethernet connection). Here, click on the little settings symbol beside your currently used network.
|
||||
|
||||
![access network settings ubuntu][6]
|
||||
|
||||
It will open a new window with several details about your connection such as the IP address, DNS, and [Mac address][7]. You can also see the [saved wifi password][8] under the security tab.
|
||||
|
||||
You’ll also see an entry named ‘Default Route’. This is what you are looking for. The IP address of your router.
|
||||
|
||||
![defaul gateway ip ubuntu][9]
|
||||
|
||||
Your system and all other devices on your network connect to the router using this IP address. This is the setup most households have.
|
||||
|
||||
Now that I have shown the GUI method, let’s go to the terminal route.
|
||||
|
||||
### Method 2: Get the router’s IP address in Linux command line
|
||||
|
||||
Open a terminal and use the following command:
|
||||
|
||||
```
|
||||
ip route
|
||||
```
|
||||
|
||||
It will show you a few entries.
|
||||
|
||||
```
|
||||
[email protected]:~$ ip route
|
||||
default via 192.168.1.1 dev wlp0s20f3 proto dhcp metric 600
|
||||
169.254.0.0/16 dev wlp0s20f3 scope link metric 1000
|
||||
192.168.1.0/24 dev wlp0s20f3 proto kernel scope link src 192.168.1.34 metric 600
|
||||
```
|
||||
|
||||
The first line, which starts with ‘default via’, gives you the gateway IP. This is your router’s IP address.
|
||||
|
||||
![defaul route linux terminal][10]
|
||||
|
||||
As you can see, 192.168.1.1 is the IP address of my router. Usually, the router’s IP address is the first number of the subnet. However, this is not a hard and fast rule. I have seen routers with x.y.z.30 addresses as well.
|
||||
|
||||
### Bonus tip
|
||||
|
||||
As shared by Samir in the comments, you can also use the ping command to get the gateway IP:
|
||||
|
||||
```
|
||||
ping _gateway
|
||||
```
|
||||
|
||||
![ping gateway][11]
|
||||
|
||||
In case you didn’t know, you have to [use the Ctrl+C to stop a running command in Linux][12].
|
||||
|
||||
I hope you find this tip useful when you need it.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/router-ip-address-linux/
|
||||
|
||||
作者:[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://www.showmyip.com/
|
||||
[2]: https://duckduckgo.com/?q=what+is+my+ip&t=h_&ia=answer
|
||||
[3]: https://itsfoss.com/duckduckgo-easter-eggs/
|
||||
[4]: https://itsfoss.com/best-linux-desktop-environments/
|
||||
[5]: https://itsfoss.com/wp-content/uploads/2022/02/go_to_settings.jpg
|
||||
[6]: https://itsfoss.com/wp-content/uploads/2022/06/access-network-settings-ubuntu-800x448.png
|
||||
[7]: https://itsfoss.com/change-mac-address-linux/
|
||||
[8]: https://itsfoss.com/how-to-find-saved-wireless-wifi-passwords-ubuntu/
|
||||
[9]: https://itsfoss.com/wp-content/uploads/2022/06/defaul-gateway-ip-ubuntu.png
|
||||
[10]: https://itsfoss.com/wp-content/uploads/2022/06/defaul-route-linux-terminal.png
|
||||
[11]: https://itsfoss.com/wp-content/uploads/2022/06/ping-gateway.png
|
||||
[12]: https://itsfoss.com/stop-program-linux-terminal/
|
@ -0,0 +1,265 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (hanszhao80)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Djinn: A Code Generator and Templating Language Inspired by Jinja2)
|
||||
[#]: via: (https://theartofmachinery.com/2021/01/01/djinn.html)
|
||||
[#]: author: (Simon Arneaud https://theartofmachinery.com)
|
||||
|
||||
Djinn:一个受 Jinja2 启发的代码生成器和模板语言
|
||||
======
|
||||
|
||||
代码生成器是非常有用的工具。我有时使用 [jinja2][1] 的命令行版本来生成高度冗余的配置文件和其他文本文件,但它在转换数据方面功能有限。显然,Jinja2 的作者有不同的想法,但我想要类似于 <ruby>列表推导<rt>list comprehensions</rt></ruby> 或 D 语言的 <ruby>可组合范围<rt>composable range</rt></ruby> 算法之类的东西。
|
||||
|
||||
我决定制作一个类似于 Jinja2 的工具,但让我可以通过使用范围算法转换数据来生成复杂的文件。这个想法非常简单:一个直接用 D 语言代码重写的模板语言。这样它就支持 D 语言所能做的一切,仅仅因为它 _是_ D 语言。我想要一个独立的代码生成器,但是由于 [ D 语言的 `mixin` 特性][2],相同的模板语言可以作为嵌入式模板语言工作(例如,Web 应用程序中的 HTML)。有关该技巧的更多信息,请参阅 [这篇关于在编译时使用 mixins 将 Brainfuck 转换为 D 到机器代码的帖子][3]。
|
||||
|
||||
像往常一样,[源码在 GitLab 上][4]。[这篇文章中的例子也可以在这里找到。][5]
|
||||
|
||||
### 你好世界示例
|
||||
|
||||
这是一个演示这个想法的例子:
|
||||
|
||||
```
|
||||
Hello [= retro("dlrow") ]!
|
||||
[: enum one = 1; :]
|
||||
1 + 1 = [= one + one ]
|
||||
```
|
||||
|
||||
`[= some_expression ]` 类似于 Jinja2 中的 `{{ some_expression }}`,它在输出中呈现一个值。`[: some_statement; :]` 类似于 `{% some_statement %}` ,用于执行完整的代码语句。我更改了语法,因为 D 也大量使用花括号,并且将两者混合使模板难以阅读(还有一些特殊的非 D 指令,比如 `include`,它们被包裹在 `[<` 和 `>]` 中)。
|
||||
|
||||
如果你将上面的内容保存到一个名为 `hello.txt.dj` 的文件中并运行 `djinn` 命令行工具,你会得到一个名为 `hello.txt` 的文件,其中包含你可能猜到的内容:
|
||||
|
||||
```
|
||||
Hello world!
|
||||
1 + 1 = 2
|
||||
```
|
||||
|
||||
如果您使用过 Jinja2,您可能想知道第二行发生了什么。Djinn 有一个简化格式化和空格处理的特殊规则:如果源代码行包含 `[:` 语句或 `[<` 指令但不包含任何非空格输出,则整行都会被忽略输出。空行则仍会原样呈现。
|
||||
|
||||
### 生成数据
|
||||
|
||||
好的,现在来讲一些更实用的东西:生成 CSV 数据。
|
||||
|
||||
```
|
||||
x,f(x)
|
||||
[: import std.mathspecial;
|
||||
foreach (x; iota(-1.0, 1.0, 0.1)) :]
|
||||
[= "%0.1f,%g", x, normalDistribution(x) ]
|
||||
```
|
||||
|
||||
一个 `[=` 和 `]` 对可以包含多个用逗号分隔的表达式。如果第一个表达式是一个由双引号包裹的字符串,则会被解释为 [格式化字符串][6]。下面是输出结果:
|
||||
|
||||
```
|
||||
x,f(x)
|
||||
-1.0,0.158655
|
||||
-0.9,0.18406
|
||||
-0.8,0.211855
|
||||
-0.7,0.241964
|
||||
-0.6,0.274253
|
||||
-0.5,0.308538
|
||||
-0.4,0.344578
|
||||
-0.3,0.382089
|
||||
-0.2,0.42074
|
||||
-0.1,0.460172
|
||||
0.0,0.5
|
||||
0.1,0.539828
|
||||
0.2,0.57926
|
||||
0.3,0.617911
|
||||
0.4,0.655422
|
||||
0.5,0.691462
|
||||
0.6,0.725747
|
||||
0.7,0.758036
|
||||
0.8,0.788145
|
||||
0.9,0.81594
|
||||
```
|
||||
|
||||
### 制作图片
|
||||
|
||||
这个例子展示了一个图片的生成过程。[经典的 Netpbm 图像库定义了一堆图像格式][7],其中一些是基于文本的。例如,这是一个 3 x 3 向量的图像:
|
||||
|
||||
```
|
||||
P2 # <ruby>便携式灰色地图<rt>Portable GrayMap</rt></ruby>格式标识
|
||||
3 3 # 宽和高
|
||||
7 # 代表纯白色的值 (0 代表黑色)
|
||||
7 0 7
|
||||
0 0 0
|
||||
7 0 7
|
||||
```
|
||||
|
||||
你可以将上述文本保存到名为 `cross.pgm` 之类的文件中,很多图像工具都知道如何解析它。下面是一些 Djinn 代码,它以相同的格式生成 [Mandelbrot 集][8] 分形:
|
||||
|
||||
```
|
||||
[:
|
||||
import std.complex;
|
||||
enum W = 640;
|
||||
enum H = 480;
|
||||
enum kMaxIter = 20;
|
||||
ubyte mb(uint x, uint y)
|
||||
{
|
||||
const c = complex(3.0 * (x - W / 1.5) / W, 2.0 * (y - H / 2.0) / H);
|
||||
auto z = complex(0.0);
|
||||
ubyte ret = kMaxIter;
|
||||
while (abs(z) <= 2 && --ret) z = z * z + c;
|
||||
return ret;
|
||||
}
|
||||
:]
|
||||
P2
|
||||
[= W ] [= H ]
|
||||
[= kMaxIter ]
|
||||
[: foreach (y; 0..H) :]
|
||||
[= "%(%s %)", iota(W).map!(x => mb(x, y)) ]
|
||||
```
|
||||
|
||||
生成的文件大约为 800 kB,但它可以很好地被压缩为 PNG:
|
||||
|
||||
```
|
||||
$ # 使用 GraphicsMagick 进行转换
|
||||
$ gm convert mandelbrot.pgm mandelbrot.png
|
||||
```
|
||||
|
||||
结果如下:
|
||||
|
||||
![][9]
|
||||
|
||||
### 解决谜题
|
||||
|
||||
这里有一个谜题:
|
||||
|
||||
![][10]
|
||||
|
||||
一个 5 行 5 列的网格需要用 1 到 5 的数字填充,每个数字在每一行中限使用一次,在每列中限使用一次(即,制作一个 5 行 5 列的<ruby>拉丁方格<rt>Latin square</rt></ruby>)。相邻单元格中的数字还必须满足所有 `>` 大于号表示的不等式。
|
||||
|
||||
[几个月前我使用了 <ruby>线性规划<rt>linear programming</rt></ruby>(英文缩写 LP)][11]。线性规划问题是具有线性约束的连续变量系统。这次我将使用<ruby>混合整数线性规划<rt>mixed integer linear programming</rt></ruby>(英文缩写 MILP),它通过允许整数约束变量来归纳 LP。事实证明,这足以成为 NP 完备的,而 MILP 恰好可以很好地模拟这个谜题。
|
||||
|
||||
在上一篇文章中,我使用 Julia 库 JuMP 来帮助解决这个问题。这次我将使用 [CPLEX:基于文本的格式][12],它受到多个 LP 和 MILP 求解器的支持(如果需要,可以通过现成的工具轻松转换为其他格式)。这是上一篇文章中 CPLEX 格式的 LP:
|
||||
|
||||
```
|
||||
Minimize
|
||||
obj: v
|
||||
Subject To
|
||||
ptotal: pr + pp + ps = 1
|
||||
rock: 4 ps - 5 pp - v <= 0
|
||||
paper: 5 pr - 8 ps - v <= 0
|
||||
scissors: 8 pp - 4 pr - v <= 0
|
||||
Bounds
|
||||
0 <= pr <= 1
|
||||
0 <= pp <= 1
|
||||
0 <= ps <= 1
|
||||
End
|
||||
```
|
||||
|
||||
CPLEX 格式易于阅读,但复杂度高的问题需要大量变量和约束来建模,这使得手工编码既痛苦又容易出错。有一些特定领域的语言,例如 [ZIMPL][13],用于以高级方式描述 MILP 和 LP。对于许多问题来说,它们非常酷,但最终它们不如具有良好库(如 JuMP)支持的通用语言或使用 D 语言的代码生成器那样富有表现力。
|
||||
|
||||
我将使用两组变量来模拟这个谜题:`v_{r,c}` 和 `i_{r,c,v}`。`v_{r,c}` 将保存 r 行 c 列单元格的值(从 1 到 5)。`i_{r,c,v}` 是一个二进制指示器,如果 r 行 c 列的单元格的值是 v,则该指示器值为 1,否则为 0。这两组变量是网格的冗余表示,但第一种表示更容易对不等式约束进行建模,而第二种表示更容易对唯一性约束进行建模。我只需要添加一些额外的约束来强制这两个表示是一致的。但首先,让我们从每个单元格必须只有一个值的基本约束开始。从数学上讲,这意味着给定行和列的所有指示器都必须为 0,但只有一个值为 1 的例外。这可以通过以下等式强制约束:
|
||||
|
||||
```
|
||||
[i_{r,c,1} + i_{r,c,2} + i_{r,c,3} + i_{r,c,4} + i_{r,c,5} = 1]
|
||||
```
|
||||
|
||||
可以使用以下 Djinn 代码生成对所有行和列的 CPLEX 约束:
|
||||
|
||||
```
|
||||
\ 单元格只有一个值
|
||||
[:
|
||||
foreach (r; iota(N))
|
||||
foreach (c; iota(N))
|
||||
:]
|
||||
[= "%-(%s + %)", vs.map!(v => ivar(r, c, v)) ] = 1
|
||||
[::]
|
||||
```
|
||||
|
||||
`ivar()` 是一个辅助函数,它为我们提供变量名为 i 的字符串标识符,而 `vs` 存储从 1 到 5 的数字以方便使用。行和列内唯一性的约束完全相同,但在 i 的其他两个维度上迭代。
|
||||
|
||||
为了使变量组 i 与变量组 v 保持一致,我们需要如下约束(请记住,变量组 i 中只有一个元素的值是非零的):
|
||||
|
||||
```
|
||||
[i_{r,c,1} + 2i_{r,c,2} + 3i_{r,c,3} + 4i_{r,c,4} + 5i_{r,c,5} = v_{r,c}]
|
||||
```
|
||||
|
||||
CPLEX 要求所有变量都位于左侧,因此 Djinn 代码如下所示:
|
||||
|
||||
```
|
||||
\ 连接变量组 i 和变量组 v
|
||||
[:
|
||||
foreach (r; iota(N))
|
||||
foreach (c; iota(N))
|
||||
:]
|
||||
[= "%-(%s + %)", vs.map!(v => text(v, ' ', ivar(r, c, v))) ] - [= vvar(r,c) ] = 0
|
||||
[::]
|
||||
```
|
||||
|
||||
不等符号相邻的和左下角值为为 4 单元格的约束写起来都很简单。剩下的便是将指示器变量声明为二进制,并为变量组 v 设置边界。加上变量的边界,总共有 150 个变量和 111 个约束 [你可以在仓库中看到完整的代码][14]。
|
||||
|
||||
[GNU 线性规划工具集][15] 有一个命令行工具可以解决这个 CPLEX MILP。不幸的是,它的输出是一个包含了所有内容的体积很大的转储,所以我使用 awk 命令来提取需要的内容:
|
||||
|
||||
```
|
||||
$ time glpsol --lp inequality.lp -o /dev/stdout | awk '/v[0-9][0-9]/ { print $2, $4 }' | sort
|
||||
v00 1
|
||||
v01 3
|
||||
v02 2
|
||||
v03 5
|
||||
v04 4
|
||||
v10 2
|
||||
v11 5
|
||||
v12 4
|
||||
v13 1
|
||||
v14 3
|
||||
v20 3
|
||||
v21 1
|
||||
v22 5
|
||||
v23 4
|
||||
v24 2
|
||||
v30 5
|
||||
v31 4
|
||||
v32 3
|
||||
v33 2
|
||||
v34 1
|
||||
v40 4
|
||||
v41 2
|
||||
v42 1
|
||||
v43 3
|
||||
v44 5
|
||||
|
||||
real 0m0.114s
|
||||
user 0m0.106s
|
||||
sys 0m0.005s
|
||||
```
|
||||
|
||||
这是在原始网格中写出的解决方案:
|
||||
|
||||
![][16]
|
||||
|
||||
这些例子只是用来玩的,但我相信你已经明白了。顺便说一下,Djinn 代码仓库的 `README.md` 文件本身是使用 Djinn 模板生成的。
|
||||
|
||||
正如我所说,Djinn 也可以用作嵌入在 D 语言代码中的编译期模板语言。我最初只是想要一个代码生成器,得益于 D 语言的元编程功能,这算是一个额外获得的功能。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://theartofmachinery.com/2021/01/01/djinn.html
|
||||
|
||||
作者:[Simon Arneaud][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[hanszhao80](https://github.com/hanszhao80)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://theartofmachinery.com
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://jinja2docs.readthedocs.io/en/stable/
|
||||
[2]: https://dlang.org/articles/mixin.html
|
||||
[3]: https://theartofmachinery.com/2017/12/31/compile_time_brainfuck.html
|
||||
[4]: https://gitlab.com/sarneaud/djinn
|
||||
[5]: https://gitlab.com/sarneaud/djinn/-/tree/v0.1.0/examples
|
||||
[6]: https://dlang.org/phobos/std_format.html#format-string
|
||||
[7]: http://netpbm.sourceforge.net/doc/#formats
|
||||
[8]: https://en.wikipedia.org/wiki/Mandelbrot_set
|
||||
[9]: https://theartofmachinery.com/images/djinn/mandelbrot.png
|
||||
[10]: https://theartofmachinery.com/images/djinn/inequality.svg
|
||||
[11]: https://theartofmachinery.com/2020/05/21/glico_weighted_rock_paper_scissors.html
|
||||
[12]: http://lpsolve.sourceforge.net/5.0/CPLEX-format.htm
|
||||
[13]: https://zimpl.zib.de/
|
||||
[14]: https://gitlab.com/sarneaud/djinn/-/tree/v0.1.0/examples/inequality.lp.dj
|
||||
[15]: https://www.gnu.org/software/glpk/
|
||||
[16]: https://theartofmachinery.com/images/djinn/inequality_solution.svg
|
89
translated/tech/20210511 What is the OSI model.md
Normal file
89
translated/tech/20210511 What is the OSI model.md
Normal file
@ -0,0 +1,89 @@
|
||||
[#]: subject: (What is the OSI model?)
|
||||
[#]: via: (https://jvns.ca/blog/2021/05/11/what-s-the-osi-model-/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (hanszhao80)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
OSI 模型是什么?
|
||||
======
|
||||
|
||||
今天我在推特上发布了一些关于 OSI 模型如何与 TCP/IP 工作原理的实际表现不相符的观点,这让我思考——OSI 模型到底是什么?通过阅读推特上的一些回复发现,似乎至少存在三种不同的思考方式:
|
||||
|
||||
1. TCP/IP 工作原理的字面描述
|
||||
2. 一个可以用来描述和比较很多不同的网络协议的抽象模型
|
||||
3. 对 1980 年代的一些计算机网络协议的字面描述,这些协议如今大多已不再使用
|
||||
|
||||
在这篇文章中,我不打算试图争辩以上哪一个才是“真正”的 OSI 模型——似乎不同的人以所有这些方式思考它。这不重要。
|
||||
|
||||
### OSI 模型有七层
|
||||
|
||||
在我们讨论 OSI 模型的含义之前,让我们大致地讨论一下它是什么。它是一个抽象模型,用于描述网络如何在七个编号的层上工作:
|
||||
|
||||
- 第一层:物理层
|
||||
- 第二层:数据链路层
|
||||
- 第三层:网络层
|
||||
- 第四层:传输层
|
||||
- 第五层:会话层
|
||||
- 第六层:表示层
|
||||
- 第七层:应用层
|
||||
|
||||
我不会再费时地去解释每一层的含义,网上有上千种解释可供查询。
|
||||
|
||||
### OSI 模型:TCP/IP 工作原理的字面描述
|
||||
|
||||
首先,我想谈谈人们在实践中使用 OSI 模型的一种常见方式:作为对 TCP/IP 工作原理的字面描述。OSI 模型的某些层非常容易映射到 TCP/IP:
|
||||
|
||||
- 第二层对应以太网
|
||||
- 第三层对应 IP
|
||||
- 第四层对应 TCP 或 UDP(或 ICMP 等)
|
||||
- 第七层对应 TCP 或 UDP 包内的任何内容(例如 DNS 查询)
|
||||
|
||||
这种映射对第二、三、四层很有意义——TCP 数据包有三个<ruby>标头<rt>header</rt></ruby>对应于这三个层(以太网标头、IP 标头和 TCP 标头)。
|
||||
|
||||
用数字来描述 TCP 数据包中的不同标头非常有用——如果你说“第二层”,很显然它位于第三层“下方”,因为二比三小。
|
||||
|
||||
“OSI 模型作为字面描述”的古怪之处在于,第五层和第六层并不真正对应于 TCP/IP 中的任何内容——我听说过很多关于第五层或第六层可能是什么的不同解释(你可以说第五层是 TLS 或其他东西!)但它们没有像第二、三、四层那样“每一层在 TCP 数据包中都有相应的标头”这样的明确对应关系。
|
||||
|
||||
此外,TCP/IP 的某些部分即使在第二层到第四层也不能很好地适应 OSI 模型——例如,哪一层是 ARP 数据包?ARP 数据包发送一些带有以太网标头的数据,这是否意味着它们是第三层?或是第二层?列出不同 OSI 层的维基百科文章将其归类为“第 2.5 层”,这并不令人满意。
|
||||
|
||||
因为 OSI 模型有时用于教授 TCP/IP,若搞不清楚它的哪些部分与 TCP/IP 映射良好,而哪些部分不能,则会令人困惑。这才是真的问题。
|
||||
|
||||
### OSI 模型:用于比较网络协议的一个抽象
|
||||
|
||||
我听说过的另一种关于 OSI 的思考方式是,它是一种抽象,可以用来在许多不同的网络协议之间进行类比。例如,如果你想了解蓝牙协议的工作原理,也许你可以使用 OSI 模型来帮助你——这是我在 [这个网页][1] 上找到的一张图表,显示了蓝牙协议如何适配 OSI 模型。
|
||||
|
||||
![][2]
|
||||
|
||||
另一个例子是,[这篇维基百科文章][3] 有一个 OSI 层列表,详细划分了哪些特定的网络协议对应于这些 OSI 层。
|
||||
|
||||
### OSI 模型:一些过时协议的字面描述
|
||||
|
||||
维基百科上的一些非常简短的研究表明,除了对这七层的抽象描述之外,OSI 模型还包含了 [一组实现这些层的特定协议][4]。显然,这发生在 70 年代和 80 年代的 [协议战争][5] 时期,OSI 模型失败了,TCP/IP 则取得了胜利。
|
||||
|
||||
这就解释了为什么 OSI 模型无法与 TCP/IP 很好地对应,因为如果当时“获胜”的是 OSI 协议,那么 OSI 模型 _将_ 完全对应于互联网网络的实际工作方式。
|
||||
|
||||
### 结语
|
||||
|
||||
我写这篇文章的初衷是,当我最初学习 OSI 模型时,我发现它非常令人困惑(所有这些层是什么?它们是真实存在的吗?这是网络的实际工作原理吗?发生了什么?)我希望有人告诉我这个只使用 TCP/IP 网络协议的人,只需了解 OSI 模型第二、三、四和七层与 TCP/IP 的关系,然后忽略它的所有其他内容即可。所以我希望这篇文章对某些人能有所帮助!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2021/05/11/what-s-the-osi-model-/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[hanszhao80](https://github.com/hanszhao80)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://flylib.com/books/en/4.215.1.116/1/
|
||||
[2]: https://jvns.ca/images/bluetooth.gif
|
||||
[3]: https://en.wikipedia.org/wiki/List_of_network_protocols_(OSI_model)
|
||||
[4]: https://en.wikipedia.org/wiki/OSI_protocols
|
||||
[5]: https://en.wikipedia.org/wiki/Protocol_Wars
|
@ -3,19 +3,19 @@
|
||||
[#]: author: "Gaurav Kamathe https://opensource.com/users/gkamathe"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: reviewer: "turbokernel"
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
使用 rustup 管理你的 Rust 工具链
|
||||
======
|
||||
Rustup 可用于安装 Rust 并保持更新。它还允许你在稳定版、测试版和每日 Rust 编译器和工具之间无缝切换。
|
||||
Rustup 可用于 Rust 安装与更新。它还能够将 Rust 编译器和工具在稳定版、测试版和每日更新版之间无缝切换。
|
||||
|
||||
![Tools illustration][1]
|
||||
|
||||
图片来源:Opensource.com
|
||||
|
||||
[Rust 编程语言][2] 如今变得越来越流行,受到爱好者和公司的一致好评。它受欢迎的原因之一是 Rust 提供的令人惊叹的工具使其成为开发人员使用的乐趣。 [Rustup][3] 是用于管理 Rust 工具的官方工具。它不仅可以用于安装 Rust 并保持更新,它还允许你在稳定、测试和每日 Rust 编译器和工具之间无缝切换。本文将向你介绍 rustup 和一些常用命令。
|
||||
[Rust 编程语言][2] 如今变得越来越流行,受到爱好者和公司的一致好评。它受欢迎的原因之一是 Rust 提供的令人惊叹的工具使其成为开发人员使用的乐趣。 [Rustup][3] 是管理 Rust 工具的官方工具。它不仅可以安装和更新 Rust ,它还能够将 Rust 编译器和工具在稳定、测试和每日更新版之间无缝切换。本文将向你介绍 rustup 和一些常用命令。
|
||||
|
||||
### 默认 Rust 安装方式
|
||||
|
||||
@ -25,7 +25,7 @@ Rustup 可用于安装 Rust 并保持更新。它还允许你在稳定版、测
|
||||
$ sudo dnf install rust cargo
|
||||
```
|
||||
|
||||
这提供了一个稳定版本的 Rust 工具链,如果你是 Rust 的初学者并想尝试编译和运行简单的程序,它会非常有用。但是,由于 Rust 是一种新的编程语言,它变化很快,并且经常添加许多新功能。这些功能是 Rust 工具链的每日和之后测试版的一部分。要试用这些功能,你需要安装这些较新版本的工具链,而不会影响系统上的稳定版本。不幸的是,你的发行版的包管理器在这里无法为你提供帮助。
|
||||
这提供了一个稳定版本的 Rust 工具链,如果你是 Rust 的初学者并想尝试编译和运行简单的程序,它会非常有用。但是,由于 Rust 是一种新的编程语言,它变化很快,并且经常添加许多新功能。这些功能是 Rust 工具链的每日更新版和之后测试版的一部分。要试用这些功能,你需要安装这些较新版本的工具链,而不会影响系统上的稳定版本。不幸的是,你的发行版的包管理器在这里无法做到。
|
||||
|
||||
### 使用 rustup 安装 Rust 工具链
|
||||
|
||||
@ -54,7 +54,7 @@ $ bash sh.rustup.rs
|
||||
> 1
|
||||
```
|
||||
|
||||
安装后,你必须获取环境变量以确保 `rustup` 命令立即可供你使用:
|
||||
安装后,你必须获取环境变量以确保 `rustup` 命令立即可供你运行:
|
||||
|
||||
```
|
||||
$ source $HOME/.cargo/env
|
||||
@ -67,9 +67,9 @@ $ rustc --version
|
||||
$ cargo --version
|
||||
```
|
||||
|
||||
### 查看已安装和活动的工具链
|
||||
### 查看已安装和可用的工具链
|
||||
|
||||
你可以使用以下命令查看已安装的不同工具链以及哪个工具链是活动的:
|
||||
你可以使用以下命令查看已安装的不同工具链以及哪个工具链是可用的:
|
||||
|
||||
```
|
||||
$ rustup show
|
||||
@ -77,14 +77,14 @@ $ rustup show
|
||||
|
||||
### 在工具链之间切换
|
||||
|
||||
你可以查看默认工具链并根据需要进行更改。如果你当前使用的是稳定的工具链,并希望尝试每日版本中提供的新功能,你可以轻松切换到每日工具链:
|
||||
你可以查看默认工具链并根据需要进行更改。如果你当前使用的是稳定的工具链,并希望尝试每日更新版中提供的新功能,你可以轻松切换到每日更新版工具链:
|
||||
|
||||
```
|
||||
$ rustup default
|
||||
$ rustup default nightly
|
||||
```
|
||||
|
||||
要查看 Rust 的编译器和包管理器的确切路径:
|
||||
要查看 Rust 的编译器和包管理器的完整路径:
|
||||
|
||||
```
|
||||
$ rustup which rustc
|
||||
@ -113,7 +113,7 @@ $ rustup update
|
||||
$ rustup --help
|
||||
```
|
||||
|
||||
Rustup 在 GitHub 上有完整的[说明书][4],你可以将其用作参考。所有 Rust 文档都安装在你的本地系统上,不需要你连接到 Internet。你可以访问包括书籍、标准库等在内的本地文档:
|
||||
Rustup 在 GitHub 上有完整的[参考手册][4],你可以将其用作参考。所有 Rust 文档都安装在你的本地系统上,不需要你连接到 Internet。你可以访问包括书籍、标准库等在内的本地文档:
|
||||
|
||||
```
|
||||
$ rustup doc
|
||||
@ -131,7 +131,7 @@ 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)
|
||||
校对:[turbokernel](https://github.com/turbokernel)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user