不久前，我偶然发现了一个有趣的 Linux 项目。这个项目旨在为 Debian 和基于 Debian 的系统创建一个小型的现场版 CD，类似于 Puppy Linux 项目 。让我们看看 DebianDog 。DebianDog 是什么？正如字面所述，DebianDog “是一个被塑造成一个外观和动作都像 Puppy Linux 的小型 Debian 现场版 CD。没有改动 Debian 结构和方式，Debian 的文档对 DebianDog 来说是完全有效的。你可以使用 apt-get 或 synaptic 来访问所有的 Debian 存储库。”对于那些不熟悉 Puppy Linux 的人来说，该项目是 “多个 Linux 发行版的一个集合，建立在相同的共享准则之上”。这些准则能够实现快速、小型（300 MB 或更少）、易于使用。这里有为支持 Ubuntu, Slackware 和 Raspbian 软件包构建的 Puppy Linux 变种。DebianDog 和 Puppy Linux 之间最大的不同是，Puppy Linux 有其自己的软件包管理器 Puppy 软件包管理器 。如上所述，DebianDog 使用 Debian 软件包管理器及其软件包。甚至 DebianDog 网站也试图澄清这一点：“它不是 Puppy Linux，并且也与基于 Debian 的 Puppy 无关。”为什么一些人使用 DebianDog ？安装 DebianDog（或其任何衍生产品）的主要原因是让一台较旧电脑重焕新生。在 DebianDog 上的每个版本都有一个 32 位版本。它们还有更轻量级的桌面环境/窗口管理器，例如 Openbox 或 Trinity Desktop 环境。它们中大多数也都有一个 systemd 的可替代版本。它们也安装更轻的应用程序，例如 PCManFM 。DebianDog 有哪些可用的变体版本？尽管 DebianDog 在本系列中是第一个，但是该项目被称为 ‘Dog Linux’ ，提供各种基于Debian 和 Ubuntu的流行发行版的 ‘Dog 变体’。DebianDog JessieDebianDog 的第一个（也是最初的）版本是 DebianDog Jessie。它有两个 32 位版本 ，一个使用 Joe’s Window Manager (JWM) 作为默认桌面环境，另一个使用 XFCE 作为默认桌面环境。systemd 和 sysvinit 都是可用的。它还有一个 64 位版本。DebianDog Jessie 基于 Debian 8.0（Jessie）。Debian 8.0 的支持将于 2020 年 6 月 30 日结束，因此安装需谨慎。StretchDogStretchDog 基于 Debian 9.0（Stretch）。它有 32 位和 64 位两种版本可用。Openbox 是默认的窗口管理器，但是我们可以切换到 JWM 。Debian 9.0 的支持将于 2022 年 6 月 30 日结束。BusterDogBusterDog 是很有趣的。它基于 Debian 10（Buster）。它不使用 systemd，反而像 AntiX 一样使用 elogind 。Debian 10.0 的支持将于 2024 年 6 月结束。MintPupMintPup 基于 Linux Mint 17.1。现场版 CD 仅有 32 位版本。你也可以使用 “apt-get 或 synaptic 访问 Ubuntu/Mint 的存储库”。考虑到 Mint 17 已经到了生命的尽头，这一版本必须避免使用。XenialDogXenialDog 有 32 位和 64 位 两种变种，基于 Ubuntu 16.04 LTS 。两个变种都使用 Openbox 作为默认版本，JWM 可选。Ubuntu 16.04 LTS 的支持将于 2021 年 4 月结束, 因此安装需谨慎。TrinityDogTrintyDog 有两种变体。一个基于 Debian 8 ，另一个基于 Debian 9 。两种变体都有 32 位版本，并且都使用 Trinity Desktop Environment ，以此得名。BionicDog你应该能够从名称猜到。BionicDog 基于 Ubuntu 18.04 LTS。主要版本有 32 位和 64 位两个版本，Openbox 是默认的窗口管理器。这里也有一个使用 Cinnamon desktop) 的版本，并且只有 64 位版本。结束语我喜欢任何 想让较旧电脑系统有用的 Linux 项目。但是，通过 DebianDog 项目提供的大多数操作系统不再受支持，或者接近它们的生命尽头。从长远来看，这就不那么有用了。我不建议在你的主计算机上使用它。在现场版 USB 中或一台闲置的系统上尝试它。此外，如果你想使用较新的基础系统，你可以创建你自己的现场版 CD 。似乎冥冥中自有天意，我总是在探索鲜为人知的 Linux 发行版的路上艰难地前行，像 FatDog64、4M Linux 以及 Vipper Linux 。虽然我不建议使用它们，但是知晓这些项目的存在的意义总是好的。你对 DebianDog 有什么看法？你最最喜欢的 Puppy 式的操作系统是什么？请在下面的评论区中告诉我们。如果你觉得这篇文章很有趣，请花点时间在社交媒体、黑客新闻或 Reddit 上分享。via: https://itsfoss.com/debiandog/作者：John Paul 选题：lujun9972 译者：robsean 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
开源软件在应对新冠病毒中的贡献
在新冠疫情爆发之际，涌现了数以千计的开源项目，今天我们来了解其中四个。在当前紧张的疫情环境下，保持专注和积极性是一个很大的挑战。而研究开源社区如何应对这一次疫情爆发，对于我来说却成为了一种宣泄。从今年一月底开始，整个开源社区已经贡献了数以千计关于冠状病毒或新冠病毒的开源软件仓库，其中涉及的内容包括但不限于数据集、模型、可视化、Web 应用、移动应用，且大多数都使用了 JavaScript 和 Python 编写。之前我们分享过一些关于开源硬件创客们在帮助遏制冠状病毒传播方面做的贡献，现在将继续分享四个由开源社区作出的应对冠状病毒和新冠病毒的项目，这体现了开发者们和整个开源社区在当下对整个世界的影响力。1. PennSignals：CHIME 新冠病毒流行病医院影响模型 COVID-19 Hospital Impact Model for Epidemics （CHIME）是由宾夕法尼亚大学 Penn Medicine 机构的数据科学家们建立的开源在线应用，它可以让医院更好地了解本次新型冠状病毒对医院需求的影响。医院的管理人员可以通过 CHIME 来大致预测未来几天和几周内将会有多少患者需要住院治疗，并推算 ICU 和呼吸机的需求量。只需要输入当前住院患者数以及一些相关的变量，就可以看到未来几天内需求的变化情况。CHIME 主要使用 Python 开发，并通过 Pandas 这个开源库实现了大部分的数据转换和数值计算，最终得出相关的估计值。Pandas 的背后有一个强大的团队进行支持，它是在数据分析方面被广泛使用的 Python 库之一。和很多其它的开源项目一样，Pandas 团队的收入大部分来源于用户的资金支持。2. Locale.ai：实时新冠病毒可视化实时显示世界各地病例数量分布的地图可以让我们直观了解新冠病毒的规模和扩散程度。Locale.ai 就开发了这样一个开源、可交互的新冠病毒已知病例可视化分布图，这个图会根据最新的可靠数据实时进行更新。这个项目有趣的地方在于，它的数据是是通过 GitHub 用户 ExpDev07 创建的开源 API 进行检索的，这个 API 的数据来源是约翰·霍普金斯大学的开源数据集，而约翰·霍普金斯大学这份聚合了多个来源的数据集则是 GitHub 上新冠病毒相关的最受欢迎的项目。这就是开源项领域中分支带来的一大好处。Locale.ai 的这个图表通过 Vue.js 开发。Vue.js 是一个在 Web 应用开发方面非常流行的框架，它是由尤雨溪创造并维护的。值得一提的是，尤雨溪是少数以全职参与开源项目维护的人之一。3. BlankerL：DXY-COVID-19-CrawlerDXY-COVID-19-Crawler 建立于今年 1 月份，是开源社区对新冠病毒最早发起响应的项目之一。当时该病毒主要在中国范围内传播，中国医学界通过丁香园网站来进行病例的报告和跟踪。为了使这些疫情信息具有更高的可读性和易用性，GitHub 用户 BlankerL 开发了一个爬虫，系统地从丁香园网站获取数据，并通过 API 和数据仓库的方式对外公开。这些数据也被学术研究人员用于研究病毒传播趋势和制作相关的可视化图表。到目前为止，DXY-COVID-19-Crawler 这个项目已经获得了超过 1300 个星标和近 300 次的复刻。BlankerL 使用 Python 和 Beautiful Soup 库开发了这个爬虫。Beautiful Soup 是 Python 开发者用于从页面 HTML DOM 中提取信息的库，它由 Leonard Richardson 维护，这位作者另外还全职担任软件架构师。4. 东京新冠病毒工作组网站世界各地很多城市都在网络上持续更新当地的新冠病毒信息。东京都政府则为此创建了一个综合性的网站，让东京当地居民、在东京设有办事处的公司以及到东京的游客了解最新情况，并采取相应的预防措施。这个网站的不同之处在于它是由东京都政府开源的。这个项目受到了来自 180 多名用户的贡献，日本的长野市、千叶市、福冈市还对这个网站进行了改造。这个项目是城市公共建设更好地服务大众的有力示范。这个开源网站也使用了很多开源技术。通过 Tidelift，我留意到项目中存在了 1365 个依赖项，而这都是由 38 个由开发者明确使用的直接依赖项所依赖的。也就是说，超过一千多个开源项目（包括 Nuxt.js、Prettier、Babel、Ajv 等等）都为东京向市民共享信息提供了帮助。其它项目除此以外，还有很多应对新冠病毒的重要项目正在公开进行当中。在这次研究中，开源社区应对流行病以及利用开源技术开展工作的方式让我深受启发。接下来的一段时间都是应对疫情的关键时期，我们也可以继续在开源社区中寻找到更大的动力。如果你也参与到了新冠病毒相关的开源项目当中，欢迎在评论区分享。via: https://opensource.com/article/20/3/open-source-software-covid19作者：Jeff Stern 选题：lujun9972 译者：HankChow 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
本文是该系列的第三篇。第一篇：模式第二篇：OAuth在我们的即时消息应用中，消息表现为两个参与者对话的堆叠。如果你想要开始一场对话，就应该向应用提供你想要交谈的用户，而当对话创建后（如果该对话此前并不存在），就可以向该对话发送消息。就前端而言，我们可能想要显示一份近期对话列表。并在此处显示对话的最后一条消息以及另一个参与者的姓名和头像。在这篇帖子中，我们将会编写一些 端点 endpoint 来完成像“创建对话”、“获取对话列表”以及“找到单个对话”这样的任务。首先，要在主函数 main() 中添加下面的路由。router.HandleFunc("POST", "/api/conversations", requireJSON(guard(createConversation))) router.HandleFunc("GET", "/api/conversations", guard(getConversations)) router.HandleFunc("GET", "/api/conversations/:conversationID", guard(getConversation))这三个端点都需要进行身份验证，所以我们将会使用 guard() 中间件。我们也会构建一个新的中间件，用于检查请求内容是否为 JSON 格式。JSON 请求检查中间件func requireJSON(handler http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if ct := r.Header.Get("Content-Type"); !strings.HasPrefix(ct, "application/json") { http.Error(w, "Content type of application/json required", http.StatusUnsupportedMediaType) return } handler(w, r) } }如果 请求 request 不是 JSON 格式，那么它会返回 415 Unsupported Media Type（不支持的媒体类型）错误。创建对话type Conversation struct { ID string `json:"id"` OtherParticipant *User `json:"otherParticipant"` LastMessage *Message `json:"lastMessage"` HasUnreadMessages bool `json:"hasUnreadMessages"` }就像上面的代码那样，对话中保持对另一个参与者和最后一条消息的引用，还有一个 bool 类型的字段，用来告知是否有未读消息。type Message struct { ID string `json:"id"` Content string `json:"content"` UserID string `json:"-"` ConversationID string `json:"conversationID,omitempty"` CreatedAt time.Time `json:"createdAt"` Mine bool `json:"mine"` ReceiverID string `json:"-"` }我们会在下一篇文章介绍与消息相关的内容，但由于我们这里也需要用到它，所以先定义了 Message 结构体。其中大多数字段与数据库表一致。我们需要使用 Mine 来断定消息是否属于当前已验证用户所有。一旦加入实时功能，ReceiverID 可以帮助我们过滤消息。接下来让我们编写 HTTP 处理程序。尽管它有些长，但也没什么好怕的。func createConversation(w http.ResponseWriter, r *http.Request) { var input struct { Username string `json:"username"` } defer r.Body.Close() if err := json.NewDecoder(r.Body).Decode(&input); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } input.Username = strings.TrimSpace(input.Username) if input.Username == "" { respond(w, Errors{map[string]string{ "username": "Username required", }}, http.StatusUnprocessableEntity) return } ctx := r.Context() authUserID := ctx.Value(keyAuthUserID).(string) tx, err := db.BeginTx(ctx, nil) if err != nil { respondError(w, fmt.Errorf("could not begin tx: %v", err)) return } defer tx.Rollback() var otherParticipant User if err := tx.QueryRowContext(ctx, ` SELECT id, avatar_url FROM users WHERE username = $1 `, input.Username).Scan( &otherParticipant.ID, &otherParticipant.AvatarURL, ); err == sql.ErrNoRows { http.Error(w, "User not found", http.StatusNotFound) return } else if err != nil { respondError(w, fmt.Errorf("could not query other participant: %v", err)) return } otherParticipant.Username = input.Username if otherParticipant.ID == authUserID { http.Error(w, "Try start a conversation with someone else", http.StatusForbidden) return } var conversationID string if err := tx.QueryRowContext(ctx, ` SELECT conversation_id FROM participants WHERE user_id = $1 INTERSECT SELECT conversation_id FROM participants WHERE user_id = $2 `, authUserID, otherParticipant.ID).Scan(&conversationID); err != nil && err != sql.ErrNoRows { respondError(w, fmt.Errorf("could not query common conversation id: %v", err)) return } else if err == nil { http.Redirect(w, r, "/api/conversations/"+conversationID, http.StatusFound) return } var conversation Conversation if err = tx.QueryRowContext(ctx, ` INSERT INTO conversations DEFAULT VALUES RETURNING id `).Scan(&conversation.ID); err != nil { respondError(w, fmt.Errorf("could not insert conversation: %v", err)) return } if _, err = tx.ExecContext(ctx, ` INSERT INTO participants (user_id, conversation_id) VALUES ($1, $2), ($3, $2) `, authUserID, conversation.ID, otherParticipant.ID); err != nil { respondError(w, fmt.Errorf("could not insert participants: %v", err)) return } if err = tx.Commit(); err != nil { respondError(w, fmt.Errorf("could not commit tx to create conversation: %v", err)) return } conversation.OtherParticipant = &otherParticipant respond(w, conversation, http.StatusCreated) }在此端点，你会向 /api/conversations 发送 POST 请求，请求的 JSON 主体中包含要对话的用户的用户名。因此，首先需要将请求主体解析成包含用户名的结构。然后，校验用户名不能为空。type Errors struct { Errors map[string]string `json:"errors"` }这是错误消息的结构体 Errors，它仅仅是一个映射。如果输入空用户名，你就会得到一段带有 422 Unprocessable Entity（无法处理的实体）错误消息的 JSON 。{ "errors": { "username": "Username required" } }然后，我们开始执行 SQL 事务。收到的仅仅是用户名，但事实上，我们需要知道实际的用户 ID 。因此，事务的第一项内容是查询另一个参与者的 ID 和头像。如果找不到该用户，我们将会返回 404 Not Found（未找到） 错误。另外，如果找到的用户恰好和“当前已验证用户”相同，我们应该返回 403 Forbidden（拒绝处理）错误。这是由于对话只应当在两个不同的用户之间发起，而不能是同一个。然后，我们试图找到这两个用户所共有的对话，所以需要使用 INTERSECT 语句。如果存在，只需要通过 /api/conversations/{conversationID} 重定向到该对话并将其返回。如果未找到共有的对话，我们需要创建一个新的对话并添加指定的两个参与者。最后，我们 COMMIT 该事务并使用新创建的对话进行响应。获取对话列表端点 /api/conversations 将获取当前已验证用户的所有对话。func getConversations(w http.ResponseWriter, r *http.Request) { ctx := r.Context() authUserID := ctx.Value(keyAuthUserID).(string) rows, err := db.QueryContext(ctx, ` SELECT conversations.id, auth_user.messages_read_at < messages.created_at AS has_unread_messages, messages.id, messages.content, messages.created_at, messages.user_id = $1 AS mine, other_users.id, other_users.username, other_users.avatar_url FROM conversations INNER JOIN messages ON conversations.last_message_id = messages.id INNER JOIN participants other_participants ON other_participants.conversation_id = conversations.id AND other_participants.user_id != $1 INNER JOIN users other_users ON other_participants.user_id = other_users.id INNER JOIN participants auth_user ON auth_user.conversation_id = conversations.id AND auth_user.user_id = $1 ORDER BY messages.created_at DESC `, authUserID) if err != nil { respondError(w, fmt.Errorf("could not query conversations: %v", err)) return } defer rows.Close() conversations := make([]Conversation, 0) for rows.Next() { var conversation Conversation var lastMessage Message var otherParticipant User if err = rows.Scan( &conversation.ID, &conversation.HasUnreadMessages, &lastMessage.ID, &lastMessage.Content, &lastMessage.CreatedAt, &lastMessage.Mine, &otherParticipant.ID, &otherParticipant.Username, &otherParticipant.AvatarURL, ); err != nil { respondError(w, fmt.Errorf("could not scan conversation: %v", err)) return } conversation.LastMessage = &lastMessage conversation.OtherParticipant = &otherParticipant conversations = append(conversations, conversation) } if err = rows.Err(); err != nil { respondError(w, fmt.Errorf("could not iterate over conversations: %v", err)) return } respond(w, conversations, http.StatusOK) }该处理程序仅对数据库进行查询。它通过一些联接来查询对话表……首先，从消息表中获取最后一条消息。然后依据“ID 与当前已验证用户不同”的条件，从参与者表找到对话的另一个参与者。然后联接到用户表以获取该用户的用户名和头像。最后，再次联接参与者表，并以相反的条件从该表中找出参与对话的另一个用户，其实就是当前已验证用户。我们会对比消息中的 messages_read_at 和 created_at 两个字段，以确定对话中是否存在未读消息。然后，我们通过 user_id 字段来判定该消息是否属于“我”（指当前已验证用户）。注意，此查询过程假定对话中只有两个用户参与，它也仅仅适用于这种情况。另外,该设计也不很适用于需要显示未读消息数量的情况。如果需要显示未读消息的数量，我认为可以在 participants 表上添加一个unread_messages_count INT 字段，并在每次创建新消息的时候递增它，如果用户已读则重置该字段。接下来需要遍历每一条记录，通过扫描每一个存在的对话来建立一个 对话切片 slice of conversations 并在最后进行响应。找到单个对话端点 /api/conversations/{conversationID} 会根据 ID 对单个对话进行响应。func getConversation(w http.ResponseWriter, r *http.Request) { ctx := r.Context() authUserID := ctx.Value(keyAuthUserID).(string) conversationID := way.Param(ctx, "conversationID") var conversation Conversation var otherParticipant User if err := db.QueryRowContext(ctx, ` SELECT IFNULL(auth_user.messages_read_at < messages.created_at, false) AS has_unread_messages, other_users.id, other_users.username, other_users.avatar_url FROM conversations LEFT JOIN messages ON conversations.last_message_id = messages.id INNER JOIN participants other_participants ON other_participants.conversation_id = conversations.id AND other_participants.user_id != $1 INNER JOIN users other_users ON other_participants.user_id = other_users.id INNER JOIN participants auth_user ON auth_user.conversation_id = conversations.id AND auth_user.user_id = $1 WHERE conversations.id = $2 `, authUserID, conversationID).Scan( &conversation.HasUnreadMessages, &otherParticipant.ID, &otherParticipant.Username, &otherParticipant.AvatarURL, ); err == sql.ErrNoRows { http.Error(w, "Conversation not found", http.StatusNotFound) return } else if err != nil { respondError(w, fmt.Errorf("could not query conversation: %v", err)) return } conversation.ID = conversationID conversation.OtherParticipant = &otherParticipant respond(w, conversation, http.StatusOK) }这里的查询与之前有点类似。尽管我们并不关心最后一条消息的显示问题，并因此忽略了与之相关的一些字段，但是我们需要根据这条消息来判断对话中是否存在未读消息。此时，我们使用 LEFT JOIN 来代替 INNER JOIN，因为 last_message_id 字段是 NULLABLE（可以为空）的；而其他情况下，我们无法得到任何记录。基于同样的理由，我们在 has_unread_messages 的比较中使用了 IFNULL 语句。最后，我们按 ID 进行过滤。如果查询没有返回任何记录，我们的响应会返回 404 Not Found 错误，否则响应将会返回 200 OK 以及找到的对话。本篇帖子以创建了一些对话端点结束。在下一篇帖子中，我们将会看到如何创建并列出消息。源代码via: https://nicolasparada.netlify.com/posts/go-messenger-conversations/作者：Nicolás Parada 选题：lujun9972 译者：PsiACE 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
过去，我眼中的华为是神秘、大公司体制的代名词，但是，这一次 HDC.Cloud 华为开发者大会的参会体验和所见所闻，打破了我对于华为的认知，如今的华为与开放、创新等关键词紧密联系在一起。一、引语突如其来的全球性疫情的爆发，打乱了这个世界很多既定的事情。作为一个 IT “会虫”，我每年要参加很多重要的行业峰会，但如今的疫情形势，显然现场参会不再是一个好主意。在年前，我参加了华为的 HDC.Cloud 媒体预热会，近距离了解了原计划在春节后举办 HDC.Cloud，对这次计划中的大会充满了期待，也准备亲自去了解一些有趣的话题。在目前看起来还是愈演愈烈的疫情之下，全球各类 IT 行业的峰会纷纷停摆，或从线下改为线上，或延期观望，甚至直接取消的也比比皆是。而这次华为的 HDC.Cloud 也在调整之后，决定将原本预计参会规模达上万人的行业顶级峰会改为线上举办。说实话，在参会之前，我对线上会议能不能如以往般直面演讲者获得最新的重要信息还是有一定的疑虑的——不过事实上证明，至少在华为的 IT 基础设施加持之下，效果要比预期的好，只是心疼我滚烫的笔记本电脑。作为中国的一家开源社区，华为的开源举措和战略是我最为关注的，因此，在这篇文章中，我将向大家分享我对华为在开源方面的观察和感受。二、软件开源可以说，以华为这些年来的表现来看，已经将开源和开放作为其主要的生态战略来推进，这在华为的很多宣传和会议上，尤其是这次的 HDC.Cloud 上更为显著。几乎在每个话题和演讲中，都会或多或少地提及开源和开放生态。首先说开源软件，除了华为捐赠给 Apache 基金会的 ServiceComb、CarbonData、MetaModel 等若干顶级项目之外，华为在 GitHub 上的几个企业账户中还有很多项目：huawei ：160huaweicloud ：93huawei-cloudnative ：18huawei-noah：15liteos ：11……让我们再梳理下 openEuler 社区的几大里程碑事件：2019 年 9 月 18 日，华为宣布操作系统 、数据库等的开源计划，openEuler 开源社区上线（社区地址：https://openeuler.org/zh/）。2019 年 12 月 31 日，openEuler 源代码正式上线，至 3 月 25 日，下载 ISO 的累计次数：5479，贡献代码的总人数 220、总次数 5324。2020 年 3 月 27 日，openEuler 开源社区正式发布 openEuler 20.03 LTS（长期支持）版本。该版本是自开源社区上线以来的首个 LTS 版本。当前，openEuler 社区秘书处、技术委员会、安全委员会等组织已开始运作，社区参与者申请并成立了 30 多个项目组。这些其实并不出乎我们的预期，不过在这次会议上，大家之前关注颇多的 openEuler 这次披露了一个重要消息，它成功地和国内 4 家重要的操作系统厂家麒麟软件、普华基础软件、统信软件、中科院软件所等达成了合作，共同宣布基于 openEuler 的商用版本操作系统正式发布，以加速鲲鹏相关技术在各行业的落地和应用。openEuler 社区后续将每两年发布一次 LTS 版本，每 6 个月发布一次社区创新版本，并提供 CVE 漏洞管理能力。 openEuler也将始终坚持 Upstream First 策略，所有能力第一时间向上游开源社区推送。openEuler 20.03 LTS 版本基于华为长期的技术积累和产品实践，在稳定性、安全性上达到了业界领先水平，并通过软件全栈的技术优化，充分释放多样化计算平台算力。这说明了什么？openEuler 不仅仅是一个普通的 Linux 发行版，而是作为上游发行版，以开放的姿态迎来了国内各大操作系统厂商的支持。这在我的印象中，还是国内第一次跨越一家一地的操作系统层面的大合作，其开放形态可见一斑，也映射出了大家对鲲鹏计算生态的看好。三、硬件开放除了软件的开源，华为硬件开放方面也取得了长足的进展，这体现在了华为为其通用计算处理器“鲲鹏”和人工智能处理器“昇腾”打造的开放生态上。很多人知道开源软件，但是对硬件怎么开放不甚了然。随着互联网技术的发展，开源这个词已经逐渐被大众所接触和理解。以粗浅的解释来说，所谓开源软件就是将软件的源代码公开出来。有些人会疑问，那么硬件怎么开源呢？开源硬件和非开源硬件有很多区别，但是开源硬件联盟（OSHWA）定义了一个大多数人同意的定义，如果你熟悉开源软件，这不会听上去太奇怪：“开源硬件（OSHW）是一个指有形的造物：机器、设备或者其它物理东西的术语——其设计向公众发布，任何人可以制造、修改、分发并使用那些造物。”为了营造开放的计算生态，华为聚焦做好处理器、板卡和主板等底层基础硬件设施，并开发硬件设施的相关资源，使能合作伙伴优先发展自有品牌的计算产品整机。目前全球已经有黄河、长虹天宫、紫光恒越、同方、湘江等11家整机厂商基于鲲鹏主板推出自有品牌的服务器及PC产品。对于个人来说，我们可能很快就可以用上基于鲲鹏处理器的 PC 和服务器产品了。多样化计算时代，计算产品能够有新的选择，得益于华为一直以来在技术研发方面的高度投入。从2004年华为开始投资研发第一颗嵌入式处理芯片以来，目前已总共投入超过2万名的工程师，在去年9月的华为全联接大会上，华为基于“鲲鹏+昇腾”双引擎正式发布了计算战略，以“一云两翼双引擎”的计算产业布局，致力于为世界提供最强算力。最终形成了以“鲲鹏+昇腾”为核心的基础芯片族，满足世界对通用计算和智能计算的最新需求。三、开发者扶持再次投入 2 亿美元的沃土计划 2.0作为开源的土壤，开发者也是屡屡被华为提在口中的。在华为开发者大会 2020（Cloud）上，华为高调宣布“沃土计划 2.0”的进一步举措，将在 2020 年投入 2 亿美元推动鲲鹏计算产业发展，并公布面向高校、初创企业、开发人员及合作伙伴的扶持细则。高校教研扶持：面向高校，提供1亿人民币的扶持金额，包括人才培养，云资源及样机支持，同时华为与教育部签署3年协议投入 10 亿人民币，共同推进人才的培养。初创企业及开发人员扶持：面向初创企业及个体开发人员，以云资源及线下活动的方式发放 1 亿人民币的补助，每家初创公司最高可获得 75 万人民币的云券。合作伙伴发展扶持：面向合作伙伴，提供6亿人民币的扶持总额，其中 3 亿人民币一次性研发费用补贴，3 亿人民币的云资源。华为云与计算 BG 总裁侯金龙在《与全球开发者共成长，共赢计算新时代》主题演讲时表示：“开发者是改变世界的重要力量，也是企业创新的引擎和产业生态的灵魂。华为去年发布了沃土计划 2.0，计划 5 年内发展 500 万开发者，目前华为云开发者已经增长到 160 万。”华为云与计算 BG 总裁侯金龙在主题演讲打造鲲鹏的开发工具平台为了让每位开发者用上并用好鲲鹏，华为在大会上发布了 CloudIDE 开发环境服务、鲲鹏加速库和开发者社区。站在鲲鹏开发者的角度，如果在本地做开发构建，则需要做交叉编译；而如果在鲲鹏环境做原生编译，则面临着和其它工作的割裂。而现在，有了支持鲲鹏原生开发环境的华为云 CloudIDE，这个痛点就迎刃而解。华为云 DevCloud 研发总监王亚伟介绍， CloudIDE 只需要几十秒时间就能快速创建鲲鹏原生的云端开发环境，开发者可以直接在浏览器内连接到云端实例，进行编码、调试、测试，10 分钟就能快速开发鲲鹏云原生应用。作为华为云 DevCloud 开发平台组件之一，CloudIDE 是轻量化的基于 Web 的集成开发环境服务，支持鲲鹏原生和多语言，打通了开发态和运行态。目前，已有超过 40 万用户在 DevCloud 上开发了超过 50 万个项目。而且，2020 年 CloudIDE 对所有鲲鹏实例全年免费。此外，华为还提供了鲲鹏加速库。它分为基础，压缩，加解密，存储，多媒体五大类，应用开发者可以在代码修改量不到1%的情况下，将性能提升大于 10% 甚至在加解密等场景下将性能提升超过 100%。如今，鲲鹏开发者们还有了一个活跃的开发者社区，汇聚集了全栈软硬件知识、鲲鹏产业资讯、政策发布、认证查询等信息，华为还为社区提供全天候 7x24H 的专家在线服务。四、结语华为在计算产业的发展策略“硬件开放，软件开源，使能合作伙伴”，同时华为也是业界唯一一家同时拥有“CPU、NPU、存储控制、网络互连、智能管理”五大关键芯片的厂商。对于华为来说，惟有以软件开源+硬件开放，才能发掘更大的潜能、释放更大的算力，为数字经济时代提供最具创新性的核心生产力。随着华为持续不断地提供各种资源，帮助广大开发者学习和使用鲲鹏，会帮助更多的伙伴逐步实现应用的迁移。华为是国内难得的高研发投入企业，并不断推出开放的策略，对于整个产业中的我们每个人来说，都是一个重大的利好消息。学习、理解、利用华为所开放出来的这些技术，对于我们这些从业者来说，都是不可多得的好资料。也希望更多的企业能够向华为学习，从闭源、封闭，渐渐走向开放。
如果你是一名系统管理员或者开发者，当你在终端工作时有时会需要编辑一个文件。在 Linux 系统中有几种文件编辑器，你可以根据需求选择合适的文件编辑器。在这里，我想推荐 Vim 编辑器。为什么推荐 Vim 编辑器相对于创建新文件，你更多是修改已经存在的文件。在这种情况下，Vim 快捷键可以有效地满足你的需求。下列文章可以帮助你了解对文件和目录的操作。Linux 基础：对文件和目录进行操作的 Linux 和 Unix 命令在 Linux 中查看不同文件格式的 10 种方法什么是 VimVim 是被 Linux 管理员和开发者广泛使用的最流行和功能强大的编辑器之一。它可以通过高度的自定义配置来提高文本编辑效率。它是在众多 Unix 默认安装的 Vi 编辑器的升级版。Vim 通常被称为“程序员的编辑器”，但并不限于此，它也可用于编辑任何类型的文件。它具有许多功能，例如：多次撤销、多窗口和缓冲区、语法高亮、命令行编辑、文件名补全、可视选择等等。你可以使用 :help 命令来获取在线帮助。理解 Vim 的模式Vim 有两种模式，详细介绍如下：命令模式： 当启动 Vim 编辑器后，默认处在命令模式下。你可以在文件中移动并且修改内容，剪切、复制和粘贴文件的一部分，同时发出命令执行更多操作（按 ESC 键进入命令模式）插入模式： 插入模式用于在给定的文档位置插入文本（按 i 键进入插入模式）我如何知道我正使用哪种 Vim 模式呢？如果你正在使用插入模式，你会在编辑器的底部看到 INSERT。如果编辑器底部没有显示任何内容，或者在编辑器底部显示了文件名，则处于 “命令模式”。命令模式下的光标移动Vim 快捷键允许你使用不同的方式来移动光标：G – 跳转到文件最后一行gg – 跳转到文件首行$ – 跳转到行末尾0（数字 0） – 跳转到行开头w – 跳转到下一个单词的开始（单词的分隔符可以是空格或其他符号）W – 跳转到下一个单词的开始（单词的分隔符只能是空格）b – 跳转到下一个单词的末尾（单词的分隔符可以是空格或其他符号）B – 跳转到下一个单词的末尾（单词的分隔符只能是空格）PgDn 键 – 向下移动一页PgUp 键 – 向上移动一页Ctrl+d – 向下移动半页Ctrl+u – 向上移动半页插入模式：插入文字下面的 Vim 快捷键允许你根据需要在光标的不同位置插入内容。i – 在光标之前插入a – 在光标之后插入I – 在光标所在行的开头插入。当光标位于行中间时，这个键很有用A – 在光标所在行的末尾插入。o – 在光标所在行的下面插入新行O – 在光标所在行的上面插入新行ea – 在单词的末尾插入拷贝、粘贴和删除一行yy – 复制一行p / P – 将内容粘贴到光标之后 / 之前dd – 删除一行dw – 删除一个单词在 Vim 中搜索和替换匹配的模式/模式 – 向后搜索给定的模式?模式 – 向前搜索给定的模式n – 向后重复搜索之前给定的模式N – 向前重复搜索之前给定的模式:%s/旧模式/新模式/g – 将文件中所有的旧模式替换为新模式:s/旧模式/新模式/g – 将当前行中所有的旧模式替换为新模式:%s/旧模式/新模式/gc – 逐个询问是否文件中的旧模式替换为新模式如何在 Vim 编辑器中跳转到特定行你可以根据需求以两种方式达到该目的，如果你不知道行号，建议采用第一种方法。通过打开文件并运行下面的命令来显示行号:set number当你设置好显示行号后，按 :n 跳转到相应的行号。例如，如果你想跳转到第 15 行，请输入：:15如果你已经知道行号，请使用以下方法在打开文件时直接跳转到相应行。例如，如果在打开文件时直接跳转到 20 行，请输入下面的命令：$ vim +20 [文件名]撤销操作/恢复上一次操作/重复上一次操作u – 撤销更改Ctrl+r – 恢复更改. – 重复上一条命令保存和退出 Vim:w – 保存更改但不退出 vim:wq – 写并退出:q! – 强制退出via: https://www.2daygeek.com/basic-vim-commands-cheat-sheet-quick-start-guide/作者：Magesh Maruthamuthu 选题：lujun9972 译者：萌新阿岩 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
如何为你的开源项目编写实用的文档
一份优质的文档可以让很多用户对你的项目路人转粉。好的代码很多时候并不代表一切。或许你能用最精巧的代码解决了世界上最迫切需要解决的问题，但如果你作为一个开源开发者，没能用准确的语言将你的作品公之于世，你的代码也只能成为沧海遗珠。因此，技术写作和文档编写是很重要的技能。一般来说，项目中的文档是最受人关注的部分，很多用户会通过文档来决定自己是否应该对某个项目开始学习或研究。所以，我们不能忽视技术写作和文档编写的工作，尤其要重点关注其中的“ 入门 Getting Started ”部分，这会对你项目的发展起到关键性的作用。对于很多人来说，写作是一件令人厌烦甚至恐惧的事情。我们这些工程师出身的人，更多学习的是“写代码”而不是学习“为代码写文档”。不少人会把英语作为自己的第二语言或者第三语言，他们可能会对英语写作感到不自信甚至害怕（我的母语是汉语，英语是作为我的第二语言学习的，所以我也能感受到这种痛苦）。但如果你希望自己的项目能在全球范围内产生一定的影响力，英语就是你必须使用的语言，这是一个无法避免的现实。但不必害怕，我在写这篇文章的时候就考虑到了这些可能带来的挑战，并给出了我的一些建议。五条有用的写作建议这五条建议你马上就可以用起来，尽管看起来似乎有些浅显，但在技术写作时却经常被忽视。使用主动语态：感受一下主动语态下的“你可以这样更改配置（You can change these configurations by…）”和被动语态下的“配置可以这样更改（These configurations can be changed by…）”有什么不同之处。使用简洁明了的句子：可以借助 Hemingway App 或者 Grammarly 这样的工具，尽管它们并不开源。保持条理性：你可以在文档中通过写标题、划重点、引链接等方式，把各类信息划分为不同的部分，避免将所有内容都杂糅在一大段冗长的文字当中。提高可读性：除了单纯的文字之外，运用图表也是从多种角度表达的手段之一。注意拼写和语法：必须记得检查文档中是否有拼写错误或者语法错误。只要在文档的写作和编辑过程中应用到这些技巧，你就能够和读者建立起沟通和信任。高效沟通：对于工程师们来说，阅读长篇大论的冗长文字，还不如去看小说。在阅读技术文档时，他们总是希望能够从中快速准确地获取到有用的信息。因此，技术文档的最佳风格应该是精简而有效的，不过这并不代表文档中不能出现类似幽默、emoji 甚至段子这些东西，这些元素可以当你的文档更有个性、更使人印象深刻。当然，具体的实现方式就因人而异了建立信任：你需要取得文档读者们的信任，这在一个项目的前期尤为重要。读者对你的信任除了来源于你代码的质量，还跟你文档编写的质量有关。所以你不仅要打磨代码，还要润色好相关的文档，这也是上面第 5 点建议拼写和语法检查的原因。从编写“入门”文档开始现在，最需要花费功夫的应该就是“入门”部分了，这是一篇技术文档最重要的部分，二八定律在这里得到了充分体现：访问一个项目的大部分流量都会落在项目文档上，而访问项目文档的大部分流量则会落在文档的“入门”部分中。因此，如果文档的“入门”部分写得足够好，项目就会吸引到很多用户，反之，用户会对你的项目敬而远之。那么如何写好“入门”部分呢？我建议按照以下三步走：任务化：入门指南应该以任务为导向。这里的任务指的是对于开发者来说可以完成的离散的小项目，而不应该包含太多涉及到体系结构、核心概念等的抽象信息，因此在“入门”部分只需要提供一个简单明了的概述就可以了。也不要在“入门”部分大谈这个项目如何优秀地解决了问题，这个话题可以放在文档中别的部分进行说明。总而言之，“入门”部分最好是给出一些主要的操作步骤，这样显得开门见山。30 分钟内能够完成：这一点的核心是耗时尽可能短，不宜超过 30 分钟，这个时间上限是考虑到用户可能对你的项目并不了解。这一点很重要，大部分愿意浏览文档的人都是有技术基础的，但对你的项目也仅仅是一知半解。首先让这些读者尝试进行一些相关操作，在收到一定效果后，他们才会愿意花更多时间深入研究整个项目。因此，你可以从耗时这个角度来评估你的文档“入门”部分有没有需要改进之处。有意义的任务：这里“有意义”的含义取决于你的开源项目。最重要的是认真思考并将“入门”部分严格定义为一项任务，然后交给你的读者去完成。这个项目的价值应该在这项有意义的任务中有所体现，不然读者可能会感觉这是一个浪费时间的行为。提示：假如你的项目是一个分布式数据库，那么达到“整个集群在某些节点故障的情况下可以不中断地保持可用”的目标就可以认为是“有意义”的；假如你的项目是一个数据分析工具或者是商业智能工具，“有意义”的目标也可以是“加载数据后能快速生成多种可视化效果的仪表板”。总之，无论你的项目需要达到什么“有意义”的目标，都应该能在笔记本电脑上本地快速实现。Linkerd 入门就是一个很好的例子。Linkerd 是一个开源的 Kubernetes 服务网格 Service Mesh ，当时我对 Kubernetes 了解并不多，也不熟悉服务网格。但我在自己的笔记本电脑上很轻松地就完成了其中的任务，同时也加深了对服务网格的理解。上面提到的三步过程是一个很有用的框架，对一篇文档“入门”部分的设计和量化评估很有帮助。今后你如果想将你的开源项目产品化，这个框架还可能对 实现价值的时间 time-to-value 产生影响。其它核心部分认真写好“入门”部分之后，你的文档中还需要有这五个部分：架构设计、生产环境使用指导、使用案例、参考资料以及未来展望，这五个部分在一份完整的文档中是必不可少的。架构设计：这一部分需要深入探讨整个项目架构设计的依据，“入门”部分中那些一笔带过的关键细节就应该在这里体现。在产品化过程中，这个部分将会是产品推广计划的核心，因此通常会包含一些可视化呈现的内容，期望的效果是让更多用户长期参与到项目中来。生产环境使用指导：对于同一个项目，在生产环境中部署比在笔记本电脑上部署要复杂得多。因此，指导用户认真使用就尤为重要。同时，有些用户可能对项目很感兴趣，但对生产环境下的使用有所顾虑，而指导和展示的过程则正好能够吸引到这类潜在的用户。使用案例： 社会认同 social proof 的力量是有目共睹的，所以很有必要列出正在生产环境使用这个项目的其他用户，并把这些信息摆放在显眼的位置。这个部分的浏览量甚至仅次于“入门”部分。参考资料：这个部分是对项目的一些详细说明，让用户得以进行详细的研究以及查阅相关信息。一些开源作者会在这个部分事无巨细地列出项目中的每一个细节和 边缘情况 edge case ，这种做法可以理解，但不推荐在项目初期就在这个部分花费过多的时间。你可以采取更折中的方式，在质量和效率之间取得平衡，例如提供一些相关社区的链接、Stack Overflow 上的标签或单独的 FAQ 页面。未来展望：你需要制定一个简略的时间表，规划这个项目的未来发展方向，这会让用户长期保持兴趣。尽管项目在当下可能并不完美，但要让用户知道你仍然有完善这个项目的计划。这个部分也能让整个社区构建一个强大的生态，因此还要向用户提供表达他们对未来展望的看法的交流区。以上这几个部分或许还没有在你的文档中出现，甚至可能会在后期才能出现，尤其是“使用案例”部分。尽管如此，还是应该在文档中逐渐加入这些部分。如果用户对“入门”部分已经感觉良好，那以上这几个部分将会提起用户更大的兴趣。最后，请在“入门”部分、README 文件或其它显眼的位置注明整个项目所使用的许可证。这个细节会让你的项目更容易通过最终用户的审核。花 20% 的时间写作一般情况下，我建议把整个项目 10% 到 20% 的时间用在文档写作上。也就是说，如果你是全职进行某一个项目的，文档写作需要在其中占半天到一天。再细致一点，应该将写作纳入到常规的工作流程中，这样它就不再是一件孤立的琐事，而是日常的事务。文档写作应该随着工作进度同步进行，切忌将所有写作任务都堆积起来最后完成，这样才可以帮助你的项目达到最终目标：吸引用户、获得信任。特别鸣谢云原生计算基金会的布道师 Luc Perkins 给出的宝贵意见。本文首发于 COSS Media 并经许可发布。via: https://opensource.com/article/20/3/documentation作者：Kevin Xu 选题：lujun9972 译者：HankChow 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
Linux 用户偏爱使用 scp 或 rsync 来进行文件或目录的复制拷贝。不过在 Linux 上正出现了许多新的可选方式，因为 Linux 是开源的，所以任何人都可以为 Linux 开发一个安全软件。在过去我们已经写了多篇有关安全分享这个话题的文章，它们分别是 OnionShare、Magic Wormhole、Transfer.sh 和 Dcp – Dat Copy。今天我们甚至还将继续讨论这个话题，我们将介绍名为 ffsend 的工具。ffsend 是什么？ffsend 是 Firefox Send 服务的一个命令行客户端，允许用户通过命令行来传递和接收文件或目录。它允许我们通过一个安全、私密、加密的链接，使用一个简单的命令来轻易安全地分享文件和目录。通过 Firefox 的 Send 服务共享的文件最大大小为 2GB（LCTT 译注：现在官网上写的是最大 1GB，登录后最大 2.5GB）。其他人可以通过这个工具或者网页浏览器来下载这些分享的文件。所有的文件都是在客户端加密的，并且秘钥将不会被共享到远程主机。另外，你还可以为上传的文件额外设置一个密码。上传的文件在下载（默认被下载 1 次，最多可被下载 10 次）后或者 24 小时后，就会自动删除。这将确保你的文件不会一直保留在网络上。该工具当前处于 alpha 阶段，使用时请自担风险。而且，当前只有有限的安装方式可用。ffsend 的特点：全功能且使用友好的命令行工具可以安全地上传和下载文件与目录总是在客户端加密可用额外的密码进行保护、密码生成和可配置下载次数限制内置的文件或目录的打包和解压可以轻松地管理你的历史分享记录能够使用你自己的 Send 主机审查或者删除共享文件精准的错误报告低内存消耗，用于加密或上传下载无需交互，可以集成在脚本中如何在 LInux 中安装 ffsend 呢？当前除了 Debian 和 Arch Linux 系统，其他发行版还没有相应的安装包（LCTT 译注：这个信息已过时，最新内容请看这里）。然而，我们可以轻易地根据我们自己的操作系统和架构下载到相应的预编译二进制文件。运行下面的命令来为你的操作系统下载 ffsend 最新可用的版本（LCTT 译注：当前最新版本为 v0.2.58）：$ wget https://github.com/timvisee/ffsend/releases/download/v0.1.2/ffsend-v0.1.2-linux-x64.tar.gz然后使用下面的命令来解压 tar 包：$ tar -xvf ffsend-v0.1.2-linux-x64.tar.gz接着运行下面的命令来查看你的 PATH 环境变量：$ echo $PATH /home/daygeek/.cargo/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl正如我先前告知的那样，下面我们要做的就是将这个可执行文件放置到 PATH 环境变量中的某个目录中：$ sudo mv ffsend /usr/local/sbin直接运行 ffsend 可以获取其基本使用信息：$ ffsend ffsend 0.1.2 Usage: ffsend [FLAGS] ... Easily and securely share files from the command line. A fully featured Firefox Send client. Missing subcommand. Here are the most used: ffsend upload ... ffsend download ... To show all subcommands, features and other help: ffsend help [SUBCOMMAND]对于使用基于 Arch Linux 系统的用户可以简单地借助 AUR 助手来安装它，因为这个包已经在 AUR 软件仓库中了。$ yay -S ffsend对于使用 Debian/Ubuntu 系统的用户，使用 DPKG 命令来安装 ffsend。$ wget https://github.com/timvisee/ffsend/releases/download/v0.1.2/ffsend_0.1.2_amd64.deb $ sudo dpkg -i ffsend_0.1.2_amd64.deb如何使用 ffsend这并不复杂，我们可以简单地通过下面的语法来发送文件。语法：$ ffsend upload [/Path/to/the/file/name]在下面的例子中，我们将上传一个名为 passwd-up1.sh 的文件，一旦你上传了该文件，你将得到一个唯一的 URL。$ ffsend upload passwd-up1.sh --copy Upload complete Share link: https://send.firefox.com/download/a4062553f4/#yy2_VyPaUMG5HwXZzYRmpQ在任何远端的系统上，只需要使用上面那个唯一的 URL 就可以下载上传的文件了。语法：$ ffsend download [Generated URL]命令的输出如下：$ ffsend download https://send.firefox.com/download/a4062553f4/#yy2_VyPaUMG5HwXZzYRmpQ Download complete使用下面的语法来对目录进行上传：$ ffsend upload [/Path/to/the/Directory] --copy在下面的例子中，我们将上传一个名为 2g 的目录：$ ffsend upload /home/daygeek/2g --copy You've selected a directory, only a single file may be uploaded. Archive the directory into a single file? [Y/n]: y Archiving... Upload complete Share link: https://send.firefox.com/download/90aa5cfe67/#hrwu6oXZRG2DNh8vOc3BGg在任意的远端系统中，只需要利用上面生成的唯一 URL 就可以获取到刚才上传的目录了。$ ffsend download https://send.firefox.com/download/90aa5cfe67/#hrwu6oXZRG2DNh8vOc3BGg You're downloading an archive, extract it into the selected directory? [Y/n]: y Extracting... Download complete上面已经通过安全、私密和加密过的链接来发送了文件。然而，如果你想在你的掌控范围内再添加额外的安全措施，你可以为文件添加密码。$ ffsend upload file-copy-rsync.sh --copy --password Password: Upload complete Share link: https://send.firefox.com/download/0742d24515/#P7gcNiwZJ87vF8cumU71zA当你在远端系统中尝试下载该文件时，它将要求你输入密码：$ ffsend download https://send.firefox.com/download/0742d24515/#P7gcNiwZJ87vF8cumU71zA This file is protected with a password. Password: Download complete另外，你还可以在上传过程中提供下载次数限制来限制文件被下载的次数。$ ffsend upload file-copy-scp.sh --copy --downloads 10 Upload complete Share link: https://send.firefox.com/download/23cb923c4e/#LVg6K0CIb7Y9KfJRNZDQGw然后你可以在任意的远程系统中使用上面的唯一 URL 来下载该文件：ffsend download https://send.firefox.com/download/23cb923c4e/#LVg6K0CIb7Y9KfJRNZDQGw Download complete假如你想看这个链接的更多细节，你可以使用下面的命令来查看它的信息，它将为你展示文件名称、文件大小、被下载次数以及过期时间。语法：$ ffsend info [Generated URL] $ ffsend info https://send.firefox.com/download/23cb923c4e/#LVg6K0CIb7Y9KfJRNZDQGw ID: 23cb923c4e Name: file-copy-scp.sh Size: 115 B MIME: application/x-sh Downloads: 3 of 10 Expiry: 23h58m (86280s)此外，你还可以使用下面的命令来查看你的传输历史：$ ffsend history # LINK EXPIRY 1 https://send.firefox.com/download/23cb923c4e/#LVg6K0CIb7Y9KfJRNZDQGw 23h57m 2 https://send.firefox.com/download/0742d24515/#P7gcNiwZJ87vF8cumU71zA 23h55m 3 https://send.firefox.com/download/90aa5cfe67/#hrwu6oXZRG2DNh8vOc3BGg 23h52m 4 https://send.firefox.com/download/a4062553f4/#yy2_VyPaUMG5HwXZzYRmpQ 23h46m 5 https://send.firefox.com/download/74ff30e43e/#NYfDOUp_Ai-RKg5g0fCZXw 23h44m 6 https://send.firefox.com/download/69afaab1f9/#5z51_94jtxcUCJNNvf6RcA 23h43m假如你不想再分享某个链接，你可以使用下面的语法来删除它：语法：$ ffsend delete [Generated URL] $ ffsend delete https://send.firefox.com/download/69afaab1f9/#5z51_94jtxcUCJNNvf6RcA File deleted如何在浏览器中使用 Send另外，你还可以通过使用 firefox 浏览器打开 https://send.firefox.com/ 来完成相应的分享。只需要拖拽该文件就可以上传它：一旦该文件被下载，它将展示 100% 的下载状态。想查看其他的可能选项，请浏览它对应的 man 信息或者帮助页。via: https://www.2daygeek.com/ffsend-securely-share-files-folders-from-linux-command-line-using-firefox-send-client/作者：Vinoth Kumar 选题：lujun9972 译者：FSSlc 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
跟随接下来的介绍，自己搭建一个三节点的 Kubernetes 集群。我对在树莓派上搭建 Kubernetes 集群已经感兴趣很长时间了，只要照着网上的教程，我可以在由三个树莓派组成的集群中搭建一套 Kubernetes 并正常运行。但在这种情况下，主节点上的内存和 CPU 资源捉襟见肘，执行 Kubernetes 任务的时候往往性能不佳，想要升级 Kubernetes 就更不可能了。这个时候，我非常激动地发现了 K3s 这个项目。K3s 被誉为在可用于资源受限环境下的轻量级 Kubernetes，它还针对 ARM 处理器做出了优化，这让 Kubernetes 集群可以在树莓派上运行得更好。在下文中，我们将会使用 K3s 来创建一个 Kubernetes 集群。准备要按照本文介绍的方式创建 Kubernetes 集群，首先需要准备：至少一个树莓派（包括 SD 卡和电源）网线将所有树莓派连接到一起的交换机或路由器我们会通过在线安装的方式安装 K3s，因此还需要可以连接到互联网。集群概览在这个集群里，我们会使用三个树莓派。其中一个树莓派作为主节点，我们将它命名为 kmaster，并为其分配一个静态 IP 192.168.0.50（注：假设使用的私有网段是 192.168.0.0/24），而另外两个树莓派作为工作节点，分别命名为 knode1 和 knode2，也分别分配 192.168.0.51 和 192.168.0.52 两个 IP 地址。当然，如果你实际的网络布局和上面不同，只要将文中所提及到的 IP 替换成你实际可用的 IP 就可以了。为了不需要通过 IP 来引用某一个节点，我们将每个节点的主机名记录到 PC 的 /etc/hosts 文件当中：echo -e "192.168.0.50\tkmaster" | sudo tee -a /etc/hosts echo -e "192.168.0.51\tknode1" | sudo tee -a /etc/hosts echo -e "192.168.0.52\tknode2" | sudo tee -a /etc/hosts部署主节点我们首先部署主节点。最开始的步骤当然是使用镜像安装最新的 Raspbian，这个步骤可以参考我的另一篇文章，在这里就不展开介绍了。在安装完成之后，启动 SSH 服务，将主机名设置为 kmaster，然后分配静态 IP 192.168.0.50。在主节点上安装 Raspbian 完成后，启动树莓派并通过 ssh 连接上去：ssh pi@kmaster在主节点上执行以下命令安装 K3s：curl -sfL https://get.k3s.io | sh -等到命令跑完以后，一个单节点集群就已经运行起来了。让我们检查一下，还在这个树莓派上执行：sudo kubectl get nodes就会看到这样的输出：NAME STATUS ROLES AGE VERSION kmaster Ready master 2m13s v1.14.3-k3s.1获取 连接令牌 join token 之后我们需要部署工作节点。在工作节点上安装 K3s 的时候，会需要用到连接令牌，它放置在主节点的文件系统上。首先把连接令牌保存出来以便后续使用：sudo cat /var/lib/rancher/k3s/server/node-token部署工作节点通过 SD 卡在每个作为工作节点的树莓派上安装 Raspbian。在这里，我们把其中一个树莓派的主机名设置为 knode1，为其分配 IP 地址 192.168.0.51，另一个树莓派的主机名设置为 knode2，分配 IP 地址 192.168.0.52。接下来就可以安装 K3s 了。启动主机名为 knode1 的树莓派，通过 ssh 连接上去：ssh pi@knode1在这个树莓派上，安装 K3s 的过程和之前差不多，但需要另外加上一些参数，表示它是一个工作节点，需要连接到一个已有的集群上：curl -sfL http://get.k3s.io | K3S_URL=https://192.168.0.50:6443 \ K3S_TOKEN=刚才保存下来的连接令牌 sh -K3S_TOKEN 的值需要替换成刚才保存下来的实际的连接令牌。完成之后，在主机名为 knode2 的树莓派上重复这个安装过程。通过 PC 访问集群现在如果我们想要查看或者更改集群，都必须 ssh 到集群的主节点才能使用 kubectl，这是比较麻烦的。因此我们会将 kubectl 放到 PC 上使用。首先，在主节点上获取一些必要的配置信息，ssh 到 kmaster 上执行：sudo cat /etc/rancher/k3s/k3s.yaml复制上面命令的输出，然后在你的 PC 上创建一个目录用来放置配置文件：mkdir ~/.kube将复制好的内容写入到 ~/.kube/config 文件中，然后编辑该文件，将server: https://localhost:6443改为server: https://kmaster:6443出于安全考虑，只对自己保留这个配置文件的读写权限：chmod 600 ~/.kube/config如果 PC 上还没有安装 kubectl 的话，就可以开始安装了。Kubernetes 官方网站上有各种平台安装 kubectl 的方法说明，我使用的是 Ubuntu 的衍生版 Linux Mint，所以我的安装方法是这样的：sudo apt update && sudo apt install -y apt-transport-https curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list sudo apt update && sudo apt install kubectl上面几个命令的作用是添加了一个包含 Kubernetes 的 Debian 软件库，获取 GPG 密钥以确保安全，然后更新软件包列表并安装 kubectl。如果 kubectl 有更新，我们将会通过 标准软件更新机制 standard software update mechanism 收到通知。现在在 PC 上就可以查看 Kubernetes 集群了：kubectl get nodes输出大概会是这样：NAME STATUS ROLES AGE VERSION kmaster Ready master 12m v1.14.3-k3s.1 knode1 Ready worker 103s v1.14.3-k3s.1 knode1 Ready worker 103s v1.14.3-k3s.1至此，我们已经搭建了一个三节点的 Kubernetes 集群。K3s 的彩蛋如果执行 kubectl get pods --all-namespaces，就会看到其它服务的一些 Pod，比如 Traefik。Traefik 在这里起到是反向代理和负载均衡器的作用，它可以让流量从单个入口进入集群后引导到集群中的各个服务。Kubernetes 支持这种机制，但 Kubernetes 本身不提供这个功能，因此 Traefik 是一个不错的选择，K3s 安装后立即可用的优点也得益于此。在后续的文章中，我们会继续探讨 Traefik 在 Kubernetes ingress 中的应用，以及在集群中部署其它组件。敬请关注。via: https://opensource.com/article/20/3/kubernetes-raspberry-pi-k3s作者：Lee Carpenter 选题：lujun9972 译者：HankChow 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
命令行 Markdown 工具快速、强大、灵活。以下是 4 个值得试一下的工具。（在 Linux 上）在处理 Markdown 格式的文件时，命令行工具会占据主导地位。它们轻巧、快速、强大、灵活，它们大多数都遵循 Unix 哲学只做好一件事。看一下这四个程序，它们可以帮助你在命令行中更有效地处理 Markdown 文件。mdless如果你使用过一段时间的 Linux 命令行，那么你可能对名为 less 的文本查看器很熟悉。当然，你可以使用 less 查看 Markdown 文件，但结果有点枯燥。如何在终端中查看 Markdown 文件效果更好一点？来使用 mdless。你可以使用键盘上的箭头键四处移动，并且 mdless 提供了很好的搜索功能。mdless 不仅会显示文本，而且还会渲染标题、粗体和斜体等格式。它还可以显示表格并语法高亮代码块。你还可以创建一个或多个主题文件来定制 mdless 的外观。Markdown lint 工具你在快速输入时会犯错误。如果你在使用 Markdown（或其他任何标记语言）时丢失了一些格式，那么在将文件转换为另一种格式时可能会有问题。程序员通常使用名为 linter 的工具来检查语法是否正确。你可以使用 Markdown lint 工具对 Markdown 执行相同的操作。在你对 Markdown 文件运行该工具时，它会根据规则集检查格式。这些规则控制着文档的结构，包括标题级别的顺序、不正确的缩进和间距、代码块问题、文件中存在 HTML 等等。规则可能有点严格。但是，在将文件转换为其他格式之前对文件运行 Markdown lint 工具可以防止由于格式错误或不一致引起的麻烦。mdmerge合并任何类型的文件可能会很痛苦。例如，我在整理一本电子书。它是一篇文章集，最初发布在我的每周邮件中。这些文章都放在单独的文件中，作为受虐狂，我以凌乱、手动的方式将它们组合在一起。我希望在开始这个项目之前就知道 mdmerge。这样我可以节省很多时间和精力。mdmerge，你可能已经从名称中猜到了它的作用，它将两个或多个 Markdown 文件合并为一个文件。你无需在命令行中输入文件名。相反，你可以将它们添加到名为 book.txt 的文件中，并将其用作 mdmerge 的输入文件。这并不是 mdmerge 能做的一切。你可以添加对另一个文档的引用（使用 Markdown 格式引用或一段源代码），然后将其放入主文档中。这样一来，你就可以创建针对特定受众定制的主文档。mdmerge 不会是你经常使用的程序。但当你需要时，你会很高兴硬盘上有它。bashblog严格说 bashblog 并不是 Markdown 工具。它获取 Markdown 文件，并使用它们来构建简单的博客或网站。你可以将 bashblog 视为静态站点生成器，但是它没有很多脆弱的依赖关系。一切几乎都在一个不到 50KB 的 shell 脚本中。要使用 bashblog，只需在计算机上安装 Markdown 处理器即可。在此，你可以编辑 Shell 脚本添加有关博客的信息，例如标题、名字、社交媒体链接等。然后运行该脚本。之后会在默认文本编辑器中新建一篇文章。开始输入。保存文章后，你可以发布它或将其另存为草稿。如果你选择发布文章，那么 bashblog 会将你的博客、文章和所有内容生成为一组 HTML 文件，你可以将它们上传到 Web 服务器。它开箱即用，你的博客或许会平淡无奇，但可以使用。你可以根据自己喜好编辑站点的 CSS 文件来改变外观。Pandoc 如何？当然，Panddoc 是一个非常强大的工具，可以将 Markdown 文件转换为其他标记语言。但是，在命令行上使用 Markdown 要比 Pandoc 多。如果你需要 Pandoc，请查看我们发布的文章：在命令行使用 Pandoc 进行文件转换使用 Pandoc 将你的书转换成网页和电子书用 Pandoc 生成一篇调研论文使用 pandoc 将 Markdown 转换为格式化文档via: https://opensource.com/article/20/3/markdown-apps-linux-command-line作者：Scott Nesbitt 选题：lujun9972 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
开源硬件解决方案可以为抵御新型冠状病毒的传播和痛苦做出贡献。开源硬件运动长期以来一直主张维修权的重要性，完全拥有所购买的技术，并能够像音乐一样重新组合和复制部件。因此，在这个充满挑战的时期内，开源硬件为由冠状病毒大流行引起的一些问题提供了一些答案。背景概述首先，全球的硬件开发人员正在努力使用开源解决供应链中的弱点，在过去 30 年中，这种理念推动了新软件技术的大量涌现。过去在硬件运动方面的成功，如 RepRap Project、Open Source Ecology 和 Open Source Beehives，证明了这一点是可以做到的。对于使用 3D 打印和其他技术按需生产安全设备和按需制造它的替换零件，创客们的兴趣日益增加。例如，香港理工大学实验室为医院工作人员提供 3D 打印面罩。意大利初创公司 Isinnova 与米兰 FabLab 合作，为受重灾的意大利北部提供用于呼吸机的 3D 打印替换阀。公司们还发布了设计以适应我们的物理接触需求，例如 Materialise 的 3D 打印免提开门器。这些更换零件和解决问题的示例是一个很好的起点，为挽救生命做出了努力。另一种传统的硬件技术正在加速发展：缝纫。法新社报道说，全球急需口罩，来自世界卫生组织的指导也指明了其重要性。随着一次性口罩要优先供给于医护人员，捷克共和国的人们开始缝制自己的口罩。（重复使用的口罩确实会带来细菌问题。）Facebook 小组“捷克缝制口罩”开始在他们的国家解决这个问题，成千上万的成员开始用起了他们的家用缝纫机。开源硬件设备和机械项目也越来越受欢迎。首先，有一些测试性设备具备高精度且功能强大。其次，在没有其他选择方案的情况下，有一些医疗设备（顶多）可以归类为现场级。这些项目将在下面详细概述。为了解更多信息，我与总部位于芝加哥的 Tapster Robotics 的创始人兼首席执行官 Jason Huggins 进行了交谈。Tapster Robotics 使用 3D 打印、计算机数控（CNC）加工和 Arduino 等开源电子产品设计和制造台式机器人。他兼具技术知识和工业能力，具有很高的影响力。他想投入自己公司的资源来帮助这场斗争。“基本上，我们现在正处于第二次世界大战的动员时刻。即使我不是医生，我们仍然应该遵循希波克拉底誓言。无论我做什么，我都不想让问题变得更糟”，Huggins 解释，他认为：“作为对策，世卫组织执行主任 Michael Ryan 博士发表了这样的评论：‘速度胜过完美’。”哇！这个人是疾病传播的全球权威。如果您是领导者（无论以何种身份），请注意。如果不是，也请注意。pic.twitter.com/bFogaekehM— Jim RichardsSh?wgram（@JIMrichards1010）2020 年 3 月 15 日Huggins 在应需提供方面具有丰富的经验。他的努力有助于 Healthcare.gov 在挑战性的最初启动后得以扩展。他还创建了软件行业标准的测试框架 Selenium 和 Appium。有了这一经验，他的建议非常值得考虑。我还与 Tyson Law 的西雅图律师 Mark Tyson 进行了交谈，他的合作对象是初创公司和小型企业。他在快速发展的行业中与敏捷公司合作有着直接的经验。在阐述整个问题时，Tyson 说到：《 善良的撒玛利亚人法 Good Samaritan law 》保护志愿者（即“好撒玛利亚人”）免于因其在紧急情况下提供援助的决定而承担责任。尽管这些法律的具体内容因州而异，但它们具有共同的公共政策依据：即鼓励旁观者帮助遇到紧急情况的其他人。可以想象，除了传统的把车祸的受害者从伤害中拉出来之外，这种理论依据可以证明在不太传统的环境中应用这类法律的合理性。对于这种特定情况，Tyson 指出：“在采取行动之前，创客们明智的做法是与律师沟通一下，以针对特定的州进行风险评估。还应谨慎地要求大型机构（例如医院或保险公司）通过合同接受潜在的责任风险，例如，通过使用赔偿协议，使医院或其保险人同意赔偿创客们的责任。”Tyson 明白情况的紧迫性和严重性。使用合同的这种选择并不意味着障碍。相反，这可能是一种帮助其大规模采用的方法，以更快地产生更大的变化。这取决于你或你的机构。综上所述，让我们探索正在使用或正在开发中的项目（可能很快就可以部署）。7 个与新冠病毒对抗的开源硬件项目OpentronsOpentrons 的开源实验室自动化平台由一套开源硬件、经过验证的实验室器具、消耗品、试剂和工作站组成。Opentrons 表示，其产品可以“在下订单后几天内每天自动进行多达 2400 个测试”的系统，可以极大地帮助提高新冠病毒测试规模。它计划在 7 月 1 日之前提升到多达 100 万个测试样本。来自 Opentrons 网站，版权所有该公司已经在与联邦和地方政府机构合作，以确定其系统是否可以在紧急使用授权下用于临床诊断。 Opentrons 在 Apache 2.0 许可证下共享。我最初是从与该项目有联系的生物学家 Kristin Ellis 那里得知它的。Chai 的 Open qPCRChai 的 Open qPCR 设备使用聚合酶链反应（PCR）快速检测物品表面（例如，门把手和电梯按钮）上的拭子，以查看是否存在新型冠状病毒。这种在 Apache 2.0 许可证下共享的开源硬件使用 BeagleBone 低功耗 Linux 计算机。Chai 的 Open qPCR 提供的数据可以使公共卫生、公民和企业领导者做出有关清洁、缓解、关闭设施、接触追踪和测试的更明智的决策。OpenPCROpenPCR 是 Chai Open qPCR 的创建者 Josh Perfetto 和 Jessie Ho 的 PCR 测试设备套件。与他们的前一个项目相比，这更像是一种 DIY 开源设备，但它具有相同的使用场景：使用环境测试来识别野外冠状病毒。正如该项目页面所指出的那样，“能够检测这些病原体的传统实时 PCR 设备通常花费超过 30,000 美元，而且不适合在现场使用。”由于 OpenPCR 是用户构建的工具包，并且在 GPLv3.0 许可证下共享，因此该设备旨在使分子诊断的访问大众化。来自 OpenPCR 网站，版权所有而且，就像任何优秀的开源项目一样，它也有一个衍生产品！瑞士的 Gaudi Labs 推出的 WildOpenPCR 也以 GPLv3.0 许可证共享。PocketPCRGaudi Labs 的 PocketPCR 热循环仪可通过升高和降低小试管中液体的温度来激活生物反应。它可以通过简单的 USB 电源适配器供电，该适配器可以绑定到设备上，也可以单独使用，不使用计算机或智能手机时可使用预设参数。来自 PocketPCR 网站，版权所有与本文所述的其他 PCR 产品一样，此设备可能有助于对冠状病毒进行环境测试，尽管其项目页面并未明确说明。PocketPCR 在 GPLv3.0 许可证下共享。Open Lung 低资源呼吸机Open Lung 低资源呼吸机是一种快速部署的呼吸机，它以气囊阀罩（BVM）（也称为 Ambu 气囊）为核心组件。Ambu 气囊已批量生产，经过认证，体积小，机械简单，并且适用于侵入性导管和口罩。 Open Lung 呼吸机使用微电子技术来感测和控制气压和流量，以实现半自主运行。Open Lung，GitLab这个早期项目拥有一支由数百名贡献者组成的大型团队，领导者包括：Colin Keogh、David Pollard、Connall Laverty 和 Gui Calavanti。它是以 GPLv3.0 许可证共享的。Pandemic 呼吸机Pandemic 呼吸机是 DIY 呼吸机的原型。像 RepRap 项目一样，它在设计中使用了常用的硬件组件。该项目已由用户 Panvent 于 10 多年前上传到 Instructables，并且有六个主要的生产步骤。该项目是以 CC BY-NC-SA 许可证共享的。Folding at HomeFolding at Home 是一个分布式计算项目，用于模拟蛋白质动力学，包括蛋白质折叠的过程以及与多种疾病有关的蛋白质运动。这是一个面向公民科学家、研究人员和志愿者的行动呼吁，类似于退役的 SETI@Home 项目使用家中的计算机来运行解码计算。如果你是具备强大计算机硬件功能的技术人员，那么这个项目适合你。Vincent Voelz，CC BY-SA 3.0Folding at Home 项目使用马尔可夫状态模型（如上所示）来建模蛋白质可能采取的形状和折叠途径，以寻找新的治疗机会。你可以在华盛顿大学生物物理学家 Greg Bowman 的帖子《它是如何运作的以及如何提供帮助》中找到有关该项目的更多信息。该项目涉及来自许多国家和地区（包括香港、克罗地亚、瑞典和美国）的财团的学术实验室、贡献者和公司赞助者。 在 GitHub 上，在混合了 GPL 和专有许可证下共享，并且可以在 Windows、macOS 和 GNU/Linux（例如 Debian、Ubuntu、Mint、RHEL、CentOS、Fedora）。许多其他有趣的项目这些项目只是在开源硬件领域中解决或治疗新冠病毒活动中的一小部分。在研究本文时，我发现了其他值得探索的项目，例如：Coronavirus Tech Handbook 提供的开源呼吸机、氧气浓缩器等来自 ProjectOpenAir 的 有用的工程Hackaday 上的开源呼吸机黑客马拉松约翰·霍普金斯急诊医学住院医师 Julian Botta 的简单开源机械呼吸机规范与冠状病毒有关的网络钓鱼、恶意软件和随机软件正在增加，作者：Shannon Morse将低成本的 CPAP 鼓风机转换为基本呼吸机，作者： jcl5m1A.I.R.E. 论坛上关于开源呼吸器和风扇的讨论（西班牙语）关于新冠病毒的开源医疗硬件的特殊问题，作者：Elsevier HardwareX这些项目遍布全球，而这种全球合作正是我们所需要的，因为病毒无视国界。新冠病毒大流行在不同时期以不同方式影响国家，因此我们需要一种分布式方法。正如我和同事 Steven Abadie 在 OSHdata 2020 报告中所写的那样，开源硬件运动是全球性运动。参与该认证项目的个人和组织遍布全球 35 个国家地区和每个半球。OSHdata，CC BY-SA 4.0 国际版如果你有兴趣加入这场与全球开源硬件开发人员的对话，请加入开源硬件峰会的 Discord 服务器，并通过专用渠道进行有关新冠病毒的讨论。你在这里可以找到机器人专家、设计师、艺术家、固件和机械工程师、学生、研究人员以及其他共同为这场战争而战的人。希望可以看到你。via: https://opensource.com/article/20/3/open-hardware-covid19作者：Harris Kenny 选题：lujun9972 译者：wxy 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出