mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-01-25 23:11:02 +08:00
commit
b092b14fe8
71
published/20180306 Exploring free and open web fonts.md
Normal file
71
published/20180306 Exploring free and open web fonts.md
Normal file
@ -0,0 +1,71 @@
|
||||
探索自由而开放的 Web 字体
|
||||
======
|
||||
|
||||
> 谷歌字体和开放字体库中的免费 Web 字体已经改变了游戏规则,但仅在有限的范围内。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202003/08/174910xoklikblgkkbooib.jpg)
|
||||
|
||||
毫无疑问,近些年来互联网的面貌已经被开源字体所改变。早在 2010 年之前,你在 Web 浏览器上几乎只能看到微软制作的通常“Web 安全”的[核心字体][1]。但这一年(2010)正好是好几轮技术革新开始的见证之年:<ruby>[Web 开放字体格式][2]<rt>Web Open Font Format</rt></ruby>(WOFF)的引入为通过 HTTP 有效地传输字体文件提供了一个开放的标准,以及像[谷歌字体][3]和<ruby>[开放字体库][4]<rt>Open Font Library</rt></ruby>这样的 Web 字体服务的推出,使得 Web 内容发布者可以在开源许可证之下免费使用海量的字体库。
|
||||
|
||||
这些事件对 Web 排版的积极影响再夸大都不过分。但是要将 Web 开放字体的成功与整个开源排版等同起来,并得到结论——挑战已经远离了我们,困难悉数被解决了——却很容易。然而事实并非如此,如果你很关注字体,那么好消息是你有好多机会参与到对这些字体的改进工作当中去。
|
||||
|
||||
对新手来说,至关重要的是必须要意识到谷歌字体和开放字体库提供了专用的服务(为网页提供字体),而没有为其他使用情况制定字体解决方案。这不是服务方面的缺点,这只是意味着我们必须去开发其它的解决方案。
|
||||
|
||||
需要解决的问题还非常多。可能最明显的例子就是给 Linux 桌面计算机的其他软件安装字体所遇到的尴尬情况。你可以通过任何一种服务下载任何一种 Web 字体,但是你得到的只是一个最普通的压缩包文件,里面有一些 TTF 或 OTF 二进制文件和一个普通文本文件的许可证。接下来会发生什么完完全全需要你去猜。
|
||||
|
||||
大部分用户很快学会了“正确”的步骤就是手动地复制这些字体二进制文件到他们硬盘里几个特殊文件夹里的某一个里。但是这样做只能使这个文件对操作系统可见。它并不能为用户体验带来什么提升。再强调一遍,这不是 Web 字体服务的缺陷,相反它佐证了对于关于服务到哪里停止和需要在其他方面做更多工作的观点。
|
||||
|
||||
在用户视角来说,一个巨大的提升可能就是在“只是下载”这个阶段,操作系统或者桌面环境变得更智能。系统或桌面环境不仅会把字体文件安装到正确的位置上,更重要的是,当用户选择要在一个项目中使用的字体时,它会自己添加用户所需要的重要的元数据。
|
||||
|
||||
这些附加信息包含的内容与它如何呈现给用户与另一个挑战有关:与其它操作系统相比,在 Linux 环境管理一个字体库显然不那么令人满意。字体管理器总是时不时的出现一下(例如 [GTK+ 字体管理器][5],这是最近的一个例子),但是它们很少变得流行起来。我一直在思考一大堆这些软件让人失望的方面。一个核心的原因是它们把自己局限于只展示内嵌在二进制字体文件内的信息:基本字符集的覆盖、粗细/宽度和斜率的设定,内置的许可证和版权说明等等。
|
||||
|
||||
但是除了这些内嵌数据中的内容,在选择字体的过程中还涉及很多决策。严肃的字体用户,像信息设计者、杂志文章作者,或者书籍美工设计者,他们的字体选择是根据每一份文件的要求和需求做出的。这当然包含了许可证信息,但它还包含了更多,像关于设计师和厂商的信息、潮流风格的趋势,或者字体在使用中的细节。
|
||||
|
||||
举个例子,如果你的文档包含了英语和阿拉伯文,你多半想要拉丁文和阿拉伯文的字体由同时熟悉这两种<ruby>字母系统<rt>script</rt></ruby>的设计师所设计。否则,你将浪费一大堆时间来微调字体大小和行间距来使两种字母系统良好地结合在一起。你可能从经验中学到,某些设计师或字体厂商比其他人更善于多种字母系统设计。或许和你职业相关的是今天的时尚杂志几乎无一例外的采用 “[Didone][6]”风格的字体,“[Didone][6]”是指一种两百多年前最先被 [Firmin Didot][7] 和 [Giambattista Bodoni][8] 设计出来的超高反差的字体风格。这种字体恰好就是现在的潮流。
|
||||
|
||||
但是像 Didone、Didot 或 Bodoni 这些术语都不可能会出现在二进制文件的内置数据当中,你也不容易判断拉丁文和阿拉伯文是否相得益彰或其它关于字体的历史背景。这些信息有可能出现在补充的材料中,类似某种字形样本或字体文件中,如果这些东西存在的话。
|
||||
|
||||
<ruby>字形样本<rt>specimen</rt></ruby>是一份设计好的文档(一般是 PDF),它展示了这种字体的使用情况,而且包括了背景信息。字形样本经常在挑选字体时充当市场营销和外观样例的双重角色。一份精心设计的样本展示了字体在实际应用中的情况和在自动生成的字符表中所不能体现的风格。字形样本文件也有可能包含了一些其他重要信息,比如怎样激活字体的 OpenType 特性、提供的数学表达式或古体字,或者它在支持的多种语言上的风格变化。在字体管理应用程序中向用户提供此类材料,对于帮助用户找到适合其项目需求的字体将大有帮助。
|
||||
|
||||
当然,如果我们希望一个字体管理软件能够处理文件和样本问题,我们也必须仔细观察一下各种发行版提供的字体包所随附的内容。Linux 的用户刚开始只有自动安装的那几种字体,并且发行版存储库提供的包是大部分用户除了下载通用的压缩包档案之外的唯一字体来源。这些包往往非常的“简陋”。商业字体总的来说都包含了样本、文档,还有其他的支持项目,然而开源字体往往没有这些配套文件。
|
||||
|
||||
也有一些优秀的开放字体提供了高质量的样本和文档(例如 [SIL Gentium][9] 和 [Bungee][10] 是两种差异明显但是都有效的方案),但是它们几乎不涉足下游的打包工作链。我们显然可以做的更好一些。
|
||||
|
||||
要在系统的字体交互方面提供更丰富的用户体验上面还存在一些技术问题。一方面,[AppStream][11] 的元数据标准定义了一些字体文件特有的参数,但是到现在为止,这些参数没有包含样本、设计师/厂商和其他相关细节的任何信息。另外一个例子,[SPDX][13](<ruby>软件包数据交换<rt>Software Package Data Exchange</rt></ruby>)格式也没有包含太多用于分发字体的软件许可证(及许可证变体)。
|
||||
|
||||
最后,就像任何一个唱片爱好者都会告诉你的,一个不允许你编辑和完善你的 MP3 曲库中的 ID3 信息的音乐播放器很快就会变得令人失望(LCTT 译注:ID3 信息是 MP3 文件头部的元信息,用于存储歌曲信息)。你想要处理标签里的错误、想要添加注释和专辑封面之类的信息,本质上,这就是完善你的音乐库。同样,你可能也想要让你的本地字体库也保持在一个方便使用的状态。
|
||||
|
||||
但是改动字体文件的内置数据一直有所忌讳,因为字体往往是被内置或附加到其他文件里的。如果你随意改变了字体二进制文件中的字段,然后将其与你的演示文稿一起重新分发,那么下载这些演示文稿的任何人最终都会得到错误的元数据,但这个错误不是他们自己造成的。所以任何一个要改善字体管理体验的人都要想明白如何从策略上解决对内置或外置的字体元数据的重复修改。
|
||||
|
||||
除了技术角度之外,丰富的字体管理经验也是一项设计挑战。就像我在前面说的一样,有几种开放字体也带了良好的样本和精心编写的文档。但是更多的字体包这两者都没有,还有大量的更老的字体包已经没有人维护了。这很可能意味着大部分开放字体包想要获得样本和证明文件的唯一办法就是让社区去创建它们。
|
||||
|
||||
也许这是一个很高的要求。但是开源设计社区现在比以往任何时候都要庞大,它是整个自由开源软件运动中的一个高度活跃的组成部分。所以谁知道呢,也许明年这个时候会发现,在 Linux 桌面系统查找、下载和使用字体会变成一种完全不同的体验。
|
||||
|
||||
在这一连串关于现代 Linux 用户的文字设计上的挑战的思考中包含了打包、文档设计,甚至有可能需要在桌面环境加入不少新的软件部分。此外还有其他一系列的东西也需要考虑。其共通性就是在 Web 字体服务不可及的地方,事情就会变得更加困难。
|
||||
|
||||
从我的视角来看,最好的消息是现在比起以前有更多的人对这个话题感兴趣。我认为我们要感谢像谷歌字体和开放字体库这样的 Web 字体服务巨头让开放字体得到了更高的关注。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/3/webfonts
|
||||
|
||||
作者:[Nathan Willis][a]
|
||||
译者:[Fisherman110](https://github.com/Fisherman110)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/n8willis
|
||||
[1]:https://en.wikipedia.org/wiki/Core_fonts_for_the_Web
|
||||
[2]:https://en.wikipedia.org/wiki/Web_Open_Font_Format
|
||||
[3]:https://fonts.google.com/
|
||||
[4]:https://fontlibrary.org/
|
||||
[5]:https://fontmanager.github.io/
|
||||
[6]:https://en.wikipedia.org/wiki/Didone_(typography)
|
||||
[7]:https://en.wikipedia.org/wiki/Firmin_Didot
|
||||
[8]:https://en.wikipedia.org/wiki/Giambattista_Bodoni
|
||||
[9]:https://software.sil.org/gentium/
|
||||
[10]:https://djr.com/bungee/
|
||||
[11]:https://www.freedesktop.org/wiki/Distributions/AppStream/
|
||||
[12]:https://www.freedesktop.org/software/appstream/docs/sect-Metadata-Fonts.html
|
||||
[13]:https://spdx.org/
|
@ -1,28 +1,28 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11968-1.html)
|
||||
[#]: subject: (How to set up your own fast, private open source mesh network)
|
||||
[#]: via: (https://opensource.com/article/20/2/mesh-network-freemesh)
|
||||
[#]: author: (Spencer Thomason https://opensource.com/users/spencerthomason)
|
||||
|
||||
如何建立自己的快速、私有的开源网状网络
|
||||
如何建立自己的快速、私有的开源网状网络(mesh)
|
||||
======
|
||||
|
||||
> 只需要不到 10 分钟的安装时间,就可以用 FreeMesh 搭建一个经济实惠、性能卓越、尊重隐私的网格系统。
|
||||
|
||||
![people on top of a connected globe][1]
|
||||
![](https://img.linux.net.cn/data/attachment/album/202003/06/234848jaga52a0wx05w0f0.jpg)
|
||||
|
||||
[FreeMesh][2] 系统有望为大众带来完全开源的<ruby>网格网络<rt>mesh network</rt></ruby>。我最近有机会进行了测试;它安装迅速,性能非常好 —— 特别是相对它的价格而言。
|
||||
[FreeMesh][2] 系统有望为大众带来完全开源的<ruby>网状网络<rt>mesh network</rt></ruby>(LCTT 译注:也称之为“多跳网络”)。我最近有机会对它进行了测试;它安装迅速,性能非常好 —— 特别是相对它的价格而言。
|
||||
|
||||
### 为什么要网格化和开源?
|
||||
|
||||
使用开源的原因很简单:隐私。有了 FreeMesh,你的数据就是你自己的。它不会跟踪或收集数据。不相信吗?毕竟,你可以轻松检查 —— 它是开源的!而其它大型高科技企业集团提供的一些流行的网格解决方案,你是否相信它们会保护你的数据?
|
||||
使用开源的原因很简单:隐私。有了 FreeMesh,你的数据就是你自己的。它不会跟踪或收集数据。不相信吗?毕竟,你可以轻松检查 —— 它是开源的!而其它大型高科技企业集团提供的一些流行的网状网络解决方案,你是否相信它们会保护你的数据?
|
||||
|
||||
另一个重要因素:更新。FreeMesh 表示,它将致力于定期发布安全性和性能更新。从现在起到 10 年后呢?使用开放源代码解决方案,你可以根据需要自由地更新产品。
|
||||
另一个重要因素:更新。FreeMesh 表示,它将致力于定期发布安全性和性能更新。从现在起到 10 年后呢?使用开源解决方案,你可以根据需要自由地更新产品。
|
||||
|
||||
那么为什么要用网格呢?在网状网络中,多个无线路由器一起工作以广播单个超大型的无线网络。网状网络中的每个路由器都可与其他路由器智能地通信,以便为你的数据提供最佳的“路径”。FreeMesh 网站上的以下图片突出显示了使用单个无线路由器和网状网络之间的区别。 红色网络表示单个无线路由器,绿色网络是网状网络。
|
||||
那么为什么要用网状网络呢?在网状网络中,多个无线路由器一起工作以广播单个超大型的无线网络。网状网络中的每个路由器都可与其他路由器智能地通信,以便为你的数据提供最佳的“路径”。FreeMesh 网站上的以下图片突出显示了使用单个无线路由器和网状网络之间的区别。红色网络表示单个无线路由器,绿色网络是网状网络。
|
||||
|
||||
![单路由器网络] [3]
|
||||
|
||||
@ -52,7 +52,7 @@ FreeMesh 路由器的一些规格非常好:
|
||||
|
||||
![FreeMesh 设置步骤 1][8]
|
||||
|
||||
2、等待约 30 至 60 秒。设置完成后,节点将闪烁其 LED。
|
||||
2、等待约 30 至 60 秒。设置完成后,节点的 LED 将会闪烁。
|
||||
|
||||
![FreeMesh 设置步骤 2][9]
|
||||
|
||||
@ -74,7 +74,7 @@ FreeMesh 是开箱即用的,它由 OpenWRT 和 LuCI 组合而成。它具有
|
||||
|
||||
设置完 FreeMesh 系统后,我将节点移动到了房屋周围的各个地方。我使用 [iPerf][13] 测试带宽,它达到了约 150Mbps。WiFi 可能会受到许多环境变量的影响,因此你的结果可能会有所不同。节点与主路由器之间的距离在带宽中也有很大的影响。
|
||||
|
||||
但是,网状网络的真正优势不是高峰速度,而是整个空间的平均速度要好得多。即使在我家很远的地方,我仍然能够流媒体播放视频并正常工作。我甚至可以在后院工作。在出门之前,我只是将一个节点重新放在窗口前面而已。
|
||||
但是,网状网络的真正优势不是高峰速度,而是整个空间的平均速度要好得多。即使在我家很远的地方,我仍然能够用流媒体播放视频并正常工作。我甚至可以在后院工作。在出门之前,我只是将一个节点重新放在窗口前面而已。
|
||||
|
||||
### 结论
|
||||
|
||||
@ -91,7 +91,7 @@ via: https://opensource.com/article/20/2/mesh-network-freemesh
|
||||
作者:[Spencer Thomason][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,8 +1,8 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11967-1.html)
|
||||
[#]: subject: (PHP Development on Fedora with Eclipse)
|
||||
[#]: via: (https://fedoramagazine.org/php-development-on-fedora-with-eclipse/)
|
||||
[#]: author: (Mehdi Haghgoo https://fedoramagazine.org/author/powergame/)
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
![][1]
|
||||
|
||||
[Eclipse][2] 是由 Eclipse 基金会开发的功能全面的免费开源 IDE。自 2001 年以来一直存在。你可以在此 IDE 中编写从 C/C++ 和 Java 到 PHP、Python、HTML、JavaScript、Kotlin 等。
|
||||
[Eclipse][2] 是由 Eclipse 基金会开发的功能全面的自由开源 IDE。它诞生于 2001 年。你可以在此 IDE 中编写各种程序,从 C/C++ 和 Java 到 PHP,乃至于 Python、HTML、JavaScript、Kotlin 等等。
|
||||
|
||||
### 安装
|
||||
|
||||
@ -36,15 +36,15 @@ sudo dnf install eclipse-pdt
|
||||
|
||||
### 示例项目
|
||||
|
||||
现在已经安装了 IDE,让我们创建一个简单的 PHP 项目。进入 _File →New → Project_。在出现的对话框中,选择 _PHP project_。输入项目的名称。你可能还需要更改其他一些选项,例如更改项目的默认位置,启用 JavaScript 以及更改 PHP 版本。请看以下截图。
|
||||
现在已经安装了 IDE,让我们创建一个简单的 PHP 项目。进入 “File →New → Project”。在出现的对话框中,选择 “PHP project”。输入项目的名称。你可能还需要更改其他一些选项,例如更改项目的默认位置,启用 JavaScript 以及更改 PHP 版本。请看以下截图。
|
||||
|
||||
![Create A New PHP Project in Eclipse][3]
|
||||
|
||||
你可以单击 _Finish_ 按钮创建项目,或按 _Next_ 配置其他选项,例如添加包含和构建路径。在大多数情况下,你无需更改这些设置。
|
||||
你可以单击 “Finish” 按钮创建项目,或按 “Next” 配置其他选项,例如添加包含和构建路径。在大多数情况下,你无需更改这些设置。
|
||||
|
||||
创建项目后,右键单击项目文件夹,然后选择 _New→PHP File_ 将新的 PHP 文件添加到项目。在本教程中,我将其命名为 _index.php_,这是每个 PHP 项目中公认的默认文件。
|
||||
创建项目后,右键单击项目文件夹,然后选择 “New→PHP File” 将新的 PHP 文件添加到项目。在本教程中,我将其命名为 `index.php`,这是每个 PHP 项目中公认的默认文件。
|
||||
|
||||
![][4]
|
||||
![add a new PHP file][4]
|
||||
|
||||
接着在新文件中添加代码。
|
||||
|
||||
@ -52,9 +52,9 @@ sudo dnf install eclipse-pdt
|
||||
|
||||
在上面的例子中,我在同一页面上使用了 CSS、JavaScript 和 PHP 标记,主要是为了展示 IDE 能够支持所有这些标记。
|
||||
|
||||
页面完成后,你可以将文件移至 Web 服务器文档根目录或在项目目录中创建一个开发 PHP 服务器来查看输出。
|
||||
页面完成后,你可以将文件移至 Web 服务器文档根目录或在项目目录中创建一个 PHP 开发服务器来查看输出。
|
||||
|
||||
借助 Eclipse 中的内置终端,我们可以直接在 IDE 中启动 PHP 开发服务器。只需单击工具栏上的终端图标(![Terminal Icon][6]),然后单击 _OK_。在新终端中,进入项目目录,然后运行以下命令:
|
||||
借助 Eclipse 中的内置终端,我们可以直接在 IDE 中启动 PHP 开发服务器。只需单击工具栏上的终端图标(![Terminal Icon][6]),然后单击 “OK”。在新终端中,进入项目目录,然后运行以下命令:
|
||||
|
||||
```
|
||||
php -S localhost:8080 -t . index.php
|
||||
@ -73,7 +73,7 @@ via: https://fedoramagazine.org/php-development-on-fedora-with-eclipse/
|
||||
作者:[Mehdi Haghgoo][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,31 +1,31 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11970-1.html)
|
||||
[#]: subject: (Use logzero for simple logging in Python)
|
||||
[#]: via: (https://opensource.com/article/20/2/logzero-python)
|
||||
[#]: author: (Ben Nuttall https://opensource.com/users/bennuttall)
|
||||
|
||||
使用 logzero 在 Python 中进行简单日志记录
|
||||
======
|
||||
一个方便的日志库快速入门,来帮助你掌握这个重要的编程概念。
|
||||
![Snake charmer cartoon with a yellow snake and a blue snake][1]
|
||||
|
||||
logzero 库使日志记录就像打印语句一样容易,是简单性的杰出代表。我不确定 logzero 的名称是否要与 pygame-zero、GPIO Zero 和 guizero 这样的 “zero 样板库”契合,但是肯定属于该类别。它是一个 Python 库,使得日志记录变得简单明了。
|
||||
> 快速了解一个方便的日志库,来帮助你掌握这个重要的编程概念。
|
||||
|
||||
你可以使用它的基本日志记录到标准输出,就像你可以使用 print 来获得信息和调试一样,它还有学习更高级日志记录(例如记录到文件)的平滑学习曲线。
|
||||
![](https://img.linux.net.cn/data/attachment/album/202003/07/122445v743hy7ajdyrrda1.jpg)
|
||||
|
||||
logzero 库使日志记录就像打印语句一样容易,是简单性的杰出代表。我不确定 logzero 的名称是否要与 pygame-zero、GPIO Zero 和 guizero 这样的 “zero 样板库”契合,但是肯定属于该类别。它是一个 Python 库,可以使日志记录变得简单明了。
|
||||
|
||||
你可以使用它基本的记录到标准输出的日志记录,就像你可以使用 print 来获得信息和调试一样,学习它的更高级日志记录(例如记录到文件)的学习曲线也很平滑。
|
||||
|
||||
首先,使用 pip 安装 logzero:
|
||||
|
||||
|
||||
```
|
||||
`$ sudo pip3 install logzero`
|
||||
$ sudo pip3 install logzero
|
||||
```
|
||||
|
||||
在 Python 文件中,导入 logger 并尝试以下一个或所有日志实例:
|
||||
|
||||
|
||||
```
|
||||
from logzero import logger
|
||||
|
||||
@ -39,14 +39,13 @@ logger.error("error")
|
||||
|
||||
![Python, Raspberry Pi: import logger][2]
|
||||
|
||||
因此现在不要再使用 **print** 来了解发生了什么,而应使用有相关日志级别的 logger。
|
||||
因此现在不要再使用 `print` 来了解发生了什么,而应使用有相关日志级别的日志器。
|
||||
|
||||
### 在 Python 中将日志写入文件
|
||||
|
||||
如果你阅读至此,并会在你写代码时做一点改变,这对我就足够了。如果你要了解更多,请继续阅读!
|
||||
|
||||
写到**标准输出**对于测试新程序不错,但是仅当你登录到运行脚本的计算机时才有用。在很多时候,你需要远程执行代码并在事后查看错误。这种情况下,记录到文件很有帮助。让我们尝试一下:
|
||||
|
||||
写到标准输出对于测试新程序不错,但是仅当你登录到运行脚本的计算机时才有用。在很多时候,你需要远程执行代码并在事后查看错误。这种情况下,记录到文件很有帮助。让我们尝试一下:
|
||||
|
||||
```
|
||||
from logzero import logger, logfile
|
||||
@ -54,32 +53,28 @@ from logzero import logger, logfile
|
||||
logfile('/home/pi/test.log')
|
||||
```
|
||||
|
||||
现在,你的日志条目将记录到文件 **test.log** 中。记住确保[脚本有权限] [3]写入该文件及其目录结构。
|
||||
现在,你的日志条目将记录到文件 `test.log` 中。记住确保[脚本有权限][3]写入该文件及其目录结构。
|
||||
|
||||
你也可以指定更多选项:
|
||||
|
||||
|
||||
```
|
||||
`logfile(’/home/pi/test.log’, maxBytes=1e6, backupCount=3)`
|
||||
logfile('/home/pi/test.log', maxBytes=1e6, backupCount=3)
|
||||
```
|
||||
|
||||
现在,当提供给 **logfile** 文件达到 1MB(10^6 字节)时,它将通过 **test.log.1**、**test.log.2** 等文件轮询写入。这种行为可以避免系统打开和关闭大量 I/O 密集的日志文件,以至于系统无法打开和关闭。你或许还要记录到 **/var/log**。假设你使用的是 Linux,那么创建一个目录并将用户设为所有者,以便可以写入该目录:
|
||||
|
||||
现在,当提供给 `test.log` 文件的数据达到 1MB(10^6 字节)时,它将通过 `test.log.1`、`test.log.2` 等文件轮替写入。这种行为可以避免系统打开和关闭大量 I/O 密集的日志文件,以至于系统无法打开和关闭。更专业一点,你或许还要记录到 `/var/log`。假设你使用的是 Linux,那么创建一个目录并将用户设为所有者,以便可以写入该目录:
|
||||
|
||||
```
|
||||
$ sudo mkdir /var/log/test
|
||||
$ sudo chown pi /var/log/test
|
||||
```
|
||||
|
||||
然后在你的 Python 代码中,更改 **logfile** 路径:
|
||||
|
||||
然后在你的 Python 代码中,更改 `logfile` 路径:
|
||||
|
||||
```
|
||||
`logfile(’/var/log/test/test.log’, maxBytes=1e6, backupCount=3)`
|
||||
logfile('/var/log/test/test.log', maxBytes=1e6, backupCount=3)
|
||||
```
|
||||
|
||||
当要在 **logfile** 中捕获异常时,可以使用 **logging.exception**:。
|
||||
|
||||
当要在 `logfile` 中捕获异常时,可以使用 `logging.exception`:
|
||||
|
||||
```
|
||||
try:
|
||||
@ -88,8 +83,7 @@ except Exception as e:
|
||||
logger.exception(e)
|
||||
```
|
||||
|
||||
这将输出(在 b 为零的情况下):
|
||||
|
||||
这将输出(在 `b` 为零的情况下):
|
||||
|
||||
```
|
||||
[E 190422 23:41:59 test:9] division by zero
|
||||
@ -99,8 +93,7 @@ except Exception as e:
|
||||
ZeroDivisionError: division by zero
|
||||
```
|
||||
|
||||
你会得到日志,还有完整回溯。另外,你可以使用 **logging.error** 并隐藏回溯:
|
||||
|
||||
你会得到日志,还有完整回溯。另外,你可以使用 `logging.error` 并隐藏回溯:
|
||||
|
||||
```
|
||||
try:
|
||||
@ -111,28 +104,20 @@ except Exception as e:
|
||||
|
||||
现在,将产生更简洁的结果:
|
||||
|
||||
|
||||
```
|
||||
`[E 190423 00:04:16 test:9] ZeroDivisionError: division by zero`
|
||||
[E 190423 00:04:16 test:9] ZeroDivisionError: division by zero
|
||||
```
|
||||
|
||||
* * *
|
||||
|
||||
* * *
|
||||
|
||||
* * *
|
||||
|
||||
**![Logging output][4]**
|
||||
![Logging output][4]
|
||||
|
||||
你可以在 [logzero.readthedocs.io] [5] 中阅读更多选项。
|
||||
|
||||
### logzero 为教育而生
|
||||
|
||||
对于新手程序员来说,日志记录可能是一个具有挑战性的概念。大多数框架依赖于流控制和大量变量操作来生成有意义的日志,但是 logzero不同。由于它的语法类似于 print 语句,因此它在教育上很成功,因为它无需解释其他概念。在你的下个项目中试试它。
|
||||
对于新手程序员来说,日志记录可能是一个具有挑战性的概念。大多数框架依赖于流控制和大量变量操作来生成有意义的日志,但是 logzero 不同。由于它的语法类似于 `print` 语句,因此它在教育上很成功,因为它无需解释其他概念。在你的下个项目中试试它。
|
||||
|
||||
\--
|
||||
|
||||
_此文章最初发布在[我的博客] [6]上,经许可重新发布。_
|
||||
此文章最初发布在[我的博客][6]上,经许可重新发布。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -141,7 +126,7 @@ via: https://opensource.com/article/20/2/logzero-python
|
||||
作者:[Ben Nuttall][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,41 +1,41 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11971-1.html)
|
||||
[#]: subject: (Install GNU Emacs on Windows)
|
||||
[#]: via: (https://opensource.com/article/20/3/emacs-windows)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
在 Windows 上安装 GNU Emacs
|
||||
如何在 Windows 上安装 GNU Emacs
|
||||
======
|
||||
即使你的操作系统是闭源的,你仍然可以使用这个流行的开源文本编辑器。
|
||||
![Tall building with windows][1]
|
||||
|
||||
GNU Emacs 是一个专为各种程序员设计的流行的文本编辑器。因为它是在 Unix 上开发的,并在 Linux(macOS 中也有)上得到了广泛使用,所以人们有时没有意识到它也可用于 Microsoft Windows 上。你也无需成为有经验的或专职的程序员即可使用 Emacs。只需单击几下就可以下载并安装 Emacs,本文向你展示了如何进行。
|
||||
> 即使你的操作系统是闭源的,你仍然可以使用这个流行的开源文本编辑器。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202003/08/094942ihwcnsqojnup46wo.jpg)
|
||||
|
||||
GNU Emacs 是一个专为各种程序员设计的流行的文本编辑器。因为它是在 Unix 上开发的,并在 Linux(macOS 中也有)上得到了广泛使用,所以人们有时没有意识到它也可用于微软 Windows 上。你也无需成为有经验的或专职的程序员即可使用 Emacs。只需单击几下就可以下载并安装 Emacs,本文向你展示了如何进行。
|
||||
|
||||
你可以手动安装 Windows,也可以使用包管理器安装,例如 [Chocolatey][2]。
|
||||
|
||||
### 7-zip
|
||||
|
||||
如果还没在 Windows 中安装 7-zip,那么就先安装它。[7-zip][3] 是一个开源的存档程序,能够创建和解压 ZIP、7z、TAR、XZ、BZIP2 和 GZIP(以及更多)文件。对于 Windows 用户来说,这是一个宝贵的工具。
|
||||
如果还没在 Windows 中安装 7-zip,那么就先安装它。[7-zip][3] 是一个开源的归档程序,能够创建和解压 ZIP、7z、TAR、XZ、BZIP2 和 GZIP(以及更多)文件。对于 Windows 用户来说,这是一个宝贵的工具。
|
||||
|
||||
安装 7-zip 后,在 Windows 资源管理器中浏览文件时,右键单击菜单中就有新的 7-zip 存档选项。
|
||||
安装 7-zip 后,在 Windows 资源管理器中浏览文件时,右键单击菜单中就有新的 7-zip 归档选项。
|
||||
|
||||
### Powershell 和 Chocolatey
|
||||
|
||||
要在 Windows 上使用 Chocolatey 安装 GNU Emacs :
|
||||
|
||||
|
||||
```
|
||||
`PS> choco install emacs-full`
|
||||
PS> choco install emacs-full
|
||||
```
|
||||
|
||||
安装后,在 Powershell 中启动 Emacs:
|
||||
|
||||
|
||||
```
|
||||
`PS> emacs`
|
||||
PS> emacs
|
||||
```
|
||||
|
||||
![Emacs running on Windows][4]
|
||||
@ -46,35 +46,35 @@ GNU Emacs 是一个专为各种程序员设计的流行的文本编辑器。因
|
||||
|
||||
![GNU Windows downloader][6]
|
||||
|
||||
它会打开连接到离你最近的服务器,并展示所有可用的 Emacs 版本。找到发行版本号最高的目录,然后单击进入。Windows 有许多不同的 Emacs 构建,但是最通用的版本只是被命名为 emacs-VERSION-ARCHITECTURE.zip。**VERSION** 取决于你要下载的版本,而 **ARCHITECTURE** 取决于你使用的是 32 位还是 64 位计算机。大多数现代计算机都是 64 位的,但是如果你有疑问,可以下载 32 位版本,它可在两者上运行。
|
||||
它会打开连接到离你最近的服务器,并展示所有可用的 Emacs 版本。找到发行版本号最高的目录,然后单击进入。Windows 有许多不同的 Emacs 构建,但是最通用的版本只是被命名为 `emacs-VERSION-ARCHITECTURE.zip`。`VERSION` 取决于你要下载的版本,而 `ARCHITECTURE` 取决于你使用的是 32 位还是 64 位计算机。大多数现代计算机都是 64 位的,但是如果你有疑问,可以下载 32 位版本,它可在两者上运行。
|
||||
|
||||
如果要下载 64 位计算机的 Emacs v26,你应该点击 emacs-26.2-x86_64.zip 的链接。有较小的下载包(例如 “no-deps” 等),但是你必须熟悉如何从源码构建 Emacs,知道它需要哪些库以及你的计算机上已经拥有哪些库。通常,获取较大版本的 Emacs 最容易,因为它包含了在计算机上运行所需的一切。
|
||||
如果要下载 64 位计算机的 Emacs v26,你应该点击 `emacs-26.2-x86_64.zip` 的链接。有较小的下载包(例如 “no-deps” 等),但是你必须熟悉如何从源码构建 Emacs,知道它需要哪些库以及你的计算机上已经拥有哪些库。通常,获取较大版本的 Emacs 最容易,因为它包含了在计算机上运行所需的一切。
|
||||
|
||||
### 解压 Emacs
|
||||
|
||||
接下来,解压下载的 ZIP 文件。要解压缩,请右键单击 Emacs ZIP 文件,然后从 7-zip 子菜单中选择 **Extract to Emacs-VERSION**。这是一个很大的压缩包,因此解压可能需要一段时间,但是完成后,你将拥有一个新目录,其中包含与 Emacs 一起分发的所有文件。例如,在此例中,下载了 emacs-26.2-x86_64.zip,因此解压后的目录为 emacs-26.2-x86_64。
|
||||
接下来,解压下载的 ZIP 文件。要解压缩,请右键单击 Emacs ZIP 文件,然后从 7-zip 子菜单中选择 “Extract to Emacs-VERSION”。这是一个很大的压缩包,因此解压可能需要一段时间,但是完成后,你将拥有一个新目录,其中包含与 Emacs 一起分发的所有文件。例如,在此例中,下载了 `emacs-26.2-x86_64.zip`,因此解压后的目录为 `emacs-26.2-x86_64`。
|
||||
|
||||
### 启动 Emacs
|
||||
|
||||
在 Emacs 目录中,找到 **bin** 目录。此文件夹存储随 Emacs 一起分发的所有二进制可执行文件(EXE 文件)。双击 emacs.exe 文件启动应用。
|
||||
在 Emacs 目录中,找到 `bin` 目录。此文件夹存储随 Emacs 一起分发的所有二进制可执行文件(EXE 文件)。双击 `emacs.exe` 文件启动应用。
|
||||
|
||||
![Emacs running on Windows][7]
|
||||
|
||||
你可以在桌面上创建 **emacs.exe** 的快捷方式,以便于访问。
|
||||
你可以在桌面上创建 `emacs.exe` 的快捷方式,以便于访问。
|
||||
|
||||
### 学习 Emacs
|
||||
|
||||
Emacs 并不像传闻那样难用。它具有自己的传统和惯例,但是当你其中输入文本时,你可以像在记事本或者网站的文本框中那样使用它。
|
||||
|
||||
重要的区别是在你_编辑_输入的文本时。
|
||||
重要的区别是在你*编辑*输入的文本时。
|
||||
|
||||
但是,学习的唯一方法是开始使用它,因此,使 Emacs 成为完成简单任务的首选文本编辑器。当你通常打开记事本、Word 或 Evernote 或其他工具来做快速笔记或临时记录时,请启动 Emacs。
|
||||
|
||||
Emacs 以基于终端的应用而闻名,但它显然有 GUI,因此请像使用其他程序一样经常使用它的 GUI。从菜单而不是使用键盘复制、剪切和粘贴(paste)(或用 Emacs 的术语 “yank”),然后从菜单或工具栏打开和保存文件。从头开始,并根据应用本身来学习它,而不是根据你以往对其他编辑器的经验就认为它应该是怎样。
|
||||
|
||||
### 下载[速查表][8]!
|
||||
- 下载[速查表][8]!
|
||||
|
||||
_感谢 Matthias Pfuetzner 和 Stephen Smoogen。_
|
||||
感谢 Matthias Pfuetzner 和 Stephen Smoogen。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -83,7 +83,7 @@ via: https://opensource.com/article/20/3/emacs-windows
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,8 +1,8 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11972-1.html)
|
||||
[#]: subject: (Drauger OS Linux Aims to Bring Console Gaming Experience on the Desktop)
|
||||
[#]: via: (https://itsfoss.com/drauger-os/)
|
||||
[#]: author: (John Paul https://itsfoss.com/author/john/)
|
||||
@ -10,7 +10,7 @@
|
||||
Drauger OS Linux 旨在为台式机带来主机游戏体验
|
||||
======
|
||||
|
||||
多年来(或数十年),人们抱怨不[使用Linux][1] 的原因之一是缺乏主流游戏。[Linux 上的游戏][2]在最近几年有了显著改进,特别是 [Steam Proton][3] 项目的引入使你可以[在 Linux 上玩很多 Windows 专用的游戏][4]。
|
||||
多年来(或数十年),人们抱怨不[使用Linux][1] 的原因之一是它缺乏主流游戏。[Linux 上的游戏][2]在最近几年有了显著改进,特别是 [Steam Proton][3] 项目的引入使你可以[在 Linux 上玩很多 Windows 专用的游戏][4]。
|
||||
|
||||
这也鼓励了一些[以游戏为中心的 Linux发行版][5]。以 [Lakka][6] 为例,你可以[借助 Lakka Linux 将旧计算机变成复古的街机游戏机][7]。
|
||||
|
||||
@ -34,9 +34,9 @@ Drauger OS 开箱即用地安装了多个应用程序和工具,以改善游戏
|
||||
* Steam
|
||||
* [DXVK][15]
|
||||
|
||||
它还具有一组与游戏无关的有趣工具。[Drauger Installer][16] 是 .deb 安装程序,是 Gdebi 的替代品。[多软件库应用安装器][17](mrai)是“用于基于 Debian 的 Linux 操作系统的类似于 AUR-helper 的脚本”。Mrai 旨在与 apt、snap、flatpaks 配合使用,并且可以从 GitHub 安装应用程序。
|
||||
它还具有一组与游戏无关的有趣工具。[Drauger 安装器][16]是 .deb 安装程序,是 Gdebi 的替代品。[多软件库应用安装器][17](mrai)是“用于基于 Debian 的 Linux 操作系统的类似于 AUR-helper 的脚本”。Mrai 旨在与 apt、snap、flatpaks 配合使用,并且可以从 GitHub 安装应用程序。
|
||||
|
||||
有趣的是,Drauger OS 的名称是一个错误。首席开发者 [Thomas Castleman][18](即 batcastle)曾打算为其发行版命名为 Draugr,但是却打错了名字。在 Drauger OS 播客的[第 23 集][19]中,Castleman 说保持这个拼写错误的名称,因为要对其进行更正需要大量工作。根据 [Wikipedia][20] 的描述,Draugr 是“来自北欧神话中的不死生物”。
|
||||
有趣的是,Drauger OS 的名称是一个错误。开发负责人 [Thomas Castleman][18](即 batcastle)曾打算为其发行版命名为 Draugr,但是却打错了名字。在 Drauger OS 播客的[第 23 集][19]中,Castleman 说会保留这个拼写错误的名称,因为要对其进行更正需要大量工作。根据 [Wikipedia][20] 的描述,Draugr 是“来自北欧神话中的不死生物”。
|
||||
|
||||
是的,你没看错。Drauger OS 是仅有的几个具有自己的[播客][21]的发行版之一。当被问到这个问题时,Castleman 告诉我:“无论他们的情况如何,我都希望确保我们的社区拥有最大的透明度。”多数情况下,播客是 Drauger OS 博客的音频版本,但有时他们会在没有时间撰写博客文章时使用它来发布公告。
|
||||
|
||||
@ -44,7 +44,7 @@ Drauger OS 开箱即用地安装了多个应用程序和工具,以改善游戏
|
||||
|
||||
![Drauger OS][22]
|
||||
|
||||
Druager OS 背后的开发人员正在开发其下一个主要版本:7.5.1。此版本将基于 Ubuntu 19.10。将有三个主要变化。首先,将使用“我们内部构建的内核” [替换][23] Liquorix 内核。该内核将基于 Linux Kernel GitHub 存储库,“因此,它变得越来越原汁原味”。
|
||||
Druager OS 背后的开发人员正在开发其下一个主要版本:7.5.1。此版本将基于 Ubuntu 19.10。将有三个主要变化。首先,将使用“我们内部构建的内核” [替换][23] Liquorix 内核。该内核将基于 Linux 内核 GitHub 存储库,“因此,它会变得越来越原汁原味”。
|
||||
|
||||
新版本的第二个主要变化将是为其桌面提供新布局。根据用户的反馈,他们决定将其更改为看起来更类似于 GNOME 的样子。
|
||||
|
||||
@ -64,7 +64,7 @@ Drauger OS [系统要求][25]非常适中。请记住,Drauger OS 仅在 64 位
|
||||
* 图形处理器:集成
|
||||
* 屏幕分辨率:60Hz 时为 1024×768
|
||||
* 外部端口:1 个用于显示的端口(HDMI/DisplayPort/VGA/DVI),2 个用于安装 USB 驱动器和键盘的 USB 端口(鼠标可选,但建议使用)
|
||||
|
||||
|
||||
#### 推荐系统要求
|
||||
|
||||
* CPU:四核、2.2Ghz、64 位处理器
|
||||
@ -93,15 +93,15 @@ via: https://itsfoss.com/drauger-os/
|
||||
作者:[John Paul][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/john/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/why-use-linux/
|
||||
[2]: https://itsfoss.com/linux-gaming-guide/
|
||||
[3]: https://itsfoss.com/steam-play-proton/
|
||||
[2]: https://linux.cn/article-7316-1.html
|
||||
[3]: https://linux.cn/article-10054-1.html
|
||||
[4]: https://itsfoss.com/steam-play/
|
||||
[5]: https://itsfoss.com/linux-gaming-distributions/
|
||||
[6]: http://www.lakka.tv/
|
@ -0,0 +1,111 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How I learned about burnout the hard way)
|
||||
[#]: via: (https://opensource.com/article/20/3/burnout)
|
||||
[#]: author: (Jason Hibbets https://opensource.com/users/jhibbets)
|
||||
|
||||
How I learned about burnout the hard way
|
||||
======
|
||||
Burnout can happen to anyone. Here are the 3 things I wish I knew before
|
||||
I burned out.
|
||||
![Light bulb][1]
|
||||
|
||||
In early 2017, I was mentally in a bad spot. It was the perfect storm of stress, the kind that no one asks for, but you deal with the hand you're dealt. Work was piling up to a point where I couldn't process all the things that were expected of me. I was training for spring half-marathons, which should have been stress relief, but I was putting too much pressure on myself to perform at a high level. And then on top of the everyday family obligations, a surgery in our household turned us into a one-car family and seriously added to the mounting pressure on me to provide and take care of the family.
|
||||
|
||||
Then I broke.
|
||||
|
||||
It wasn't one thing. It was the culmination of things. And it hit me from the blind side, unexpected. I never thought I would be a victim of burnout. I was aware of it and thoughtful about the community I was managing. But "not me," I thought to myself, "I've got this under control." I remember thinking that something was wrong; something was off. But I couldn't quite put my finger on the source.
|
||||
|
||||
I distinctly remember the day where I cried at work, crumbling under the pressure that I was putting on myself. I consider myself a high performer in the office environment. I push myself to exceed the goals that my team co-creates because I want that success. I want the feeling that comes with it. But this experience was different. This wasn't a healthy win for my team or me. I felt like I let everyone down, including myself.
|
||||
|
||||
I was attending South by Southwest in Austin, Texas, where I was [presenting my first Ignite Talk][2] on applying open source principles to government—a talk that was well received by the audience. I remember practicing, and practicing, and practicing more the day before and the morning of my talk. I got that high that comes after delivering a great talk. I had a book signing at the City of Raleigh's Economic Development booth during the event, which was another emotional boost. Life was good. Upon reflection, that's when I started noticing signs of my burnout.
|
||||
|
||||
I didn't have much of an appetite. I was tired all the time. I was sleeping in, and not because of jet lag. I was exercising but wasn't getting the endorphins I was used to. And I wasn't motivated to do the work that I normally love to do. I was very blah and meh about getting work done or hanging out with people I love. These are all signs of depression and burnout.
|
||||
|
||||
After the trip, I scheduled my annual physical and talked to my doctor about my situation, who recommended I see a psychologist. I sat on the couch and talked things out. I was diagnosed with severe anxiety, which was enough for me to know that I didn't want to know what true depression felt like.
|
||||
|
||||
I learned my lesson the hard way. I'd like to share my experience so that you can recognize the signs and avoid going down this path. And before we move on, I must say that it's perfectly fine to ask for help. Ask a trusted co-worker or friend for help or guidance. We're human, and we need to help each other through the ups and the downs.
|
||||
|
||||
### Three things to know about burnout
|
||||
|
||||
Work burnout is a form of depression where you are not motivated to do the things that are expected of you at your job. It's not the occasional slacking off or spring fever because the weather is nice. It's a buildup of emotional stress where you don't want to do what is asked of you at work. There are numerous factors that can lead to burnout.
|
||||
|
||||
#### Know the signs of burnout
|
||||
|
||||
Lesson number one about burnout is to know the signs. I mentioned some of the things I was experiencing, but there are many others. I remember one thing that was extremely abnormal for me (because I'm so social) is that I started to separate myself from my usual team activities and people.
|
||||
|
||||
* Hey Jason, want to grab lunch with us? Nope, I'm too busy.
|
||||
* Hey Jason, Matt's in town, want to join us for happy hour? No. I've got work to do.
|
||||
|
||||
|
||||
|
||||
This is totally unlike me. I would normally have said yes to both those opportunities. According to the [Mayo Clinic][3], here are a few things to ask yourself if you think you are experiencing burnout:
|
||||
|
||||
* Do you drag yourself to work?
|
||||
* Do you have trouble getting started with work?
|
||||
* Are you cynical or critical at work?
|
||||
* Have you become irritable or impatient with co-workers or customers?
|
||||
* Do you lack the energy to be productive?
|
||||
* Do you find it hard to concentrate?
|
||||
* Do you lack satisfaction from your achievements?
|
||||
* Do you feel disillusioned about your work?
|
||||
* Are you using food, drugs, or alcohol to feel better or to simply not feel?
|
||||
* Have your sleep habits changed?
|
||||
* Are you troubled by unexplained headaches, stomach or bowel problems, or other physical complaints?
|
||||
|
||||
|
||||
|
||||
You can check your own burnout risk at [BurnoutIndex.org][4], an anonymous online questionnaire created in response to the [high level of burnout][5] in the tech industry.
|
||||
|
||||
#### Prevent burnout
|
||||
|
||||
The second lesson is to identify ways [to prevent burnout][6]. First, take time away from your job and plan time to unplug and unwind. This means planning vacations, staycations, or other time away from work. It's sometimes hard to unplug like this with the pressures and obligations we put on ourselves.
|
||||
|
||||
There are three different levels of paid time off (PTO):
|
||||
|
||||
1. **Best way to unplug:** I'm totally cut-off, not logging in, not checking email.
|
||||
2. **Decent way to unplug:** I'm kind of checking in, but not as responsive as normal.
|
||||
3. **Meh way to unplug:** I'm available if you need me, I'll monitor email, but I'm away from normal office life.
|
||||
|
||||
|
||||
|
||||
Your situation will dictate which of these levels of time off will work for you. In my experience, you need at least two total check-outs a year. I typically have a blend of all three throughout the year, but since 2017, I have taken at least three week-long vacations each year to completely escape. It's working so far!
|
||||
|
||||
#### Manage stress
|
||||
|
||||
The third and final lesson is to manage stress effectively. My first go-to for stress management is exercise. I'm addicted to it. I work out pretty much every single day. And I like to mix it up: Cardio, weight lifting, swimming, running, cycling, surfing, and high-intensity interval training (HIIT) are staples in my exercise routine. I used to focus solely on running four to six half marathons a year, but I recently switched to triathlons. The multidisciplinary aspect of the activity has brought more joy and different challenges to my life.
|
||||
|
||||
Another way to reduce stress is to manage your time better. Time is our most precious resource. You've got to choose how you want to spend your time. Family, work, self, social? It's up to you. Find ways to work more efficiently, more effectively, and make sure that you put yourself first. It may sound selfish, but as I've learned from the airplane preflight safety videos, "you need to put your mask on first before helping others."
|
||||
|
||||
### Conclusion
|
||||
|
||||
Burnout can lead to fatigue, excessive stress, sadness, anger, irritability, insomnia, alcohol or substance misuse, heart disease, and other medical conditions—all things that are not good for humans or for your team at work. I hope you can use these tips to put yourself first, reduce stress, and prevent burnout.
|
||||
|
||||
* * *
|
||||
|
||||
_Jason Hibbets will present "[10 things I wish I knew before experiencing burnout][7]" at [SCaLE 18x][8], March 5–8, 2020, in Pasadena, Calif. This article is a preview for the talk and a way to share a bit of his experience._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/3/burnout
|
||||
|
||||
作者:[Jason Hibbets][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jhibbets
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/bulb-light-energy-power-idea.png?itok=zTEEmTZB (Light bulb)
|
||||
[2]: https://schedule.sxsw.com/2017/events/PP96070
|
||||
[3]: https://www.mayoclinic.org/healthy-lifestyle/adult-health/in-depth/burnout/art-20046642
|
||||
[4]: https://burnoutindex.org/
|
||||
[5]: https://opensource.com/article/19/11/burnout-open-source-communities
|
||||
[6]: https://www.redhat.com/sysadmin/tips-avoiding-burnout
|
||||
[7]: https://www.socallinuxexpo.org/scale/18x/presentations/10-things-i-wish-i-knew-experiencing-burnout
|
||||
[8]: https://www.socallinuxexpo.org/scale/18x/
|
@ -0,0 +1,115 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (The De-Googled Android Fork is Making Good Progress)
|
||||
[#]: via: (https://itsfoss.com/gael-duval-interview/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
|
||||
The De-Googled Android Fork is Making Good Progress
|
||||
======
|
||||
|
||||
A couple years ago, we covered the [Eelo project][1]. If you remember, the Eelo project was started by [Gael Duval][2] who once created Mandrake Linux. The goal of the Eelo project was to remove all Google services from Android to give you an [alternate mobile operating system][3] that doesn’t track you and invade your privacy.
|
||||
|
||||
A lot has happened to Eelo since then. It’s not called Eelo anymore, now it’s called /e/. So, what’s happening with this project? We talked to Gael Duval himself. Here’s what he shared with us.
|
||||
|
||||
![][4]
|
||||
|
||||
_**Why did you create this Eelo or /e/ project in the first place?**_
|
||||
|
||||
**Gael:** In 2017, I realized that using Android and iPhone, Google and many mobile apps was not compatible with my personal privacy.
|
||||
|
||||
A later study by a US University confirmed this: using an iPhone or and Android phone sends between 6 to 12 MB of personal data to Google servers, daily! And this doesn’t count mobile apps.
|
||||
|
||||
So I looked for reasonable alternatives to iPhone and Android phones but didn’t find any. Either I found options for hobbyists, like Ubuntu Touch, that were not compatible with existing apps and not fully unGoogled either. Or there were alternative ROMs with all the Google fat inside, and no associated basic online services that could be used without tweaking the system.
|
||||
|
||||
Therefore, an idea came to mind: why not fork Android, remove all the Google features, even low level, such as connectivity check, DNS…, replace default apps with more virtuous apps, add basic online services, and integrate all this into a consistent form that could be used by Mum and Dad and any people without tech or expert knowledge?
|
||||
|
||||
_**How is it any different from other custom Android ROMs?**_
|
||||
|
||||
**Gael:** It doesn’t send a bit of data to Google, and is and will be more and more privacy-focused.
|
||||
|
||||
Low-level: we remove any Android feature that sends data to Google servers. Even the connectivity check when you start the smartphone! To my knowledge, there is not any other Android ROM that does this at the moment. We change default DNS settings and offer users an option to set the DNS of their choice. We change NTP (automatic time configuration) settings to the default NTP servers because there is no reason to use Google NTP servers actually. Then we remove Google services, and we replace with a software layout called microG that can still receive push notifications and have geolocation data for apps (using Mozilla geolocation service).
|
||||
|
||||
Then we change the default apps by non-Google apps, including the maps applications, mail etc., most are open source applications and I can say that there is 99% probability that all will be open source before the end of this year.
|
||||
|
||||
Then we add our own Android application installer, with close to 80 000 available applications at the moment.
|
||||
|
||||
We provide a different web browser, which is a fork of Chromium, were all features that data to Google are removed, and were the default search engine is not Google…
|
||||
|
||||
And we operate online services:
|
||||
|
||||
* search, using a meta-search system that we have improve for a better user experience
|
||||
* online drive with encrypted data, calendar etc. using a modified version of NextCloud
|
||||
* mail…
|
||||
|
||||
|
||||
|
||||
And for we provide a unique identifier that can be used to access all those services, either on the web or from the /e/ OS system, by login once. Then you can sync all your data, calendar, email etc. between your smartphone and your personal /e/ cloud (it can also be self-hosted).
|
||||
The purpose of the project is to provide a normal, ready to use, and attractive “digital life” to users, without sending all your personal data to Google.
|
||||
|
||||
_**If it is completely ‘ungoogled’, how do users install new apps? Do you have your own app store? If yes, how can we trust that these apps don’t spy on user data?**_
|
||||
|
||||
**Gael:** Yes – we have our own application installer, with about 80 000 applications. And we analyse each application to unveil the number of trackers, and we display this information to our users, for each application. We are also adding Progressive Web Apps soon to this application installer.
|
||||
|
||||
/e/ OS is about freedom of choice. We want the core system to be better, and then offer as many possible options to users, by informing them as much as possible. In short: they can still any application they need. Next step will be to offer a feature to actually block trackers used in applications.
|
||||
|
||||
_**What is the target user base for /e/? Can an average Joey use it without much trouble?**_
|
||||
|
||||
![][5]
|
||||
|
||||
**Gael:** We started with tech-savvy users, and we’re expanding the user base to people with less knowledge. At the moment, our typical user base is a mix of tech-savvy users, who can flash a smartphone with /e/ OS and people who are very concerned with Google and their data privacy but have very limited technical knowledge. For those people we have some smartphones pre-installed with /e/ OS for sale, on high-grade refurbished hardware.
|
||||
|
||||
We are also announcing this week an “/e/ easy installer” that will make the flashing process much more easier, by pluging the smartphone to a PC and launching a dedicated application that will make most of the job.
|
||||
|
||||
Then, the next step will be to expand our target users to a more global market, once we find the good partners. But clearly, there is a demand for something different than the Apple-Google worldwide market duopoly on the mobile.
|
||||
|
||||
_**Initially the project was named eelo and it is called /e/ or [e foundation][6]. Personally, I find the name /e/ weird and it is not easily recognizable. Why did you change the project name?**_
|
||||
|
||||
**Gael:** We have been “attacked” by a company called “eelloo”. They considered that “eelo” would interfere with their business. They are in the HR business solutions, but registered their trademark in all the classes related to mobile OS, smartphones etc. This is silly and a shame, but we had no money to defend us strongly at the time.
|
||||
|
||||
However the/e/ name will be abandonned for something else quite soon.
|
||||
|
||||
_**It’s been a couple of years since the initial launch. How do you see the adoption of /e/?**_
|
||||
|
||||
**Gael:** We launched the first beta 18 months ago, and we have started to sell smartphones with /e/ a little more than 6 months ago. The adoption is growing a lot at the moment, we have to add terabytes of online storage regularly!
|
||||
|
||||
Also with the /e/ installer arriving, and some official partnerships with some hardware mobile manufacturers in the pipe, this is going to accelerate a lot this year.
|
||||
|
||||
However, this is not surprising, privacy concerns are rising both for individuals and corporations, and I think the rejection of Google is also trending.
|
||||
|
||||
_**What are your future plans to grow /e/?**_
|
||||
|
||||
**Gael:** The growth is very natural. There is a strong community of users who realize how unique our approach is. These guys are contributing, supporting us and talking a lot about the project.
|
||||
|
||||
With the easy installer coming along and strategic partnerships with hardware makers, this is going to accelerate a lot.
|
||||
|
||||
Also, and this is more personal, I think that there is a natural connection between /e/ OS, and the Linux world. OK, /e/ OS is based on Android, but it’s still a Linux kernel and it’s the same spirit, it’s Open Source… So I’d really like to have more natural integration between my /e/ smartphone and my Linux desktop. There should be some nice features added in this spirit in the next versions of /e/ OS.
|
||||
|
||||
_**What can /e/ users and our readers do to help e foundation?**_
|
||||
|
||||
**Gael:** Join us, talk about what we are doing, send your feedback, organize some meetups… Help improve the /e/ Wikipedia page which is very poor and doesn’t represent at all what we are actually doing.
|
||||
|
||||
We also have a [permanent crowdfunding campaign where users can support the project financially][7], pay for the servers etc. And, in addition to giving back in term of open source product, we send cool stuff in return :)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/gael-duval-interview/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/abhishek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/eelo-mobile-os/
|
||||
[2]: https://en.wikipedia.org/wiki/Ga%C3%ABl_Duval
|
||||
[3]: https://itsfoss.com/open-source-alternatives-android/
|
||||
[4]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/03/e-os-interview.jpg?ssl=1
|
||||
[5]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/03/e-foundation-smartphones.jpg?resize=800%2C590&ssl=1
|
||||
[6]: https://e.foundation/
|
||||
[7]: https://e.foundation/donate/
|
@ -1,229 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (mengxinayan)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to structure a multi-file C program: Part 2)
|
||||
[#]: via: (https://opensource.com/article/19/7/structure-multi-file-c-part-2)
|
||||
[#]: author: (Erik O'Shaughnessy https://opensource.com/users/jnyjny)
|
||||
|
||||
How to structure a multi-file C program: Part 2
|
||||
======
|
||||
Dive deeper into the structure of a C program composed of multiple files
|
||||
in the second part of this article.
|
||||
![4 manilla folders, yellow, green, purple, blue][1]
|
||||
|
||||
In [Part 1][2], I laid out the structure for a multi-file C program called [MeowMeow][3] that implements a toy [codec][4]. I also talked about the Unix philosophy of program design, laying out a number of empty files to start with a good structure from the very beginning. Lastly, I touched on what a Makefile is and what it can do for you. This article picks up where the other one left off and now I'll get to the actual implementation of our silly (but instructional) MeowMeow codec.
|
||||
|
||||
The structure of the **main.c** file for **meow**/**unmeow** should be familiar to anyone who's read my article "[How to write a good C main function][5]." It has the following general outline:
|
||||
|
||||
|
||||
```
|
||||
/* main.c - MeowMeow, a stream encoder/decoder */
|
||||
|
||||
/* 00 system includes */
|
||||
/* 01 project includes */
|
||||
/* 02 externs */
|
||||
/* 03 defines */
|
||||
/* 04 typedefs */
|
||||
/* 05 globals (but don't)*/
|
||||
/* 06 ancillary function prototypes if any */
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* 07 variable declarations */
|
||||
/* 08 check argv[0] to see how the program was invoked */
|
||||
/* 09 process the command line options from the user */
|
||||
/* 10 do the needful */
|
||||
}
|
||||
|
||||
/* 11 ancillary functions if any */
|
||||
```
|
||||
|
||||
### Including project header files
|
||||
|
||||
The second section, **/* 01 project includes /***, reads like this from the source:
|
||||
|
||||
|
||||
```
|
||||
/* main.c - MeowMeow, a stream encoder/decoder */
|
||||
...
|
||||
/* 01 project includes */
|
||||
#include "main.h"
|
||||
#include "mmecode.h"
|
||||
#include "mmdecode.h"
|
||||
```
|
||||
|
||||
The **#include** directive is a C preprocessor command that causes the contents of the named file to be "included" at this point in the file. If the programmer uses double-quotes around the name of the header file, the compiler will look for that file in the current directory. If the file is enclosed in <>, it will look for the file in a set of predefined directories.
|
||||
|
||||
The file [**main.h**][6] contains the definitions and typedefs used in [**main.c**][7]. I like to collect these things here in case I want to use those definitions elsewhere in my program.
|
||||
|
||||
The files [**mmencode.h**][8] and [**mmdecode.h**][9] are nearly identical, so I'll break down **mmencode.h**.
|
||||
|
||||
|
||||
```
|
||||
/* mmencode.h - MeowMeow, a stream encoder/decoder */
|
||||
|
||||
#ifndef _MMENCODE_H
|
||||
#define _MMENCODE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int mm_encode(FILE *src, FILE *dst);
|
||||
|
||||
#endif /* _MMENCODE_H */
|
||||
```
|
||||
|
||||
The **#ifdef, #define, #endif** construction is collectively known as a "guard." This keeps the C compiler from including this file more than once per file. The compiler will complain if it finds multiple definitions/prototypes/declarations, so the guard is a _must-have_ for header files.
|
||||
|
||||
Inside the guard, there are only two things: an **#include** directive and a function prototype declaration. I include **stdio.h** here to bring in the definition of **FILE** that is used in the function prototype. The function prototype can be included by other C files to establish that function in the file's namespace. You can think of each file as a separate _namespace_, which means variables and functions in one file are not usable by functions or variables in another file.
|
||||
|
||||
Writing header files is complex, and it is tough to manage in larger projects. Use guards.
|
||||
|
||||
### MeowMeow encoding, finally
|
||||
|
||||
The meat and potatoes of this program—encoding and decoding bytes into/out of **MeowMeow** strings—is actually the easy part of this project. All of our activities until now have been putting the scaffolding in place to support calling this function: parsing the command line, determining which operation to use, and opening the files that we'll operate on. Here is the encoding loop:
|
||||
|
||||
|
||||
```
|
||||
/* mmencode.c - MeowMeow, a stream encoder/decoder */
|
||||
...
|
||||
while (![feof][10](src)) {
|
||||
|
||||
if (![fgets][11](buf, sizeof(buf), src))
|
||||
break;
|
||||
|
||||
for(i=0; i<[strlen][12](buf); i++) {
|
||||
lo = (buf[i] & 0x000f);
|
||||
hi = (buf[i] & 0x00f0) >> 4;
|
||||
[fputs][13](tbl[hi], dst);
|
||||
[fputs][13](tbl[lo], dst);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In plain English, this loop reads in a chunk of the file while there are chunks left to read (**feof(3)** and **fgets(3)**). Then it splits each byte in the chunk into **hi** and **lo** nibbles. Remember, a nibble is half of a byte, or 4 bits. The real magic here is realizing that 4 bits can encode 16 values. I use **hi** and **lo** as indices into a 16-string lookup table, **tbl**, that contains the **MeowMeow** strings that encode each nibble. Those strings are written to the destination **FILE** stream using **fputs(3)**, then we move on to the next byte in the buffer.
|
||||
|
||||
The table is initialized with a macro defined in [**table.h**][14] for no particular reason except to demonstrate including another project local header file, and I like initialization macros. We will go further into why a future article.
|
||||
|
||||
### MeowMeow decoding
|
||||
|
||||
Alright, I'll admit it took me a couple of runs at this before I got it working. The decode loop is similar: read a buffer full of **MeowMeow** strings and reverse the encoding from strings to bytes.
|
||||
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow, a stream decoder/decoder */
|
||||
...
|
||||
int mm_decode(FILE *src, FILE *dst)
|
||||
{
|
||||
if (!src || !dst) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return stupid_decode(src, dst);
|
||||
}
|
||||
```
|
||||
|
||||
Not what you were expecting?
|
||||
|
||||
Here, I'm exposing the function **stupid_decode()** via the externally visible **mm_decode()** function. When I say "externally," I mean outside this file. Since **stupid_decode()** isn't in the header file, it isn't available to be called in other files.
|
||||
|
||||
Sometimes we do this when we want to publish a solid public interface, but we aren't quite done noodling around with functions to solve a problem. In my case, I've written an I/O-intensive function that reads 8 bytes at a time from the source stream to decode 1 byte to write to the destination stream. A better implementation would work on a buffer bigger than 8 bytes at a time. A _much_ better implementation would also buffer the output bytes to reduce the number of single-byte writes to the destination stream.
|
||||
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow, a stream decoder/decoder */
|
||||
...
|
||||
int stupid_decode(FILE *src, FILE *dst)
|
||||
{
|
||||
char buf[9];
|
||||
decoded_byte_t byte;
|
||||
int i;
|
||||
|
||||
while (![feof][10](src)) {
|
||||
if (![fgets][11](buf, sizeof(buf), src))
|
||||
break;
|
||||
byte.field.f0 = [isupper][15](buf[0]);
|
||||
byte.field.f1 = [isupper][15](buf[1]);
|
||||
byte.field.f2 = [isupper][15](buf[2]);
|
||||
byte.field.f3 = [isupper][15](buf[3]);
|
||||
byte.field.f4 = [isupper][15](buf[4]);
|
||||
byte.field.f5 = [isupper][15](buf[5]);
|
||||
byte.field.f6 = [isupper][15](buf[6]);
|
||||
byte.field.f7 = [isupper][15](buf[7]);
|
||||
|
||||
[fputc][16](byte.value, dst);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Instead of using the bit-shifting technique I used in the encoder, I elected to create a custom data structure called **decoded_byte_t**.
|
||||
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow, a stream decoder/decoder */
|
||||
...
|
||||
|
||||
typedef struct {
|
||||
unsigned char f7:1;
|
||||
unsigned char f6:1;
|
||||
unsigned char f5:1;
|
||||
unsigned char f4:1;
|
||||
unsigned char f3:1;
|
||||
unsigned char f2:1;
|
||||
unsigned char f1:1;
|
||||
unsigned char f0:1;
|
||||
} fields_t;
|
||||
|
||||
typedef union {
|
||||
fields_t field;
|
||||
unsigned char value;
|
||||
} decoded_byte_t;
|
||||
```
|
||||
|
||||
It's a little complex when viewed all at once, but hang tight. The **decoded_byte_t** is defined as a **union** of a **fields_t** and an **unsigned char**. The named members of a union can be thought of as aliases for the same region of memory. In this case, **value** and **field** refer to the same 8-bit region of memory. Setting **field.f0** to 1 would also set the least significant bit in **value**.
|
||||
|
||||
While **unsigned char** shouldn't be a mystery, the **typedef** for **fields_t** might look a little unfamiliar. Modern C compilers allow programmers to specify "bit fields" in a **struct**. The field type needs to be an unsigned integral type, and the member identifier is followed by a colon and an integer that specifies the length of the bit field.
|
||||
|
||||
This data structure makes it simple to access each bit in the byte by field name and then access the assembled value via the **value** field of the union. We depend on the compiler to generate the correct bit-shifting instructions to access the fields, which can save you a lot of heartburn when you are debugging.
|
||||
|
||||
Lastly, **stupid_decode()** is _stupid_ because it only reads 8 bytes at a time from the source **FILE** stream. Usually, we try to minimize the number of reads and writes to improve performance and reduce our cost of system calls. Remember that reading or writing a bigger chunk less often is much better than reading/writing a lot of smaller chunks more frequently.
|
||||
|
||||
### The wrap-up
|
||||
|
||||
Writing a multi-file program in C requires a little more planning on behalf of the programmer than just a single **main.c**. But just a little effort up front can save a lot of time and headache when you refactor as you add functionality.
|
||||
|
||||
To recap, I like to have a lot of files with a few short functions in them. I like to expose a small subset of the functions in those files via header files. I like to keep my constants in header files, both numeric and string constants. I _love_ Makefiles and use them instead of Bash scripts to automate all sorts of things. I like my **main()** function to handle command-line argument parsing and act as a scaffold for the primary functionality of the program.
|
||||
|
||||
I know I've only touched the surface of what's going on in this simple program, and I'm excited to learn what things were helpful to you and which topics need better explanations. Share your thoughts in the comments to let me know.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/7/structure-multi-file-c-part-2
|
||||
|
||||
作者:[Erik O'Shaughnessy][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[萌新阿岩](https://github.com/mengxinayan)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jnyjny
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/file_system.jpg?itok=pzCrX1Kc (4 manilla folders, yellow, green, purple, blue)
|
||||
[2]: https://opensource.com/article/19/7/how-structure-multi-file-c-program-part-1
|
||||
[3]: https://github.com/jnyjny/MeowMeow.git
|
||||
[4]: https://en.wikipedia.org/wiki/Codec
|
||||
[5]: https://opensource.com/article/19/5/how-write-good-c-main-function
|
||||
[6]: https://github.com/JnyJny/meowmeow/blob/master/main.h
|
||||
[7]: https://github.com/JnyJny/meowmeow/blob/master/main.c
|
||||
[8]: https://github.com/JnyJny/meowmeow/blob/master/mmencode.h
|
||||
[9]: https://github.com/JnyJny/meowmeow/blob/master/mmdecode.h
|
||||
[10]: http://www.opengroup.org/onlinepubs/009695399/functions/feof.html
|
||||
[11]: http://www.opengroup.org/onlinepubs/009695399/functions/fgets.html
|
||||
[12]: http://www.opengroup.org/onlinepubs/009695399/functions/strlen.html
|
||||
[13]: http://www.opengroup.org/onlinepubs/009695399/functions/fputs.html
|
||||
[14]: https://github.com/JnyJny/meowmeow/blob/master/table.h
|
||||
[15]: http://www.opengroup.org/onlinepubs/009695399/functions/isupper.html
|
||||
[16]: http://www.opengroup.org/onlinepubs/009695399/functions/fputc.html
|
@ -1,238 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (caiichenr)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Building a non-breaking breakpoint for Python debugging)
|
||||
[#]: via: (https://opensource.com/article/19/8/debug-python)
|
||||
[#]: author: (Liran Haimovitch https://opensource.com/users/liranhaimovitch)
|
||||
|
||||
Building a non-breaking breakpoint for Python debugging
|
||||
======
|
||||
Have you ever wondered how to speed up a debugger? Here are some lessons
|
||||
learned while building one for Python.
|
||||
![Real python in the graphic jungle][1]
|
||||
|
||||
This is the story of how our team at [Rookout][2] built non-breaking breakpoints for Python and some of the lessons we learned along the way. I'll be presenting all about the nuts and bolts of debugging in Python at [PyBay 2019][3] in San Francisco this month. Let's dig in.
|
||||
|
||||
### The heart of Python debugging: sys.set_trace
|
||||
|
||||
There are many Python debuggers out there. Some of the more popular include:
|
||||
|
||||
* **pdb**, part of the Python standard library
|
||||
* **PyDev**, the debugger behind the Eclipse and PyCharm IDEs
|
||||
* **ipdb**, the IPython debugger
|
||||
|
||||
|
||||
|
||||
Despite the range of choices, almost every Python debugger is based on just one function: **sys.set_trace**. And let me tell you, **[sys.settrace][4]** might just be the most complex function in the Python standard library.
|
||||
|
||||
![set_trace Python 2 docs page][5]
|
||||
|
||||
In simpler terms, **settrace** registers a trace function for the interpreter, which may be called in any of the following cases:
|
||||
|
||||
* Function call
|
||||
* Line execution
|
||||
* Function return
|
||||
* Exception raised
|
||||
|
||||
|
||||
|
||||
A simple trace function might look like this:
|
||||
|
||||
|
||||
```
|
||||
def simple_tracer(frame, event, arg):
|
||||
co = frame.f_code
|
||||
func_name = co.co_name
|
||||
line_no = frame.f_lineno
|
||||
print("{e} {f} {l}".format(
|
||||
e=event, f=func_name, l=line_no))
|
||||
return simple_tracer
|
||||
```
|
||||
|
||||
When looking at this function, the first things that come to mind are its arguments and return values. The trace function arguments are:
|
||||
|
||||
* **frame** object, which is the full state of the interpreter at the point of the function's execution
|
||||
* **event** string, which can be **call**, **line**, **return**, or **exception**
|
||||
* **arg** object, which is optional and depends on the event type
|
||||
|
||||
|
||||
|
||||
The trace function returns itself because the interpreter keeps track of two kinds of trace functions:
|
||||
|
||||
* **Global trace function (per thread):** This trace function is set for the current thread by **sys.settrace** and is invoked whenever a new **frame** is created by the interpreter (essentially on every function call). While there's no documented way to set the trace function for a different thread, you can call **threading.settrace** to set the trace function for all newly created **threading** module threads.
|
||||
* **Local trace function (per frame):** This trace function is set by the interpreter to the value returned by the global trace function upon frame creation. There's no documented way to set the local trace function once the frame has been created.
|
||||
|
||||
|
||||
|
||||
This mechanism is designed to allow the debugger to have more granular control over which frames are traced to reduce performance impact.
|
||||
|
||||
### Building our debugger in three easy steps (or so we thought)
|
||||
|
||||
With all that background, writing your own debugger using a custom trace function looks like a daunting task. Luckily, **pdb**, the standard Python debugger, is built on top of **Bdb**, a base class for building debuggers.
|
||||
|
||||
A naive breakpoints debugger based on **Bdb** might look like this:
|
||||
|
||||
|
||||
```
|
||||
import bdb
|
||||
import inspect
|
||||
|
||||
class Debugger(bdb.Bdb):
|
||||
def __init__(self):
|
||||
Bdb.__init__(self)
|
||||
self.breakpoints = dict()
|
||||
self.set_trace()
|
||||
|
||||
def set_breakpoint(self, filename, lineno, method):
|
||||
self.set_break(filename, lineno)
|
||||
try :
|
||||
self.breakpoints[(filename, lineno)].add(method)
|
||||
except KeyError:
|
||||
self.breakpoints[(filename, lineno)] = [method]
|
||||
|
||||
def user_line(self, frame):
|
||||
if not self.break_here(frame):
|
||||
return
|
||||
|
||||
# Get filename and lineno from frame
|
||||
(filename, lineno, _, _, _) = inspect.getframeinfo(frame)
|
||||
|
||||
methods = self.breakpoints[(filename, lineno)]
|
||||
for method in methods:
|
||||
method(frame)
|
||||
```
|
||||
|
||||
All this does is:
|
||||
|
||||
1. Inherits from **Bdb** and write a simple constructor initializing the base class and tracing.
|
||||
2. Adds a **set_breakpoint** method that uses **Bdb** to set the breakpoint and keeps track of our breakpoints.
|
||||
3. Overrides the **user_line** method that is called by **Bdb** on certain user lines. The function makes sure it is being called for a breakpoint, gets the source location, and invokes the registered breakpoints
|
||||
|
||||
|
||||
|
||||
### How well did the simple Bdb debugger work?
|
||||
|
||||
Rookout is about bringing a debugger-like user experience to production-grade performance and use cases. So, how well did our naive breakpoint debugger perform?
|
||||
|
||||
To test it and measure the global performance overhead, we wrote two simple test methods and executed each of them 16 million times under multiple scenarios. Keep in mind that no breakpoint was executed in any of the cases.
|
||||
|
||||
|
||||
```
|
||||
def empty_method():
|
||||
pass
|
||||
|
||||
def simple_method():
|
||||
a = 1
|
||||
b = 2
|
||||
c = 3
|
||||
d = 4
|
||||
e = 5
|
||||
f = 6
|
||||
g = 7
|
||||
h = 8
|
||||
i = 9
|
||||
j = 10
|
||||
```
|
||||
|
||||
Using the debugger takes a shocking amount of time to complete. The bad results make it clear that our naive **Bdb** debugger is not yet production-ready.
|
||||
|
||||
![First Bdb debugger results][6]
|
||||
|
||||
### Optimizing the debugger
|
||||
|
||||
There are three main ways to reduce debugger overhead:
|
||||
|
||||
1. **Limit local tracing as much as possible:** Local tracing is very costly compared to global tracing due to the much larger number of events per line of code.
|
||||
2. **Optimize "call" events and return control to the interpreter faster:** The main work in **call** events is deciding whether or not to trace.
|
||||
3. **Optimize "line" events and return control to the interpreter faster:** The main work in **line** events is deciding whether or not we hit a breakpoint.
|
||||
|
||||
|
||||
|
||||
So we forked **Bdb**, reduced the feature set, simplified the code, optimized for hot code paths, and got impressive results. However, we were still not satisfied. So, we took another stab at it, migrated and optimized our code to **.pyx**, and compiled it using [Cython][7]. The final results (as you can see below) were still not good enough. So, we ended up diving into CPython's source code and realizing we could not make tracing fast enough for production use.
|
||||
|
||||
![Second Bdb debugger results][8]
|
||||
|
||||
### Rejecting Bdb in favor of bytecode manipulation
|
||||
|
||||
After our initial disappointment from the trial-and-error cycles of standard debugging methods, we decided to look into a less obvious option: bytecode manipulation.
|
||||
|
||||
The Python interpreter works in two main stages:
|
||||
|
||||
1. **Compiling Python source code into Python bytecode:** This unreadable (for humans) format is optimized for efficient execution and is often cached in those **.pyc** files we have all come to love.
|
||||
2. **Iterating through the bytecode in the _interpreter loop_:** This executes one instruction at a time.
|
||||
|
||||
|
||||
|
||||
This is the pattern we chose: use **bytecode manipulation** to set **non-breaking breakpoints** with no global overhead. This is done by finding the bytecode in memory that represents the source line we are interested in and inserting a function call just before the relevant instruction. This way, the interpreter does not have to do any extra work to support our breakpoints.
|
||||
|
||||
This approach is not magic. Here's a quick example.
|
||||
|
||||
We start with a very simple function:
|
||||
|
||||
|
||||
```
|
||||
def multiply(a, b):
|
||||
result = a * b
|
||||
return result
|
||||
```
|
||||
|
||||
In documentation hidden in the **[inspect][9]** module (which has several useful utilities), we learn we can get the function's bytecode by accessing **multiply.func_code.co_code**:
|
||||
|
||||
|
||||
```
|
||||
`'|\x00\x00|\x01\x00\x14}\x02\x00|\x02\x00S'`
|
||||
```
|
||||
|
||||
This unreadable string can be improved using the **[dis][10]** module in the Python standard library. By calling **dis.dis(multiply.func_code.co_code)**, we get:
|
||||
|
||||
|
||||
```
|
||||
4 0 LOAD_FAST 0 (a)
|
||||
3 LOAD_FAST 1 (b)
|
||||
6 BINARY_MULTIPLY
|
||||
7 STORE_FAST 2 (result)
|
||||
|
||||
5 10 LOAD_FAST 2 (result)
|
||||
13 RETURN_VALUE
|
||||
```
|
||||
|
||||
This gets us closer to understanding what happens behind the scenes of debugging but not to a straightforward solution. Unfortunately, Python does not offer a method for changing a function's bytecode from within the interpreter. You can overwrite the function object, but that's not good enough for the majority of real-world debugging scenarios. You have to go about it in a roundabout way using a native extension.
|
||||
|
||||
### Conclusion
|
||||
|
||||
When building a new tool, you invariably end up learning a lot about how stuff works. It also makes you think out of the box and keep your mind open to unexpected solutions.
|
||||
|
||||
Working on non-breaking breakpoints for Rookout has taught me a lot about compilers, debuggers, server frameworks, concurrency models, and much much more. If you are interested in learning more about bytecode manipulation, Google's open source **[cloud-debug-python][11]** has tools for editing bytecode.
|
||||
|
||||
* * *
|
||||
|
||||
_Liran Haimovitch will present "[Understanding Python’s Debugging Internals][12]" at [PyBay][3], which will be held August 17-18 in San Francisco. Use code [OpenSource35][13] for a discount when you purchase your ticket to let them know you found out about the event from our community._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/8/debug-python
|
||||
|
||||
作者:[Liran Haimovitch][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/liranhaimovitch
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/python_jungle_lead.jpeg?itok=pFKKEvT- (Real python in the graphic jungle)
|
||||
[2]: https://rookout.com/
|
||||
[3]: https://pybay.com/
|
||||
[4]: https://docs.python.org/3/library/sys.html#sys.settrace
|
||||
[5]: https://opensource.com/sites/default/files/uploads/python2docs.png (set_trace Python 2 docs page)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/debuggerresults1.png (First Bdb debugger results)
|
||||
[7]: https://cython.org/
|
||||
[8]: https://opensource.com/sites/default/files/uploads/debuggerresults2.png (Second Bdb debugger results)
|
||||
[9]: https://docs.python.org/2/library/inspect.html
|
||||
[10]: https://docs.python.org/2/library/dis.html
|
||||
[11]: https://github.com/GoogleCloudPlatform/cloud-debug-python
|
||||
[12]: https://pybay.com/speaker/liran-haimovitch/
|
||||
[13]: https://ti.to/sf-python/pybay2019/discount/OpenSource35
|
@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (cycoe)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
@ -0,0 +1,148 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Communicating with other users on the Linux command line)
|
||||
[#]: via: (https://www.networkworld.com/article/3530343/communicating-with-other-users-on-the-linux-command-line.html)
|
||||
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
|
||||
|
||||
Communicating with other users on the Linux command line
|
||||
======
|
||||
|
||||
Thinkstock / Linux
|
||||
|
||||
Sending messages to other users on the Linux command line can be very easy, but there are a number of commands that you might want to consider. In this post, we’ll look at four commands and see how each of them works.
|
||||
|
||||
### wall
|
||||
|
||||
The **wall** command (as in "write all") allows you to send a message to all users who are currently logged into the system. This implies that the system is likely a server and that users are working on the command line. While the wall command is generally used by sysadmins to send out notices to users to let send out information (e.g., that the server is going down for maintenance), it can be used by any user.
|
||||
|
||||
A sysadmin might send out a message like this:
|
||||
|
||||
```
|
||||
$ wall The system will be going down in 15 minutes to address a serious problem
|
||||
```
|
||||
|
||||
Everyone logged into the system will see something like this:
|
||||
|
||||
```
|
||||
Broadcast message from admin@dragonfly (pts/0) (Thu Mar 5 08:56:42 2020):
|
||||
|
||||
The system is going down in 15 minutes to address a serious problem
|
||||
```
|
||||
|
||||
If you want to use single quote marks in your message, enclose the message in double quote marks like this:
|
||||
|
||||
```
|
||||
$ wall “Don’t forget to save your work before logging off”
|
||||
```
|
||||
|
||||
The outside quote marks will not show up in the transmitted message, but, without them, the command sits and waits for a closing single quote.
|
||||
|
||||
### mesg
|
||||
|
||||
If, for some reason, you don’t want to accept messages from another user, you can stop them from arriving with the **mesg** command. This command can be used with a “n” argument to refuse mail from the user or a “y” argument to allow the messages to arrive.
|
||||
|
||||
[][1]
|
||||
|
||||
```
|
||||
$ mesg n doug
|
||||
$ mesg y doug
|
||||
```
|
||||
|
||||
The blocked user will not be notified that their messages have been blocked. You can also block or allow all messages with a **mesg** command like one of these:
|
||||
|
||||
```
|
||||
$ mesg y
|
||||
$ mesg n
|
||||
```
|
||||
|
||||
### write
|
||||
|
||||
Another command for sending text without reverting to email is **write**. This command can be used to communicate with a specific user.
|
||||
|
||||
```
|
||||
$ write nemo
|
||||
Are you still at your desk?
|
||||
I need to talk with you right away.
|
||||
^C
|
||||
```
|
||||
|
||||
Enter your text and use **^C** to exit when you’re done. The command allows you to send text, but doesn’t start a two-way conversation. It just sends the text. If the user is logged in on more than one terminal, you can specify which terminal you want to send the message to or you can rely on the system to choose the one with the shortest idle time.
|
||||
|
||||
```
|
||||
$ write nemo#1
|
||||
```
|
||||
|
||||
If the user you are trying to write to has messages blocked, you should see something like this:
|
||||
|
||||
```
|
||||
$ write nemo
|
||||
write: nemo has messages disabled
|
||||
```
|
||||
|
||||
### talk/ytalk
|
||||
|
||||
The **talk** or **ytalk** command gives you a chance to have an interactive chat with one or more other users. The command will bring up a double-pane (top and bottom) window. Each individual will type into the top portion of the display on their screen and see the responses in the bottom section(s). The respondents can respond to a talk request by typing "talk" followed by the username of the person addressing them.
|
||||
|
||||
```
|
||||
Message from Talk_Daemon@dragonfly at 10:10 ...
|
||||
talk: connection requested by dory@127.0.0.1.
|
||||
talk: respond with: talk dory@127.0.0.1
|
||||
|
||||
$ talk dory
|
||||
```
|
||||
|
||||
The window can involve more than two participants if **ytalk** is used. As you can see in the example below (the result of the "talk dory" command shown above), talk is often ytalk.
|
||||
|
||||
```
|
||||
----------------------------= YTalk version 3.3.0 =--------------------------
|
||||
Is the report ready?
|
||||
|
||||
-------------------------------= nemo@dragonfly =----------------------------
|
||||
Just finished it
|
||||
```
|
||||
|
||||
As explained above, on the other side of the conversation, the talk session window panes are reversed:
|
||||
|
||||
```
|
||||
----------------------------= YTalk version 3.3.0 =--------------------------
|
||||
Just finished it
|
||||
|
||||
-------------------------------= dory@dragonfly =----------------------------
|
||||
Is the report ready?
|
||||
```
|
||||
|
||||
Again, use **^C** to exit.
|
||||
|
||||
To talk with someone on another system, you just need to add a **-h** option and the hostname or IP address with a command like this:
|
||||
|
||||
```
|
||||
$ talk -h 192.168.0.11 nemo
|
||||
```
|
||||
|
||||
### Wrap-Up
|
||||
|
||||
There are a number of basic commands for sending messages to other logged-in users on Linux systems, and they can be especially useful when you need to send out a quick message to all of the users, prefer a quick exchange to a phone call or want to easily involve more than two people in a quick messaging session.
|
||||
|
||||
Some commands, like **wall**, allow a message to be broadcast, but are not interactive. Others, like **talk**, allow both lengthy and multi-user chats, avoiding the need to set up a conference call when a fairly quick exchange of information is all that's required.
|
||||
|
||||
Join the Network World communities on [Facebook][2] and [LinkedIn][3] to comment on topics that are top of mind.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3530343/communicating-with-other-users-on-the-linux-command-line.html
|
||||
|
||||
作者:[Sandra Henry-Stocker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.networkworld.com/author/Sandra-Henry_Stocker/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.networkworld.com/article/3440100/take-the-intelligent-route-with-consumption-based-storage.html?utm_source=IDG&utm_medium=promotions&utm_campaign=HPE21620&utm_content=sidebar ( Take the Intelligent Route with Consumption-Based Storage)
|
||||
[2]: https://www.facebook.com/NetworkWorld/
|
||||
[3]: https://www.linkedin.com/company/network-world
|
130
sources/tech/20200307 Compose music as code using Sonic Pi.md
Normal file
130
sources/tech/20200307 Compose music as code using Sonic Pi.md
Normal file
@ -0,0 +1,130 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Compose music as code using Sonic Pi)
|
||||
[#]: via: (https://opensource.com/article/20/3/sonic-pi)
|
||||
[#]: author: (Matt Bargenquast https://opensource.com/users/mbargenquast)
|
||||
|
||||
Compose music as code using Sonic Pi
|
||||
======
|
||||
There's no need for instrumental mastery with this accessible open
|
||||
source program that can turn you into a musical virtuoso.
|
||||
![Bird singing and music notes][1]
|
||||
|
||||
Maybe you're like me, and you learned a musical instrument when you were in school. For me, it was the piano, and later, the viola. However, I've always held that, as my childhood interests shifted towards computers and coding, I subsequently neglected my music practice. I do wonder what I would have done if I'd had something like Sonic Pi when I was younger. Sonic Pi is an open source program that lets you compose and perform music through code itself. It's the perfect marriage of those two worlds.
|
||||
|
||||
Opensource.com is no stranger to Sonic Pi—we [featured an interview][2] with the creator, Dr. Sam Aaron, back in 2015. Since that time, a lot has changed, and Sonic Pi has grown substantially in many ways. It's reached a major new version milestone, with the long-awaited v3.2 release made publically available on February 28, 2020. A growing community of developers is actively contributing to its [GitHub project][3], while an equally thriving community of composers shares ideas and support in the [official forums][4]. The project is now also financially assisted through a [Patreon campaign][5], and Sam himself has been spreading the word of Sonic Pi through schools, conferences, and workshops worldwide.
|
||||
|
||||
What really shines about Sonic Pi is its approachability. Releases are available for many major flavors of OS, including Windows, macOS, Linux, and of course, the Raspberry Pi itself. In fact, getting started with Sonic Pi on a Raspberry Pi couldn't be simpler; it comes pre-installed with [Raspbian][6], so if you have an existing Raspbian-based setup, you'll find it situated in the programming menu.
|
||||
|
||||
Upon loading Sonic Pi for the first time, you'll be greeted with a simple interface with two main areas: an editor in which to write your code, and a section devoted to Sonic Pi's expansive tutorial. For newcomers, the tutorial is an essential resource for learning the basics, featuring accompanying music programs to reinforce each concept being taught.
|
||||
|
||||
If you're following along, let's code ourselves a simple bit of music and explore the potential of live-coding music. Type or paste the following code into the Sonic Pi editor:
|
||||
|
||||
|
||||
```
|
||||
live_loop :beat do
|
||||
sample :drum_heavy_kick
|
||||
sleep 1
|
||||
end
|
||||
```
|
||||
|
||||
Even if you're a Sonic Pi novice, many coders may immediately understand what's going on here. We're playing a drum kick sample, sleeping for a second, and then repeating. Click the Run button or press ALT+R (meta+R on macOS), and you should hear it begin to play.
|
||||
|
||||
This isn't a very exciting song yet, so let's liven it up with a snare playing on the off-beat. Replace the existing code with the block below and Run again. You can leave the existing beat playing while you do this; you'll notice that your changes will be applied naturally, in time with the beat:
|
||||
|
||||
|
||||
```
|
||||
live_loop :beat do
|
||||
sample :drum_heavy_kick
|
||||
sleep 0.5
|
||||
sample :drum_snare_soft
|
||||
sleep 0.5
|
||||
end
|
||||
```
|
||||
|
||||
While we're at it, let's add a hi-hat right before every fourth beat, just to make things a little interesting. Add this new block below our existing one and Run again:
|
||||
|
||||
|
||||
```
|
||||
live_loop :hihat do
|
||||
sleep 3.9
|
||||
sample :drum_cymbal_closed
|
||||
sleep 0.1
|
||||
end
|
||||
```
|
||||
|
||||
We've got our beat going now, so let's add a bassline! Sonic Pi comes with a variety of synths built-in, along with effects filters such as reverb and distortion. We'll use a combination of the "dsaw" and "tech_saw" synths to give it an electronic retro-synth feel. Add the block below to your existing program, Run, and have a listen:
|
||||
|
||||
|
||||
```
|
||||
live_loop :bass do
|
||||
use_synth :dsaw
|
||||
play :a2, attack: 1, release: 2, amp: 0.3
|
||||
sleep 2.5
|
||||
use_synth :tech_saws
|
||||
play :a1, attack: 1, release: 1.5, amp: 0.8
|
||||
sleep 1.5
|
||||
end
|
||||
```
|
||||
|
||||
You'll note above that we have full control over the [ADSR][7] envelope when playing notes, so we can decide when each sound should peak and fade.
|
||||
|
||||
Lastly, let's add a lead synth and try out one of those effects features known as the "slicer." To spice things up, we'll also introduce an element of pseudo-randomness by letting Sonic Pi pick from a series of potential chords. This is where some of the fun improvisation and "happy accidents" can begin to occur. Add the block below to your existing program and Run:
|
||||
|
||||
|
||||
```
|
||||
live_loop :lead do
|
||||
with_fx :slicer do
|
||||
chords = [(chord :A4, :minor7), (chord :A4, :minor), (chord :D4, :minor7), (chord :F4, :major7)]
|
||||
use_synth :blade
|
||||
play chords.choose, attack: 1, release: 2, amp: 1
|
||||
sleep 2
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Great! Now, we're certainly not going to be competing with Daft Punk any time soon, but hopefully, through this process, you've seen how we can go from a bare beat to something much bigger, in real-time, by adding some simple morsels of code. It is well worth watching one of Sam Aaron's [live coding performances][8] on YouTube for a demonstration of how creative and adaptive Sonic Pi can let you be.
|
||||
|
||||
![Sonic Pi composition example][9]
|
||||
|
||||
Our finished piece, in full
|
||||
|
||||
If you've ever wanted to learn a musical instrument, but felt held back by thoughts like "I don't have rhythm" or "my hands aren't nimble enough," Sonic Pi is a versatile instrument for which none of those things matter. All you need are the ideas, the inspiration, and an inexpensive computer such as the humble Raspberry Pi. The rest is at your fingertips—literally!
|
||||
|
||||
Here are a few handy links to get you started:
|
||||
|
||||
* The Official Sonic Pi [website][10] and [tutorial][11]
|
||||
* [Getting Started with Sonic Pi][12] ([projects.raspberrypi.org][13])
|
||||
* Sonic Pi [Github project][3]
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/3/sonic-pi
|
||||
|
||||
作者:[Matt Bargenquast][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/mbargenquast
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/music-birds-recording-520.png?itok=UoM7brl0 (Bird singing and music notes)
|
||||
[2]: https://opensource.com/life/15/10/interview-sam-aaron-sonic-pi
|
||||
[3]: https://github.com/samaaron/sonic-pi/
|
||||
[4]: https://in-thread.sonic-pi.net/
|
||||
[5]: https://www.patreon.com/samaaron
|
||||
[6]: https://www.raspberrypi.org/downloads/raspbian/
|
||||
[7]: https://en.wikipedia.org/wiki/Envelope_(music)
|
||||
[8]: https://www.youtube.com/watch?v=JEHpS1aTKp0
|
||||
[9]: https://opensource.com/sites/default/files/uploads/sonicpi.png (Sonic Pi composition example)
|
||||
[10]: https://sonic-pi.net/
|
||||
[11]: https://sonic-pi.net/tutorial.html
|
||||
[12]: https://projects.raspberrypi.org/en/projects/getting-started-with-sonic-pi
|
||||
[13]: http://projects.raspberrypi.org
|
@ -1,73 +0,0 @@
|
||||
|
||||
探索免费而开放的网络字体
|
||||
======
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/osdc-lead-docdish-yellow-typewriter-keys.png?itok=0sPgIdMG)
|
||||
|
||||
毫无疑问,近些年来互联网的面貌已经被开放免费的字体所改变。在早些的2010年,你在网络浏览器上几乎只能看到微软制作的最普通的“网络安全字体”[core fonts]
|
||||
[1]。但这一年(2010)正好是好几轮技术革新开始的见证之年:Web开放字体格式的应用给网络高效传输字体文件提供了一个开放的标准,像[Google Fonts]和
|
||||
[Open Font Library]这样的网络字体服务使网络内容发布者在开放证书证书下可以免费使用海量的字体库。
|
||||
|
||||
要夸大这些网络排印领域大事件的积极影响是很难的。但是要将网络开放字体的成功与开源的网络排印划上等号作为一个整体却非常容易,而且得到的结论是挑战已经远离了我们,困难悉数被解决了。然而事实并非如此,如果你很关注网络字体,好消息是你会有非常多的机会参与到对这些字体的改进工作当中去。
|
||||
|
||||
对新手来说,必须要意识到谷歌字体和开源字体库为网页提供了特殊的”服务提供“(service—delivering)字体但是他们给其他使用情况制定字体解决方案。这不是服务方的短视,这是是意味这我们必须去建立其他的解决方案。
|
||||
|
||||
需要解决的问题还非常多。可能最明显的例子就是给linux桌面机器的其他软件安装字体使用所遇到的尴尬情况。你可以通过任何一种服务下载任何一种网络字体,但是你能得到的是一个最普通的压缩包文件,里面有一些TTF或OTF二进制文件和一个普通文本文件的证书。接下来会发生什么完完全全需要你去猜。
|
||||
|
||||
大部分用户很快学会了”正确“的步骤就是手动地复制这些字体二进制文件到他们硬件驱动里一大把的文件夹里的某个文件夹里。但是这样做只能使这个文件被操作系统检索到。它并不能为用户体验带来什么。再强调一遍,这不是网络字体服务的缺陷,然而它是对于关于服务到哪里停止和更多工作需要在其他方面做这个观点的证据。
|
||||
|
||||
在用户视角来说,一个巨大的提升可能就是直接在“下载“这个阶段系统或者桌面环境变得更智能。它(系统或桌面环境)不仅会把字体文件安装到正确的位置上,更重要的是,当用户选择在一个工程使用的字体时,它会自己添加用户所需要得到的重要的元数据。
|
||||
|
||||
附加信息的组成与它如何展示给用户连接着另一个挑战:在linux环境管理一个字体库明显不如任何其他操作系统愉快。字体管理软件总是时不时的出现一下(例如[GTK+ Font Manager][5] 这是最近的一个例子),但是他们(字体管理软件)很少能正确的时候出现。我一直在思考一大堆这些软件让人失望的方面。一个核心的原因是他们把自己限制只展示自己在二进制字体文件内嵌的信息:基本字符集的覆盖,粗细,宽度,和斜度的设定,内置的证书和版权说明等等。
|
||||
|
||||
但是在选择字体的过程中为了工作的选择(字体)都不能在内置数据中找到。正经的字体用户像信息设计者,杂志文章作者,或者书籍美工设计者,他们的字体选择是在每一份文件的需求上做出的。这些需求包含了证书信息,很自然的,它还包含了更多,像关于设计师和厂商的信息,潮流风格的趋势,或者字体在使用当中的细节。
|
||||
|
||||
举个例子,如果你的文档包含了英语和阿拉伯文,你多半想要一种某个很熟悉拉丁文和阿拉伯文设计师设计同时设计两种语言的字体。否则,你将浪费一大堆时间来微调字体大小和行间距来使两种语言良好地结合在一起。你可能从经验中学到,特定的设计师或服务商(字体)比其他人更善于多语言设计。或许和你职业相关的是今天的时尚杂志几乎无一例外的采用"[Didone][6]"风格的字体,"[Didone][6]"是指一种两百多年前最先被[Firmin Didot][7] 和 [Giambattista Bodoni][8]设计出来的反差超级大的字体风格。这种字体恰好就是现在的潮流。
|
||||
|
||||
但是这些字体(Didone, Didot, or Bodoni)中没有一种有可能会出现在内置的二进制文件中,你也不容易发现拉丁文和阿拉伯文是否相得益彰或其他关于字体的背后故事。这些信息有可能出现在补充的材料中,类似某种样本或字体文件中,如果这些东西存在的话。
|
||||
|
||||
字体样本是一份设计好的文档(一般是PDF),它展示了这种字体在使用的情况而且包括了背景信息。字体样本经常起到两重作用,作为市场样本和在挑选字体时的样本。一份样品精心的设计展示了字体在实际应用中的情况和一种自动生产字符表所不能形成的风格。字体样本文件也有可能包含了一些其他重要信息,比如怎样激活字体的开放特色,它提供了什么样的数学表达式和古体字,或者它怎么在跨支持的语言上风格多样。要使这些资源能够被字体管理软件上的用户使用还要走过帮助用户找到合适他们工程的字体的漫长之路。
|
||||
|
||||
当然,如果我们要去考虑一个字体管理软件能够解决文件和样本问题,我们也必须仔细观察各种发行版提供的字体包伴随着什么。linux的用户刚开始只有自动安装的那几种字体,并且提供仓库的包是大部分用户除了下载最普通的压缩包档案之外的唯一字体来源。这些资源包往往非常的“骨感”。商业字体总的来说都包含了样本,文档,还有其他的支持项目,然而开源字体往往没有(这些配套文件)。
|
||||
|
||||
也有一些很棒的开源字体提供了高质量的样本和文档的例子(例如 [SIL Gentium][9] 和 [Bungee][10] 是两种极度不一样但是有效的方案),但是他们几乎不涉足下端的整合包链条。我们肯定能做的(比他们)更好。
|
||||
|
||||
在和系统的字体交互方面提供更丰富的用户体验上面还有一些技术问题。比如说,[AppStream][11]的元数据标准定义了几项针对字体文件的参数,但是现在为止这些参数没有包含样本,设计师和厂商,和其他相关细节的任何信息。另外一个例子,[SPDX][13] (软件包信息交换)格式也没有包含很多软件证书(和证书参数),这些软件证书是用来分配指定字体的。
|
||||
|
||||
最后,就像任何一个唱片爱好者都会告诉你,一个不允许你编辑和完善你的mp3库的ID3信息(mp3头部的一个字节,记录歌手信息)的音乐播放器很快就会变得让人失望。你想要处理标志里的错误,你想要添加比如笔记和乐队,艺术家这样的基本信息,你想要提升你的音乐库。你可能想要做一样的事情来使你的本地字体仓库保持在一个方便使用的状态。
|
||||
|
||||
但是改动字体文件的内置数据已经被禁止了,因为字体往往是被内置或附加到其他文件里的。如果你拿字体二进制文件来胡闹的话,那么你需要重新为你的展示幻灯片分配字体,任何一个人下载这些幻灯片最终都会面对错误的元数据但他们自己并没有过失。所以任何一个要提升字体管理体验的人都要弄清楚如何来战略的讨论内置或外置的字体元数据里反反复复的变化。
|
||||
|
||||
除了技术角度之外,丰富字体管理的体验也是一个设计的挑战。就像我前面说的一样,有几种开放的字体也带了良好的样本和精心写好的证明文件。但是有更多的字体包两者都没有,还有大量的更老的字体包已经没有人维护了。这很可能意味着大部分开放字体包想要获得样本和证明文件的唯一办法就是让(字体)社区去为它们创造。
|
||||
|
||||
可能那(前面说的)是一个很高的要求。但是开源设计社区现在比它以前任何时候都要庞大,并且它(社区)是全面免费开源软件运动中的一个高度活跃的组成部分。所以谁知道呢。可能明年这个时候会发现,在linux桌面系统下载和使用字体会变成一种完全不同的体验。
|
||||
|
||||
在关于现代Linux用户的文字设计上的挑战的一连串思考中包含了打包文件,证明文件设计,甚至有可能需要在桌面环境加入不少新的软件成分。还有其他一连串的东西也需要考虑。共通性就是在网络字体服务不及的地方,事情就变得更加困难。
|
||||
|
||||
最好的消息是,从我的视角来看,就是现在比起以前有更多的人对这个议题感兴趣。我认为我们要感谢像谷歌字体和开放字体库这样的网络字体服务巨头让开放字体得到了更高的关注。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/3/webfonts
|
||||
|
||||
作者:[Nathan Willis][a]
|
||||
译者:https://github.com/Fisherman110
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/n8willis
|
||||
[1]:https://en.wikipedia.org/wiki/Core_fonts_for_the_Web
|
||||
[2]:https://en.wikipedia.org/wiki/Web_Open_Font_Format
|
||||
[3]:https://fonts.google.com/
|
||||
[4]:https://fontlibrary.org/
|
||||
[5]:https://fontmanager.github.io/
|
||||
[6]:https://en.wikipedia.org/wiki/Didone_(typography)
|
||||
[7]:https://en.wikipedia.org/wiki/Firmin_Didot
|
||||
[8]:https://en.wikipedia.org/wiki/Giambattista_Bodoni
|
||||
[9]:https://software.sil.org/gentium/
|
||||
[10]:https://djr.com/bungee/
|
||||
[11]:https://www.freedesktop.org/wiki/Distributions/AppStream/
|
||||
[12]:https://www.freedesktop.org/software/appstream/docs/sect-Metadata-Fonts.html
|
||||
[13]:https://spdx.org/
|
@ -0,0 +1,226 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (mengxinayan)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to structure a multi-file C program: Part 2)
|
||||
[#]: via: (https://opensource.com/article/19/7/structure-multi-file-c-part-2)
|
||||
[#]: author: (Erik O'Shaughnessy https://opensource.com/users/jnyjny)
|
||||
|
||||
如何组织构建多文件 C 语言程序(二)
|
||||
======
|
||||
我将在本系列的第二篇中深入研究由多个文件组成的C程序的结构。
|
||||
![4 个 manilla 文件,黄色,绿色,紫色,蓝色][1]
|
||||
|
||||
在 [(第一篇)][2] 中,我设计了一个名为 [MeowMeow][3] 的多文件 C 程序,该程序实现了一个玩具——[codec][4]。我提到了程序设计中的 Unix 哲学,即在一开始创建多个空文件,并建立一个好的结构。最后,我创建了一个 Makefile 文件夹并阐述了它的作用。在本文中将另一个方向展开:现在我将介绍简单但具有指导性的 MeowMeow 编/解码器的实现。
|
||||
|
||||
当读过我的 "[如何写一个好的 C 语言 main 函数][5]." 后,你便会知道 `main.c` 文件中 `meow` 和 `unmeow` 的结构,其主体结构如下:
|
||||
|
||||
```
|
||||
/* main.c - MeowMeow 流编码器和解码器 */
|
||||
|
||||
/* 00 system includes */
|
||||
/* 01 project includes */
|
||||
/* 02 externs */
|
||||
/* 03 defines */
|
||||
/* 04 typedefs */
|
||||
/* 05 globals (but don't)*/
|
||||
/* 06 ancillary function prototypes if any */
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* 07 variable declarations */
|
||||
/* 08 check argv[0] to see how the program was invoked */
|
||||
/* 09 process the command line options from the user */
|
||||
/* 10 do the needful */
|
||||
}
|
||||
|
||||
/* 11 ancillary functions if any */
|
||||
```
|
||||
|
||||
### 包含项目头文件
|
||||
|
||||
位于第二部分中的 `/* 01 project includes */` 的源代码如下:
|
||||
|
||||
|
||||
```
|
||||
/* main.c - MeowMeow 流编码器和解码器 */
|
||||
...
|
||||
/* 01 project includes */
|
||||
#include "main.h"
|
||||
#include "mmecode.h"
|
||||
#include "mmdecode.h"
|
||||
```
|
||||
|
||||
`#include` 是 C 语言的预处理命令,它会将其后面的文件内容拷贝到当前文件中。如果程序员在头文件名称周围使用双引号,编译器将会在当前目录寻找该文件。如果文件被尖括号包围,编译器将在一组预定义的目录中查找该文件。
|
||||
|
||||
[main.h][6] 文件中包含了 [main.c][7] 文件中用到的定义和别名。我喜欢在头文件里尽可能多的声明,以便我想在我的程序的其他位置使用这些定义。
|
||||
|
||||
头文件 [mmencode.h][8] 和 [mmdecode.h][9] 几乎相同,因此我以 `mmencode.h` 为例来分析。
|
||||
|
||||
|
||||
```
|
||||
/* mmencode.h - MeowMeow 流编码器和解码器 */
|
||||
|
||||
#ifndef _MMENCODE_H
|
||||
#define _MMENCODE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int mm_encode(FILE *src, FILE *dst);
|
||||
|
||||
#endif /* _MMENCODE_H */
|
||||
```
|
||||
|
||||
`#ifdef`,`#define`,`#endif` 指令统称为 “防护” 指令。其可以防止 C 编译器在一个文件中多次包含同一文件。如果编译器在一个文件中发现多个定义/原型/声明,它将会产生警告。因此这些防护措施是必要的。
|
||||
|
||||
在防护内部,它只做两件事:`#include` 指令和函数原型声明。我将包含 `stdio.h` 头文件,以便于能在函数原型中使用 `FILE` 流。函数原型也可以被包含在其他 C 文件中,以便于在文件的命名空间中创建它。你可以将每个文件视为一个命名空间,其中的变量和函数不能被另一个文件中的函数或者变量使用。
|
||||
|
||||
编写头文件很复杂,并且在大型项目中很难管理它。不要忘记使用防护。
|
||||
|
||||
### MeowMeow 编码的实现
|
||||
|
||||
该程序的功能是按照字节进行 `MeowMeow` 字符串的编解码,事实上这是该项目中最简单的部分。截止目前我所做的工作便是支持允许在适当的位置调用此函数:解析命令行,确定要使用的操作,并打开将要操作的文件。下面的循环是编码的过程:
|
||||
|
||||
|
||||
```
|
||||
/* mmencode.c - MeowMeow 流编码器 */
|
||||
...
|
||||
while (![feof][10](src)) {
|
||||
|
||||
if (![fgets][11](buf, sizeof(buf), src))
|
||||
break;
|
||||
|
||||
for(i=0; i<[strlen][12](buf); i++) {
|
||||
lo = (buf[i] & 0x000f);
|
||||
hi = (buf[i] & 0x00f0) >> 4;
|
||||
[fputs][13](tbl[hi], dst);
|
||||
[fputs][13](tbl[lo], dst);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
简单的说,上面代码循环读取文件的一部分,剩下的内容通过 `feof(3)` 函数和 `fgets(3)` 函数读取。然后将读入的内容的每个字节分成 `hi` 和 `lo` 半个字节。半个字节是 4 个比特。这里的奥妙之处在于可以用 4 个比特来编码16个值。我将字符串 `hi` 和 `lo` 用作 16 字符串查找表 `tbl` 的索引,表中包含了对每半个字节编码后的 `MeowMeow` 字符串。这些字符串使用 `fputs(3)` 函数写入目标 `FILE` 流,然后移动到缓存区的下一个字节。
|
||||
|
||||
该表使用 [table.h][14] 中的宏定义进行初始化,在没有特殊原因(比如:要展示包含了另一个项目的本地头文件)时,我喜欢使用宏来进行初始化。我将在未来的文章中进一步探讨原因。
|
||||
|
||||
### MeowMeow 解码的实现
|
||||
|
||||
我承认在开始工作前花了一些时间。解码的循环与编码类似:读取 `MeowMeow` 字符串到缓冲区,将编码从字符串转换为字节
|
||||
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow 流解码器 */
|
||||
...
|
||||
int mm_decode(FILE *src, FILE *dst)
|
||||
{
|
||||
if (!src || !dst) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return stupid_decode(src, dst);
|
||||
}
|
||||
```
|
||||
|
||||
这不是所期望的吗?
|
||||
|
||||
在这里,我通过外部公开的 `mm_decode()` 函数公开了 `stupid_decode()` 函数细节。我上面所说的“外部”是指在这个文件之外。因为 `stupid_decode()` 函数不在头文件中,因此无法在其他文件中调用它。
|
||||
|
||||
当我们想发布一个可靠的公共接口时,有时候会这样做,但是我们还没有完全使用函数解决问题。在本例中,我编写了一个 I/O 密集型函数,该函数每次从源中读取 8 个字节,然后解码获得 1 个字节写入目标流中。较好的实现是一次处理多于 8 个字节的缓冲区。更好的实现还可以通过缓冲区输出字节,进而减少目标流中单字节的写入次数。
|
||||
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow 流解码器 */
|
||||
...
|
||||
int stupid_decode(FILE *src, FILE *dst)
|
||||
{
|
||||
char buf[9];
|
||||
decoded_byte_t byte;
|
||||
int i;
|
||||
|
||||
while (![feof][10](src)) {
|
||||
if (![fgets][11](buf, sizeof(buf), src))
|
||||
break;
|
||||
byte.field.f0 = [isupper][15](buf[0]);
|
||||
byte.field.f1 = [isupper][15](buf[1]);
|
||||
byte.field.f2 = [isupper][15](buf[2]);
|
||||
byte.field.f3 = [isupper][15](buf[3]);
|
||||
byte.field.f4 = [isupper][15](buf[4]);
|
||||
byte.field.f5 = [isupper][15](buf[5]);
|
||||
byte.field.f6 = [isupper][15](buf[6]);
|
||||
byte.field.f7 = [isupper][15](buf[7]);
|
||||
|
||||
[fputc][16](byte.value, dst);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
我并没有使用编码器中使用的位移方法,而是创建了一个名为 `decoded_byte_t` 的自定义数据结构。
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow 流解码器 */
|
||||
...
|
||||
|
||||
typedef struct {
|
||||
unsigned char f7:1;
|
||||
unsigned char f6:1;
|
||||
unsigned char f5:1;
|
||||
unsigned char f4:1;
|
||||
unsigned char f3:1;
|
||||
unsigned char f2:1;
|
||||
unsigned char f1:1;
|
||||
unsigned char f0:1;
|
||||
} fields_t;
|
||||
|
||||
typedef union {
|
||||
fields_t field;
|
||||
unsigned char value;
|
||||
} decoded_byte_t;
|
||||
```
|
||||
|
||||
初次看到代码时可能会感到有点儿复杂,但不要放弃。`decoded_byte_t` 被定义为 `fields_t` 和 `unsigned char` 的 **联合体** 。可以将联合中的命名成员看作同一内存区域的别名。在这种情况下,`value` 和 `field` 指向相同的 8 比特内存区域。将 `field.f0` 设置为 1 也将设置 `value` 中的最低有效位。
|
||||
|
||||
虽然 `unsigned char` 并不神秘,但是对 `fields_t` 的 别名(`typedef`) 也许看起来有些陌生。现代 C 编译器允许程序员在结构体中指定单个 bit 的值。`field` 成员是一个无符号整数类型,可以在成员标识符后紧跟一个冒号和一个整数,该整数指定了比特字段的长度。
|
||||
|
||||
这种数据结构使得按 `field` 名称访问每个比特变得简单。我们依赖编译器生成正确的移位指令来访问 `field`,这可以在调试时为你节省不少时间。
|
||||
|
||||
最后,因为`stupid_decode()` 函数一次仅从源 `FILE` 流中读取 8 个字节,所以它效率并不高。通常我们尝试最小化读写次数,以提高性能和降低调用系统调用的开销。请记住:少次数的读取/写入大的块比多次数的读取/写入小的块好得多。
|
||||
|
||||
### 总结
|
||||
|
||||
用 C 语言编写一个多文件程序需要程序员做更多计划,而不仅仅是一个 `main.c`。但是当你添加功能或者重构时,只需要多花费一点儿努力便可以节省大量时间以及避免让你头痛的问题。
|
||||
|
||||
回顾一下,我更喜欢这样做:多个文件,每个文件仅有简单功能;通过头文件公开那些文件中的小部分功能;把数字常量和字符串常量保存在头文件中;使用 `Makefile` 而不是 Bash 脚本来自动化处理事务;使用 `main()` 函数来处理和解析命令行参数并作为程序主要功能的框架。
|
||||
|
||||
我知道我只是涉及了这个简单程序中发生的事情,并且我很高兴知道哪些事情对您有所帮助以及哪些主题需要详细的解释。在评论中分享您的想法,让我知道。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/7/structure-multi-file-c-part-2
|
||||
|
||||
作者:[Erik O'Shaughnessy][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[萌新阿岩](https://github.com/mengxinayan)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jnyjny
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/file_system.jpg?itok=pzCrX1Kc (4 manilla folders, yellow, green, purple, blue)
|
||||
[2]: https://opensource.com/article/19/7/how-structure-multi-file-c-program-part-1
|
||||
[3]: https://github.com/jnyjny/MeowMeow.git
|
||||
[4]: https://en.wikipedia.org/wiki/Codec
|
||||
[5]: https://opensource.com/article/19/5/how-write-good-c-main-function
|
||||
[6]: https://github.com/JnyJny/meowmeow/blob/master/main.h
|
||||
[7]: https://github.com/JnyJny/meowmeow/blob/master/main.c
|
||||
[8]: https://github.com/JnyJny/meowmeow/blob/master/mmencode.h
|
||||
[9]: https://github.com/JnyJny/meowmeow/blob/master/mmdecode.h
|
||||
[10]: http://www.opengroup.org/onlinepubs/009695399/functions/feof.html
|
||||
[11]: http://www.opengroup.org/onlinepubs/009695399/functions/fgets.html
|
||||
[12]: http://www.opengroup.org/onlinepubs/009695399/functions/strlen.html
|
||||
[13]: http://www.opengroup.org/onlinepubs/009695399/functions/fputs.html
|
||||
[14]: https://github.com/JnyJny/meowmeow/blob/master/table.h
|
||||
[15]: http://www.opengroup.org/onlinepubs/009695399/functions/isupper.html
|
||||
[16]: http://www.opengroup.org/onlinepubs/009695399/functions/fputc.html
|
@ -0,0 +1,237 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (caiichenr)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Building a non-breaking breakpoint for Python debugging)
|
||||
[#]: via: (https://opensource.com/article/19/8/debug-python)
|
||||
[#]: author: (Liran Haimovitch https://opensource.com/users/liranhaimovitch)
|
||||
|
||||
在 Python 调试过程中设置不中断的断点
|
||||
======
|
||||
你对如何让调试器变得更快产生过兴趣吗?本文将分享我们在为 Python 构建调试器时得到的一些经验。
|
||||
![Real python in the graphic jungle][1]
|
||||
|
||||
整段故事讲的是我们在 [Rookout][2] 公司的团队为 Python 调试器开发不中断断点的经历,以及开发过程中得到的经验。我将在本月于旧金山举办的 [PyBay 2019][3] 上介绍有关 Python 调试过程的更多细节,但现在就让我们立刻开始这段故事。
|
||||
|
||||
### Python 调试器的心脏:sys.set_trace
|
||||
|
||||
在诸多可选的 Python 调试器中,使用最广泛的三个是:
|
||||
|
||||
* **pdb**,它是 Python 标准库的一部分
|
||||
* **PyDev**,它是内嵌在 Eclipse 和 Pycharm 等 IDE 中的调试器
|
||||
* **ipdb**,它是IPython的调试器
|
||||
|
||||
|
||||
|
||||
Python 调试器的选择虽多,但它们几乎都基于同一个函数:**sys.set_trace**。 值得一提的是, **[sys.settrace][4]** 可能也是 Python 标准库中最复杂的函数。
|
||||
|
||||
![set_trace Python 2 docs page][5]
|
||||
|
||||
简单来讲,**settrace** 的作用是为解释器注册一个跟踪函数,它在下列四种情形发生时被调用:
|
||||
|
||||
* 函数调用 (Function call)
|
||||
* 语句执行 (Line execution)
|
||||
* 函数返回 (Function return)
|
||||
* 异常抛出 (Exception raised)
|
||||
|
||||
|
||||
|
||||
一个简单的跟踪函数看上去大概是这样:
|
||||
|
||||
|
||||
```
|
||||
def simple_tracer(frame, event, arg):
|
||||
co = frame.f_code
|
||||
func_name = co.co_name
|
||||
line_no = frame.f_lineno
|
||||
print("{e} {f} {l}".format(
|
||||
e=event, f=func_name, l=line_no))
|
||||
return simple_tracer
|
||||
```
|
||||
|
||||
在分析函数时我们首先关注的是参数和返回值,该跟踪函数的参数分别是:
|
||||
|
||||
* **frame**,当前堆栈帧,它是包含当前函数执行时解释器里完整状态的对象
|
||||
* **event**,它是一个值可能为 **"call"**, **"line"**, **"return"**, 或 **"exception"** 的字符串
|
||||
* **arg**,它的取值基于 event 的类型,是一个可选项
|
||||
|
||||
|
||||
|
||||
该跟踪函数的返回值是它自身,这是由于解释器需要持续跟踪两类跟踪函数:
|
||||
|
||||
* **全局跟踪函数(每线程):** 该跟踪函数由当前线程调用 **sys.settrace** 来设置,并在解释器创建一个新 **frame** 时被调用(即代码中发生函数调用时)。虽然没有现成的方式来为不同的线程设置跟踪函数,但你可以调用 **threading.settrace** 来为所有新创建的 **threading** 模块线程设置跟踪函数。
|
||||
* **局部跟踪函数(每一帧):** 解释器将该跟踪函数的值设置为全局跟踪函数创建帧时的返回值。同样也没有现成的方法能够在帧被创建时自动设置局部跟踪函数。
|
||||
|
||||
|
||||
|
||||
该机制的目的是让调试器对被跟踪的帧有更精确的把握,以减少对性能的影响。
|
||||
|
||||
### 简单三步构建调试器 (我们最初的设想)
|
||||
|
||||
仅仅依靠上文提到的内容,用自制的跟踪函数来构建一个真正的调试器似乎有些不切实际。幸运的是,Python 的标准调试器 **pdb** 是基于 **Bdb** 构建的,后者是 Python 标准库中专门用于构建调试器的基类。
|
||||
|
||||
基于 **Bdb** 的简易断点调试器看上去是这样的:
|
||||
|
||||
|
||||
```
|
||||
import bdb
|
||||
import inspect
|
||||
|
||||
class Debugger(bdb.Bdb):
|
||||
def __init__(self):
|
||||
Bdb.__init__(self)
|
||||
self.breakpoints = dict()
|
||||
self.set_trace()
|
||||
|
||||
def set_breakpoint(self, filename, lineno, method):
|
||||
self.set_break(filename, lineno)
|
||||
try :
|
||||
self.breakpoints[(filename, lineno)].add(method)
|
||||
except KeyError:
|
||||
self.breakpoints[(filename, lineno)] = [method]
|
||||
|
||||
def user_line(self, frame):
|
||||
if not self.break_here(frame):
|
||||
return
|
||||
|
||||
# Get filename and lineno from frame
|
||||
(filename, lineno, _, _, _) = inspect.getframeinfo(frame)
|
||||
|
||||
methods = self.breakpoints[(filename, lineno)]
|
||||
for method in methods:
|
||||
method(frame)
|
||||
```
|
||||
|
||||
这个调试器类的全部构成是:
|
||||
|
||||
1. 继承 **Bdb**,定义一个简单的构造函数来初始化基类,并开始跟踪。
|
||||
2. 添加 **set_breakpoint** 方法,它使用 **Bdb** 来设置断点,并跟踪这些断点。
|
||||
3. 重载 **Bdb** 在当前用户行调用的 **user_line** 方法,该方法一定被一个断点调用,之后获取该断点的源位置,并调用已注册的断点。
|
||||
|
||||
|
||||
|
||||
### 这个简易的 Bdb 调试器效率如何呢?
|
||||
|
||||
Rookout 的目标是在生产级性能的使用场景下提供接近普通调试器的使用体验。那么,让我们来看看先前构建出来的简易调试器表现的如何。
|
||||
|
||||
为了衡量调试器的整体性能开销,我们使用如下两个简单的函数来进行测试,它们分别在不同的情景下执行了 1600 万次。请注意,在所有情景下断点都不会被执行。
|
||||
|
||||
|
||||
```
|
||||
def empty_method():
|
||||
pass
|
||||
|
||||
def simple_method():
|
||||
a = 1
|
||||
b = 2
|
||||
c = 3
|
||||
d = 4
|
||||
e = 5
|
||||
f = 6
|
||||
g = 7
|
||||
h = 8
|
||||
i = 9
|
||||
j = 10
|
||||
```
|
||||
|
||||
在使用调试器的情况下需要大量的时间才能完成测试。糟糕的结果指明了,这个简陋 **Bdb** 调试器的性能还远不足以在生产环境中使用。
|
||||
|
||||
![First Bdb debugger results][6]
|
||||
|
||||
### 对调试器进行优化
|
||||
|
||||
降低调试器的额外开销主要有三种方法:
|
||||
|
||||
1. **尽可能的限制局部跟踪:** 由于每一行代码都可能包含大量事务,局部跟踪比全局跟踪的开销要大得多。
|
||||
2. **优化 "call" 事务并尽快将控制权还给解释器:** 在 **call** 事务发生时调试器的主要工作是判断是否需要对该事务进行跟踪。
|
||||
3. **优化 "line" 事务并尽快将控制权还给解释器:** 在 **line** 事务发生时调试器的主要工作是判断我们在此处是否需要设置一个断点。
|
||||
|
||||
|
||||
|
||||
于是我们克隆了 **Bdb** 项目,精简特征,简化代码,针对使用场景进行优化。这些工作虽然得到了一些效果,但仍无法满足我们的需求。因此我们又继续进行了其它的尝试,将代码优化并迁移至 **.pyx** 使用 [Cython][7] 进行编译,可惜结果(如下图所示)依旧不够理想。最终,我们在深入了解 CPython 源码之后意识到,让跟踪过程快到满足生产需求是不可能的。
|
||||
|
||||
![Second Bdb debugger results][8]
|
||||
|
||||
### 放弃 Bdb 转而尝试字节码操作
|
||||
|
||||
熬过先前对标准调试方法进行的试验-失败-再试验循环所带来的失望,我们将目光转向另一种选择:字节码操作。
|
||||
|
||||
Python 解释器的工作主要分为两个阶段:
|
||||
|
||||
1. **将 Python 源码编译成 Python 字节码:** 这种不可读(对人类而言)的格式专为执行的效率而优化,它们通常缓存在我们熟知的 **.pyc** 文件当中。
|
||||
2. **遍历 _interpreter loop_ 中的字节码:** 在这一步中解释器会逐条的执行指令
|
||||
|
||||
|
||||
|
||||
我们选择的模式是:使用**字节码操作**来设置没有全局额外开销的**不中断断点**。这种方式的实现首先需要在内存中的字节码里找到我们感兴趣的部分,然后在该部分的相关机器指令前插入一个函数调用。如此一来,解释器无需任何额外的工作即可实现我们的不中断断点。
|
||||
|
||||
这种方法并不依靠魔法来实现,让我们简要地举个例子。
|
||||
|
||||
首先定义一个简单的函数:
|
||||
|
||||
|
||||
```
|
||||
def multiply(a, b):
|
||||
result = a * b
|
||||
return result
|
||||
```
|
||||
|
||||
在 **[inspect][9]** 模块(其包含了许多实用的单元)的文档里,我们得知可以通过访问 **multiply.func_code.co_code** 来获取函数的字节码:
|
||||
|
||||
|
||||
```
|
||||
`'|\x00\x00|\x01\x00\x14}\x02\x00|\x02\x00S'`
|
||||
```
|
||||
|
||||
使用 Python 标准库中的 **[dis][10]** 模块可以翻译这些不可读的字符串。调用 **dis.dis(multiply.func_code.co_code)** 之后,我们就可以得到:
|
||||
|
||||
|
||||
```
|
||||
4 0 LOAD_FAST 0 (a)
|
||||
3 LOAD_FAST 1 (b)
|
||||
6 BINARY_MULTIPLY
|
||||
7 STORE_FAST 2 (result)
|
||||
|
||||
5 10 LOAD_FAST 2 (result)
|
||||
13 RETURN_VALUE
|
||||
```
|
||||
|
||||
与直截了当的解决方案相比,这种方法让我们更靠近发生在调试器背后的事情。可惜 Python 并没有提供在解释器中修改函数字节码的方法。我们可以对函数对象进行重写,不过那样做的效率满足不了大多数实际的调试场景。最后我们不得不采用一种迂回的方式来使用原生拓展才能完成这一任务。
|
||||
|
||||
### 总结
|
||||
|
||||
在构建一个新工具时,总会学到许多事情的工作原理。这种刨根问底的过程能够使你的思路跳出桎梏,从而得到意料之外的解决方案。
|
||||
|
||||
在 Rookout 团队中构建不中断断点的这段时间里,我学到了许多有关编译器、调试器、服务器框架、并发模型等等领域的知识。如果你希望更深入的了解字节码操作,谷歌的开源项目 **[cloud-debug-python][11]** 为编辑字节码提供了一些工具。
|
||||
|
||||
* * *
|
||||
|
||||
_Liran Haimovitch 将于 2019 年八月 17-18 日在旧金山举办的 [PyBay][3] 中发表题为 "[Understanding Python’s Debugging Internals][12]" 的演说,使用 [OpenSource35][13] 可以获得购票优惠,并使他们得知您是在我们的社区得知此事。_
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/8/debug-python
|
||||
|
||||
作者:[Liran Haimovitch][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[caiichenr](https://github.com/caiichenr)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/liranhaimovitch
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/python_jungle_lead.jpeg?itok=pFKKEvT- (Real python in the graphic jungle)
|
||||
[2]: https://rookout.com/
|
||||
[3]: https://pybay.com/
|
||||
[4]: https://docs.python.org/3/library/sys.html#sys.settrace
|
||||
[5]: https://opensource.com/sites/default/files/uploads/python2docs.png (set_trace Python 2 docs page)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/debuggerresults1.png (First Bdb debugger results)
|
||||
[7]: https://cython.org/
|
||||
[8]: https://opensource.com/sites/default/files/uploads/debuggerresults2.png (Second Bdb debugger results)
|
||||
[9]: https://docs.python.org/2/library/inspect.html
|
||||
[10]: https://docs.python.org/2/library/dis.html
|
||||
[11]: https://github.com/GoogleCloudPlatform/cloud-debug-python
|
||||
[12]: https://pybay.com/speaker/liran-haimovitch/
|
||||
[13]: https://ti.to/sf-python/pybay2019/discount/OpenSource35
|
Loading…
Reference in New Issue
Block a user