2019年12月

我们邀请 Opensource.com 的 DevOps 团队,希望他们能够谈一谈作为 DevOps 内向者的休验,同时给 DevOps 外向者一些建议。下面是他们的回答。

我们邀请我们的 DevOps 团队 谈一谈他们作为一个内向者的体验,并给外向者们一些建议。但是在我们开始了解他们的回答之前,让我们先来定义一下这些词汇。

“内向者”是什么意思?

内向者通常指的是一部分人群,当他们和别人相处的时候,会使他们的能量耗尽,而不是激发他们更多的能量。当我们思考我们是如何恢复能量时,这是一个非常有用的词汇:内向者通常需要更多的独处时间来恢复能量,特别是和一群人在一起很长时间后。关于内向者的一个非常大的误解就是他们一定是“害羞的”,但是科学表明,那不过是另一种不同的性格特征。

内向性与外向性是通过 Myers Briggs 类型指标 而为人所知的,现在也常常被称作一个 光谱 的两端。虽然这个世界看起来好像外向者比内向者要多,但是心理学者则倾向于认为大部分人在光谱上的位置是落在 中间性格或偏内向性格的

现在,我们来看看问答。

DevOps 技术主管可以通过哪些方式来让内向者感觉他们是团队的一部分并且愿意分享他们的想法?

“每个人都会不大一样,所以观察敏锐就很重要了。从 GitLab 过来的一个人告诉我,他们的哲学就是如果他们没有提供任何意见,那么他们就是被排除在外的。如果有人在一个会议上没有提供任何的意见,那就想办法让他们加入进来。当我知道一个内向者对我们将要讨论的会议论题感兴趣的时候,我会提前请他写一些书面文本。有非常多的会议其实是可以避免的,只要通过把讨论放到 Slack 或者 GitLab 上就行了,内向者会更愿意参与进来。在站立会议中,每个人都会交代最新的进展,在这个环境下,内向者表现得很好。有时候我们在其实会议上会重复做一些事情,仅仅是为了保证每个人都有时间发言。我同时也会鼓励内向者在工作小组或者社区小组面前发言,以此来锻炼他们的这些技能。”—— 丹·巴克

我觉得别人对我做的最好的事情,就是他们保证了当重大问题来临的时候,我拥有必要的技能去回答它。彼时,我作为一名非常年轻的入伍空军的一员,我需要给我们部队的高级领导做状态简报的汇报。我必须在任何时候都有一些可用的数据点,以及在实现我们确立的目标的过程中,产生延误以及偏差的背后的原因。那样的经历推动着我从一个‘幕后人员’逐渐变得更加愿意和别人分享自己的观点和想法。”—— 克里斯·肖特

通过文化去领导。为你的同僚一起设计和尝试仪式。你可以为给你的小组或团队设计一个小的每周仪式,甚至给你的部门或组织设计一个年度的大仪式。它的意义在于去尝试一些事物,并观察你在其中的领导角色。去找到你们文化当中的代沟以及对立。回顾团队的信仰和行为。你能从哪里观察到对立?你们的文化中缺失了什么?从一个小陈述开始‘我从 X 和 Y 之间看到了对立’,或者‘我的团队缺少了 Z’。接着,将代沟与对立转换为问题:写下三个‘我们如何能……(How might we’s, HMWs)’。”—— 凯瑟琳·路易斯

“内向者不是一个不同的群体,他们要么是在分享他们的想法之前想得太多或等得太久的一些人,要么就是一些根本不知道发生了什么的人。我就是第一种,我想太多了,有时候还担心我的意见会被其他人嘲笑,或者没有什么意思,或者想偏了。形成那样的思维方式很难,但它同时也在吞噬着我学习更好事物的机会。有一次,我们团队在讨论一个实现问题。我当时的老大一次又一次地问我,为什么我没有作为团队中更具经验的人参与进来,然后我就(集齐了全宇宙的力量之后)开口说我想说的大家都已经说过了。他说,有时候我可以重复说一次,事情纷繁,如果你能够重复一遍你的想法,即使它已经被讨论过了,也会大有裨益。好吧,虽然它不是一种特别信服的方式,但是我知道了至少有人想听听我怎么说,它给了我一点信心。

“现在,我所使用的让团队中的人发言的方法是我经常向内向的人求助,即使我知道解决方法,并且在团队会议和讨论中感谢他们来建立他们的自信心,通过给他们时间让他们一点一点的从他们寡言的本性中走出来,从而跟团队分享很多的知识。他们在外面的世界中可能仍然会有一点点孤立,但是在团队里面,有些会成为我们可以信赖的人。”—— 阿布希什克·塔姆拉卡尔

“我给参加会议的内向者的建议是,找一个同样要参加会议的朋友或者同事,这样到时你就会有人可以跟你一起舒服地交谈,在会议开始之前,提前跟其他的与会者(朋友、行业联系人、前同事等等)约着见个面或者吃顿饭,要注意你的疲劳程度,并且照顾好自己:如果你需要重新恢复能量,就跳过那些社交或者夜晚的活动,在事后回顾中记录一下自己的感受。”—— 伊丽莎白·约瑟夫

和一个内向者倾向的同事一起工作时,有什么提高生产效率的小建议?

“在保证质量时,生产效率会越来越具备挑战性。在大多数时候,工作中的一个小憩或者轻松随意的交谈,可能正是我们的创造性活动中需要的一个火花。再说一次,我发现当你的团队中有内向者时, Slack 和 Github 会是一个非常有用的用于交换想法以及和其他人互动的媒介。我同时也发现,结对编程对于大部分的内向者也非常有用,虽然一对一的交流对于他们来说,并不像交税那么频繁,但是生产质量和效率的提升却是重大的。但是,当一个内向者在独自工作的时间,团队中的所有人都不应该去打断他们。最好是发个邮件,或者使用没有那么强的侵入性的媒介。”—— 丹·巴克

“给他们趁手的工具,让他们工作并归档他们的工作。让他们能够在他们的工作上做到最好。要足够经常地去检查一下,保证他们没有走偏路,但是要记住,相比外向者而言,这样做是更大的一种让人分心的困扰。”—— 克里斯·肖特

当我低着头的时候,不要打断我。真的,别打断我!当我沉浸在某件事物中时,这样做会造成我至少需要花费两个小时,才能让我的大脑重新回到之前的状态。感觉很痛苦。真的。你可以发个邮件让我去有白板的地方。然后从客户的角度而不是你的角度——通过画图的方式——分享下有什么问题。要知道,可能同时会有十几个客户问题缠绕在我的脑海中,如果你的问题听起来就是‘这样子做会让我在我的领导面前显得很好’的那一类问题,那么相比我脑袋中已经有的真正的客户问题而言,它不会得到更多的关注的。画个图,给我点时间思考。当我准备分享我的看法的时候,保证有多支马克笔可以使用。准备好接受你对问题的假设有可能完全是错误的。”—— 凯瑟琳·路易斯

“感谢和鼓励就是解决的方法,感谢可能不是一份工作评估,但是感谢能让人舒服地感受到自己并不仅仅是一个活着的独立实体,因而每个人都能够感觉到自己是被倾听的,而不是被嘲笑或者低估的。”—— 阿布希什克·塔姆拉卡尔

结语

在与内向的 DevOps 爱好者的这次交谈中,我们最大的启迪就是平等:其他人需要被怎样对待,就怎样对待他们,同时你想被怎样对待,就去要求别人怎样对待你。无论你是内向还是外向,我们都需要承认我们并非全以相同的一种方式体验这个世界。我们的同事应当被给予足够的空间以完成他们的工作,通过讨论他们的需求作为了解如何支持他们的开始。我们的差异正是我们的社区如此特别的原因,它让我们的工作对更多的人更加的有用。与别人沟通最有效的方式,就是对于你们两者而言都可行的方式。


via: https://opensource.com/article/19/7/devops-introverted-people

作者:Matthew Broberg 选题:lujun9972 译者:XLCYun 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

昨天,我和一名记者谈到了一个问题:广告商是如何在互联网上对人们进行追踪的?我们津津有味地查看了 Firefox 的开发者工具(虽然我不是一个互联网隐私专家,但至少还会使用开发者工具中的“network”标签页),从中我终于弄明白 像素追踪 tracking pixels 在实际中是如何工作的了。

问题:Facebook 怎么知道你逛了 Old Navy?

我时常听人们说起这种有些诡异的上网经历:你在线上浏览了一个商品,一天之后,竟然看到了同一款靴子(或者是别的什么你当时浏览的商品)的广告。这就是所谓的“再营销”,但它到底是如何实现的呢?

在本文中,我们来进行一个小实验,看看 Facebook 究竟是怎么知道你在线上浏览了什么商品的。这里使用 Facebook 作为示例,只是因为很容易找到使用了 Facebook 像素追踪技术的网站;其实,几乎所有互联网广告公司都会使用类似的追踪技术。

准备:允许第三方追踪器,同时关闭广告拦截器

我使用的浏览器是 Firefox,但是 Firefox 默认拦截了很多这种类型的追踪,所以需要修改 Firefox 的隐私设置,才能让这种追踪生效。

首先,我将隐私设置从默认设置(截图)修改为允许第三方追踪器的个性化设置(截图),然后禁用了一些平时运行的隐私保护扩展。

截图

截图

像素追踪:关键不在于 gif,而在于请求参数

像素追踪是网站用来追踪你的一个 1x1 大小的 gif。就其本身而言,一个小小的 1x1 gif 显然起不到什么作用。那么,像素追踪到底是如何进行追踪的?其中涉及两个方面:

  1. 通过使用像素追踪上的请求参数,网站可以添加额外的信息,比如你正在访问的页面。这样一来,请求的就不是 https://www.facebook.com/tr/(这个链接是一个 44 字节大小的 1x1 gif),而是 https://www.facebook.com/tr/?the_website_you're_on。(邮件营销人员会使用类似的技巧,通过为像素追踪指定一个独特的 URL,弄清楚你是否打开了某一封邮件。)
  2. 在发送该请求的同时,还发送了相应的 cookie。这样一来广告商就可以知道,访问 oldnavy.com 的这个人和在同一台电脑上使用 Facebook 的是同一个人。

Old Navy 网站上的 Facebook 像素追踪

为了对此进行验证,我在 Old Navy(GAP 旗下的一个服装品牌)网站上浏览了一个商品,相应的 URL 是 https://oldnavy.gap.com/browse/product.do?pid=504753002&cid=1125694&pcid=1135640&vid=1&grid=pds_0_109_1(这是一件“男款短绒格子花呢大衣”)。

在我浏览这个商品的同时,页面上运行的 Javascript(用的应该是这段代码)向 facebook.com 发送了一个请求。在开发者工具中,该请求看上去是这样的:(我屏蔽了大部分 cookie 值,因为其中有一些是我的登录 cookie)

下面对其进行拆解分析:

  1. 我的浏览器向如下 URL 发送了一个请求;
https://www.facebook.com/tr/?id=937725046402747&ev=PageView&dl=https%3A%2F%2Foldnavy.gap.com%2Fbrowse%2Fproduct.do%3Fpid%3D504753002%26cid%3D1125694%26pcid%3Dxxxxxx0%26vid%3D1%26grid%3Dpds_0_109_1%23pdp-page-content&rl=https%3A%2F%2Foldnavy.gap.com%2Fbrowse%2Fcategory.do%3Fcid%3D1135640%26mlink%3D5155%2Cm_mts_a&if=false&ts=1576684838096&sw=1920&sh=1080&v=2.9.15&r=stable&a=tmtealium&ec=0&o=30&fbp=fb.1.1576684798512.1946041422&it=15xxxxxxxxxx4&coo=false&rqm=GET
  1. 与该请求同时发送的,还有一个名为 fr 的 cookie,取值为
10oGXEcKfGekg67iy.AWVdJq5MG3VLYaNjz4MTNRaU1zg.Bd-kxt.KU.F36.0.0.Bd-kx6.

(估计是我的 Facebook 广告追踪 ID)

在所发送的像素追踪查询字符串里,有三个值得注意的地方:

  • 我当前访问的页面:https://oldnavy.gap.com/browse/product.do?pid=504753002&cid=1125694&pcid=1135640&vid=1&grid=pds_0_109_1#pdp-page-content
  • 引导我来到当前页面的上一级页面:https://oldnavy.gap.com/browse/category.do?cid=1135640&mlink=5155,m_mts_a
  • 作为我的身份标识的 cookie:10oGXEcKfGekg67iy.AWVdJq5MG3VLYaNjz4MTNRaU1zg.Bd-kxt.KU.F36.0.0.Bd-kx6.

下面来逛逛 Facebook!

下面来逛逛 Facebook 吧。我之前已经登入了 Facebook,猜猜看,我的浏览器发送给 Facebook 的 cookie 是什么?

不出所料,正是之前见过的 fr cookie:10oGXEcKfGekg67iy.AWVdJq5MG3VLYaNjz4MTNRaU1zg.Bd-kxt.KU.F36.0.0.Bd-kx6.。Facebook 现在一定知道我(Julia Evans,这个 Facebook 账号所关联的人)在几分钟之前访问了 Old Navy 网站,并且浏览了“男款短绒格子花呢大衣”,因为他们可以使用这个 cookie 将数据串联起来。

这里涉及到的是第三方 cookie

Facebook 用来追踪我访问了哪些网站的 cookie,属于所谓的“第三方 cookie”,因为 Old Navy 的网站使用它为一个第三方(即 facebook.com)确认我的身份。这和用来维持登录状态的“第一方 cookie”有所不同。

Safari 和 Firefox 默认都会拦截许多第三方 cookie(所以需要更改 Firefox 的隐私设置,才能够进行这个实验),而 Chrome 目前并不进行拦截(很可能是因为 Chrome 的所有者正是一个广告公司)。(LCTT 译注:Chrome 可以设置阻拦)

网站上的像素追踪有很多

如我所料,网站上的像素追踪有 很多。比如,wrangler.com 在我的浏览器里加载了来自不同域的 19 个不同的像素追踪。wrangler.com 上的像素追踪分别来自:ct.pinterest.comaf.monetate.netcsm.va.us.criteo.netgoogle-analytics.comdpm.demdex.netgoogle.caa.tribalfusion.comdata.photorank.mestats.g.doubleclick.netvfcorp.dl.sc.omtrdc.netib.adnxs.comidsync.rlcdn.comp.brsrvr.com,以及 adservice.google.com

Firefox 贴心地指出,如果使用 Firefox 的标准隐私设置,其中的大部分追踪器都会被拦截:

浏览器的重要性

浏览器之所以如此重要,是因为你的浏览器最终决定了发送你的什么信息、发送到哪些网站。Old Navy 网站上的 Javascript 可以请求你的浏览器向 Facebook 发送关于你的追踪信息,但浏览器可以拒绝执行。浏览器的决定可以是:“哈,我知道 facebook.com/tr/ 是一个像素追踪,我不想让我的用户被追踪,所以我不会发送这个请求”。

浏览器还可以允许用户对上述行为进行配置,方法包括更改浏览器设置,以及安装浏览器扩展(所以才会有如此多的隐私保护扩展)。

摸清其中原理,实为一件趣事

在我看来,弄清楚 cookie/像素追踪是怎么用于对你进行追踪的,实在是一件趣事(尽管有点吓人)。我之前大概明白其中的道理,但是并没有亲自查看过像素追踪上的 cookie,也没有看过发送的查询参数上究竟包含什么样的信息。

当然,明白了其中的原理,也就更容易降低被追踪的概率了。

可以采取的措施

为了尽量避免在互联网上被追踪,我采取了几种简单的措施:

  • 安装一个广告拦截器(比如 ublock origin 之类)。广告拦截器可以针对许多追踪器的域进行拦截。
  • 使用目前默认隐私保护强度更高的 Firefox/Safari,而不是 Chrome。
  • 使用 Facebook Container 这个 Firefox 扩展。该扩展针对 Facebook 进一步采取了防止追踪的措施。

虽然在互联网上被追踪的方式还有很多(尤其是在使用手机应用的时候,因为在这种情况下,你没有和像对浏览器一样的控制程度),但是能够理解这种追踪方法的工作原理,稍微减少一些被追踪的可能性,也总归是一件好事。


via: https://jvns.ca/blog/how-tracking-pixels-work/

作者:Julia Evans 选题:lujun9972 译者:chen-ni 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

服务是必不可少的后台进程,它通常随系统启动,并在关机时关闭。如果你是系统管理员,那么你会定期处理服务。如果你是普通桌面用户,你可能会遇到需要重启服务的情况,例如安装 Barrier 来用于在计算机之间共享鼠标和键盘。或在使用 ufw 设置防火墙时。

今天,我将向你展示两种管理服务的方式。你将学习在 Ubuntu 或任何其他 Linux 发行版中启动、停止和重启服务。

systemd 与 init

如今,Ubuntu 和许多其他发行版都使用 systemd 而不是旧的 init。

在 systemd 中,可以使用 systemctl 命令管理服务。

在 init 中,你可以使用 service 命令管理服务。

你会注意到,即使你的 Linux 系统使用 systemd,它仍然可以使用 service 命令(与 init 系统一起使用的)。这是因为 service 命令实际上已重定向到 systemctl。systemd 引入了向后兼容性,因为系统管理员们习惯使用 service 命令。

在本教程中,我将同时展示 systemctlservice 命令。

我用的是 Ubuntu 18.04,但其他版本的过程也一样。

方法 1:使用 systemd 在 Linux 中管理服务

我从 systemd 开始,因为它被广泛接受。

1、列出所有服务

为了管理服务,你首先需要知道系统上有哪些服务可用。你可以使用 systemd 的命令列出 Linux 系统上的所有服务:

systemctl list-unit-files --type service -all

systemctl list-unit-files

此命令将输出所有服务的状态。服务状态有 启用 enabled 禁用 disabled 屏蔽 masked (在取消屏蔽之前处于非活动状态)、 静态 static 已生成 generated

grep 命令 结合,你可以仅显示正在运行的服务:

sudo systemctl | grep running

Display running services systemctl

现在,你知道了如何引用所有不同的服务,你可以开始主动管理它们。

注意: 下列命令中的 <service-name> 应该用你想管理的服务名代替。(比如:network-manager、ufw 等)

2、启动服务

要在 Linux 中启动服务,你只需使用它的名字:

systemctl start <service-name>

3、停止服务

要停止 systemd 服务,可以使用 systemctl 命令的 stop 选项:

systemctl stop <service-name>

4、重启服务

要重启 systemd 服务,可以使用:

systemctl restart <service-name>

5、检查服务状态

你可以通过打印服务状态来确认你已经成功执行特定操作:

systemctl status <service-name>

这将以以下方式输出:

systemctl status

这是 systemd 的内容。现在切换到 init。

方法 2:使用 init 在 Linux 中管理服务

init 的命令和 systemd 的一样简单。

1、列出所有服务

要列出所有 Linux 服务,使用:

service --status-all

service –status-all

前面的 [ – ] 代表禁用[ + ] 代表启用

2、启动服务

要在 Ubuntu 和其他发行版中启动服务,使用命令:

service <service-name> start

3、停止服务

停止服务同样简单。

service <service-name> stop

4、重启服务

如果你想重启服务,命令是:

service <service-name> restart

5、检查服务状态

此外,要检查是否达到了预期的结果,你可以输出服务状态:

service <service-name> status

这将以以下方式输出:

service status

最重要的是,这将告诉你某项服务是否处于活跃状态(正在运行)。

总结

今天,我详细介绍了两种在 Ubuntu 或任何其他 Linux 系统上管理服务的非常简单的方法。 希望本文对你有所帮助。

你更喜欢哪种方法? 让我在下面的评论中知道!


via: https://itsfoss.com/start-stop-restart-services-linux/

作者:Sergiu 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

本文是 24 天 Linux 桌面特别系列的一部分。如果老式的苹果电脑是用开源 POSIX 构建的呢?你可以通过构建 Macintosh 式的虚拟窗口管理器来实现。

 title=

想象一下穿越到另一段平行历史,Apple II GS 和 MacOS 7 是基于开源 POSIX 构建的,它使用了与现代 Linux 相同的所有惯例,例如纯文本配置文件和模块化系统设计。这样的操作系统将为其用户带来什么?你可以使用 Macintosh 式的虚拟窗口管理器(MLVWM)来回答这些问题(甚至更多!)。

安装 MLVWM

MLVWM 安装并不容易,并且可能不在你的发行版软件仓库中。如果你有时间理解翻译不佳的 README 文件,编辑一些配置文件,收集并调整一些旧的 .xpm 图片,编辑一两个 Xorg 选项,那么你就可以体验 MLVWM。不管怎么说,这是一个新奇的窗口管理器,其最新版本可以追溯到 2000 年。

要编译 MLVWM,你必须安装 imake,它提供了 xmkmf 命令。你可以从发行版的软件仓库中安装 imake,也可以直接从 Freedesktop.org 获得。假设你已经有 xmkmf 命令,请进入包含 MLVWM 源码的目录,然后运行以下命令进行构建:

$ xmkmf -a
$ make

构建后,编译后的 mlvwm 二进制文件位于 mlvwm 目录中。将其移动到你的 PATH 的任何位置:

$ mv mlvwm/mlvwm /usr/local/bin/

编辑配置文件

现在已经安装好 MLVWM,但是如果不调整几个配置文件并仔细放好所需的图像文件,它将无法正确启动。示例配置文件位于你下载的源代码的 sample_rc 目录中。将文件 Mlvwm-NetscapeMlvwm-Xterm 复制到你的主目录:

$ cp sample_rc/Mlvwm-{Netscape,Xterm} $HOME

Mlvwmrc 改名为 $HOME/.mlvwmrc(是的,即使示例文件的名称看似是大写字母,但你也必须使用小写的 “m”):

$ cp sample_rc/Mlvwmrc $HOME/.mlvwmrc

打开 .mlwmrc 并找到第 54-55 行,它们定义了 MLVWM 在菜单和 UI 中使用的像素图的路径(IconPath):

# Set icon search path. It needs before "Style".
IconPath /usr/local/include/X11/pixmaps:/home2/tak/bin/pixmap

调整路径以匹配你填充图像的路径(我建议使用 $HOME/.local/share/pixmaps)。MLVWM 不提供像素图,因此需要你提供构建桌面所需图标。

即使你有位于系统其他位置的像素图(例如 /usr/share/pixmaps),也要这样做,因为你需要调整像素图的大小,你可能也不想在系统范围内执行此操作。

# Set icon search path. It needs before "Style".
IconPath /home/seth/.local/share/pixmaps

选择像素图

你已将 .local/share/pixmaps 目录定义为像素图源路径,但是该目录和图像均不存在。创建目录:

$ mkdir -p $HOME/.local/share/pixmaps

现在,配置文件将图像分配给菜单项和 UI 元素,但是系统中不存在这些图像。要解决此问题,请通读配置文件并找到每个 .xpm 图像。对于配置中列出的每个图像,将具有相同文件名的图像(或更改配置文件中的文件名)添加到你的 IconPath 目录。

.mlvwmrc 文件的注释很好,因此你可以大致了解要编辑的内容。无论如何,这只是第一步。你可以随时回来更改桌面外观。

这有些例子。

此代码块设置屏幕左上角的图标:

# Register the menu
Menu Apple, Icon label1.xpm, Stick

label1.xpm 图像实际上在源代码的 pixmap 目录中,但我更喜欢使用来自 /usr/share/pixmapsPenguin.xpm(在 Slackware 上)。无论使用什么,都必须将自定义像素图放在 ~/.local/share/pixmaps 中,并在配置中更改像素图的名称,或者重命名像素图以匹配配置文件中当前的名称。

此代码块定义了左侧菜单中列出的应用:

"About this Workstation..." NonSelect, Gray, Action About
"" NonSelect
"Terminal"      Icon mini-display.xpm, Action Exec "kterm" exec kterm -ls
"Editor"  Action Exec "mule" exec mule, Icon mini-edit.xpm
"calculator" Action Exec "xcal" exec xcalc, Icon mini-calc.xpm
END

通过遵循与配置文件中相同的语法,你可以自定义像素图并将自己的应用添加到菜单中(例如,我将 mule 更改为 emacs)。这是你在 MLVWM GUI 中打开应用的入口,因此请列出你要快速访问的所有内容。你可能还希望包括指向 /usr/share/applications 文件夹的快捷方式。

"Applications" Icon Penguin.xpm, Action Exec "thunar /usr/share/applications" exec thunar /usr/share/applications

完成编辑配置文件并将自己的图像添加到 IconPath 目录后,必须将所有像素图的大小都调整为大约 16x16 像素。(MLVWM 的默认设置不一致,因此存在变化空间。)你可以使用 ImageMagick 进行批量操作:

$ for i in ~/.local/share/mlvwm-pixmaps/*xpm ; do convert -resize '16x16^' $i; done

启动 MLVWM

最简单的运行 MLVWM 的方式是让 Xorg 完成大部分工作。首先,你必须创建一个 $HOME/.xinitrc 文件。我从 Slackware 复制了这个,它也是从 Xorg 拿来的:

#!/bin/sh
# $XConsortium: xinitrc.cpp,v 1.4 91/08/22 11:41:34 rws Exp $

userresources=$HOME/.Xresources
usermodmap=$HOME/.Xmodmap
sysresources=/etc/X11/xinit/.Xresources
sysmodmap=/etc/X11/xinit/.Xmodmap

# merge in defaults and keymaps

if [ -f $sysresources ]; then
    xrdb -merge $sysresources
fi

if [ -f $sysmodmap ]; then
    xmodmap $sysmodmap
fi

if [ -f $userresources ]; then
    xrdb -merge $userresources
fi

if [ -f $usermodmap ]; then
    xmodmap $usermodmap
fi

# Start the window manager:
if [ -z "$DESKTOP_SESSION" -a -x /usr/bin/ck-launch-session ]; then
  exec ck-launch-session /usr/local/bin/mlvwm
else
  exec /usr/local/bin/mlvwm
fi

根据此文件,startx 命令的默认操作是启动 MLVWM。但是,你的发行版可能对于图形服务器启动(或被终止以重新启动)时会发生的情况有其他做法,因此此文件可能对你没有什么帮助。在许多发行版上,你可以添加 .desktop 文件到 /usr/share/xsessions 中,以将其列在 GDM 或 KDM 菜单中,因此创建名为 mlvwm.desktop 的文件并输入:

[Desktop Entry]
Name=Mlvwm
Comment=Macintosh-like virtual window manager
Exec=/usr/local/bin/mlvwm
TryExec=ck-launch-session /usr/local/bin/mlvwm
Type=Application

从桌面会话注销并重新登录到 MLVWM。默认情况下,会话管理器(KDM、GDM 或 LightDM,具体取决于你的设置)将继续登录到以前的桌面,因此在登录之前必须覆盖它。

对于 GDM:

对于 SDDM:

强制启动

如果 MLVWM 无法启动,请尝试安装 XDM,这是一个轻量级会话管理器,它不会查询 /usr/share/xsessions 的内容,而是执行经过身份验证用户的所有 .xinitrc 操作。

 title=

打造自己的复古苹果

MLVWM 桌面未经打磨、不完美、模仿到位且充满乐趣。你看到的许多菜单项都是未实现的,但你可以使它们变得活跃且有意义。

这是一次让你时光倒流、改变历史,让老式苹果系列电脑成为开源堡垒的机会。成为一名修正主义者,设计你自己的复古苹果桌面,最重要的是,它有乐趣。


via: https://opensource.com/article/19/12/linux-mlvwm-desktop

作者:Seth Kenlon 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

欢迎阅读“Python 光明节(Pythonukkah)”系列文章,这个系列文章将会讨论《Python 之禅》。我们首先来看《Python 之禅》里的前两个原则:美观与明确。

早在 1999 年,Python 的贡献者之一,Tim Peters 就提出了《Python 之禅》,直到二十年后的今天,《Python 之禅》中的 19 条原则仍然对整个社区都产生着深远的影响。为此,就像庆典光明的 光明节 Hanukkah 一样,我们举行了这一次的“ Python 光明节 Pythonukkah ”。首先,我们会讨论《Python 之禅》中的前两个原则:美观和明确。

“Hanukkah is the Festival of Lights,

Instead of one day of presents, we get eight crazy nights.”

—亚当·桑德勒,光明节之歌

美观胜于丑陋 Beautiful is better than ugly

著名的《 计算机程序的构造和解释 Structure and Interpretation of Computer Programs 》中有这么一句话: 代码是写给人看的,只是恰好能让机器运行。 Programs must be written for people to read and only incidentally for machines to execute. 机器并不在乎代码的美观性,但人类在乎。

阅读美观的代码对人们来说是一种享受,这就要求在整套代码中保持一致的风格。使用诸如 Blackflake8Pylint 这一类工具能够有效地接近这一个目标。

但实际上,只有人类自己才知道什么才是真正的美观。因此,代码审查和协同开发是其中的不二法门,同时,在开发过程中倾听别人的意见也是必不可少的。

最后,个人的主观能动性也很重要,否则一切工具和流程都会变得毫无意义。只有意识到美观的重要性,才能主动编写出美观的代码。

这就是为什么美观在众多原则当中排到了首位,它让“美”成为了 Python 社区的一种价值。如果有人要问,”我们真的在乎美吗?“社区会以代码给出肯定的答案。

明确胜于隐晦 Explicit is better than implicit

人类会欢庆光明、惧怕黑暗,那是因为光能够让我们看到难以看清的事物。同样地,尽管有些时候我们会不自觉地把代码写得含糊不清,但明确地编写代码确实能够让我们理解很多抽象的概念。

“为什么类方法中要将 self 显式指定为第一个参数?”

这个问题已经是老生常谈了,但网络上很多流传已久的回答都是不准确的。在编写 元类 metaclass 时,显式指定 self 参数就显得毫无意义。如果你没有编写过元类,希望你可以尝试一下,这是很多 Python 程序员的必经之路。

显式指定 self 参数的原因并不是 Python 的设计者不想将这样的元类视为“默认”元类,而是因为第一个参数必须是显式的。

即使 Python 中确实允许非显式的情况存在(例如上下文变量),但我们还是应该提出疑问:某个东西是不是有存在的必要呢?如果非显式地传递参数会不会出现问题呢?有些时候,由于种种原因,这是会有问题的。总之,在写代码时一旦能够优先考虑到明确性,至少意味着能对不明确的地方提出疑问并对结果作出有效的估计。


via: https://opensource.com/article/19/12/zen-python-beauty-clarity

作者:Moshe Zadka 选题:lujun9972 译者:HankChow 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

我们通过为自行车商店构建示例应用程序来学习如何使用 JPA。

对应用开发者来说, Java 持久化 API Java Persistence API (JPA)是一项重要的 java 功能,需要透彻理解。它为 Java 开发人员定义了如何将对象的方法调用转换为访问、持久化及管理存储在 NoSQL 和关系型数据库中的数据的方案。

本文通过构建自行车借贷服务的教程示例来详细研究 JPA。此示例会使用 Spring Boot 框架、MongoDB 数据库(已经不开源)和 Maven 包管理来构建一个大型应用程序,并且构建一个创建、读取、更新和删除(CRUD)层。这儿我选择 NetBeans 11 作为我的 IDE。

此教程仅从开源的角度来介绍 Java 持久化 API 的工作原理,不涉及其作为工具的使用说明。这全是关于编写应用程序模式的学习,但对于理解具体的软件实现也很益处。可以从我的 GitHub 仓库来获取相关代码。

Java: 不仅仅是“豆子”

Java 是一门面向对象的编程语言,自 1996 年发布第一版 Java 开发工具(JDK)起,已经变化了很多很多。要了解其各种发展及其虚拟机本身就是一堂历史课。简而言之,和 Linux 内核很相似,自发布以来,该语言已经向多个方向分支发展。有对社区免费的标准版本、有针对企业的企业版本及由多家供应商提供的开源替代品。主要版本每六个月发布一次,其功能往往差异很大,所以确认选用版本前得先做些研究。

总而言之,Java 的历史很悠久。本教程重点介绍 Java 11 的开源实现 JDK 11。因其是仍然有效的长期支持版本之一。

  • Spring Boot 是由 Pivotal 公司开发的大型 Spring 框架的一个模块。Spring 是 Java 开发中一个非常流行的框架。它支持各种框架和配置,也为 WEB 应用程序及安全提供了保障。Spring Boot 为快速构建各种类型的 Java 项目提供了基本的配置。本教程使用 Spring Boot 来快速编写控制台应用程序并针对数据库编写测试用例。
  • Maven 是由 Apache 开发的项目/包管理工具。Maven 通过 POM.xml 文件来管理包及其依赖项。如果你使用过 NPM 的话,可能会非常熟悉包管理器的功能。此外 Maven 也用来进行项目构建及生成功能报告。
  • Lombok 是一个库,它通过在对象文件里面添加注解来自动创建 getters/setters 方法。像 C# 这些语言已经实现了此功能,Lombok 只是把此功能引入 Java 语言而已。
  • NetBeans 是一款很流行的开源 IDE,专门用于 Java 开发。它的许多工具都随着 Java SE 和 EE 的版本更新而更新。

我们会用这组工具为一个虚构自行车商店创建一个简单的应用程序。会实现对 CustomerBike 对象集合的的插入操作。

酿造完美

导航到 Spring Initializr 页面。该网站可以生成基于 Spring Boot 和其依赖项的基本项目。选择以下选项:

  1. 项目: Maven 工程
  2. 语言: Java
  3. Spring Boot: 2.1.8(或最稳定版本)
  4. 项目元数据: 无论你使用什么名字,其命名约定都是像 com.stephb 这样的。

    • 你可以保留 Artifact 名字为 “Demo”。
  5. 依赖项: 添加:

    • Spring Data MongoDB
    • Lombok

点击 下载,然后用你的 IDE(例如 NetBeans) 打开此新项目。

模型层概要

在项目里面, 模型 model 代表从数据库里取出的信息的具体对象。我们关注两个对象:CustomerBike。首先,在 src 目录创建 dto 目录;然后,创建两个名为 Customer.javaBike.java 的 Java 类对象文件。其结构如下示:

package com.stephb.JavaMongo.dto;

import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;

/**
 *
 * @author stephon
 */
@Getter @Setter
public class Customer {

        private @Id String id;
        private String emailAddress;
        private String firstName;
        private String lastName;
        private String address;
        
}

Customer.Java

package com.stephb.JavaMongo.dto;

import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;

/**
 *
 * @author stephon
 */
@Getter @Setter
public class Bike {
        private @Id String id;
        private String modelNumber;
        private String color;
        private String description;

        @Override
        public String toString() {
                return "This bike model is " + this.modelNumber + " is the color " + this.color + " and is " + description;
        }
}

Bike.java

如你所见,对象中使用 Lombok 注解来为定义的 属性 properties / 特性 attributes 生成 getters/setters 方法。如果你不想对该类的所有特性都生成 getters/setters 方法,可以在属性上专门定义这些注解。这两个类会变成容器,里面携带有数据,无论在何处想显示信息都可以使用。

配置数据库

我使用 Mongo Docker 容器来进行此次测试。如果你的系统上已经安装了 MongoDB,则不必运行 Docker 实例。你也可以登录其官网,选择系统信息,然后按照安装说明来安装 MongoDB。

安装后,就可以使用命令行、GUI(例如 MongoDB Compass)或用于连接数据源的 IDE 驱动程序来与新的 MongoDB 服务器进行交互。到目前为止,可以开始定义数据层了,用来拉取、转换和持久化数据。需要设置数据库访问属性,请导航到程序中的 applications.properties 文件,然后添加如下内容:

spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=BikeStore

定义数据访问对象/数据访问层

数据访问层 data access layer (DAL)中的 数据访问对象 data access objects (DAO)定义了与数据库中的数据的交互过程。令人惊叹的就是在使用 spring-boot-starter 后,查询数据库的大部分工作已经完成。

让我们从 Customer DAO 开始。在 src 下的新目录 dao 中创建一个接口文件,然后再创建一个名为 CustomerRepository.java 的 Java 类文件,其内容如下示:

package com.stephb.JavaMongo.dao;

import com.stephb.JavaMongo.dto.Customer;
import java.util.List;
import org.springframework.data.mongodb.repository.MongoRepository;

/**
 *
 * @author stephon
 */
public interface CustomerRepository extends MongoRepository<Customer, String>{
        @Override
        public List<Customer> findAll();
        public List<Customer> findByFirstName(String firstName);
        public List<Customer> findByLastName(String lastName);
}

这个类是一个接口,扩展或继承于 MongoRepository 类,而 MongoRepository 类依赖于 DTO (Customer.java)和一个字符串,它们用来实现自定义函数查询功能。因为你已继承自此类,所以你可以访问许多方法函数,这些函数允许持久化和查询对象,而无需实现或引用自己定义的方法函数。例如,在实例化 CustomerRepository 对象后,你就可以直接使用 Save 函数。如果你需要扩展更多的功能,也可以重写这些函数。我创建了一些自定义查询来搜索我的集合,这些集合对象是我自定义的元素。

Bike 对象也有一个存储源负责与数据库交互。与 CustomerRepository 的实现非常类似。其实现如下所示:

package com.stephb.JavaMongo.dao;

import com.stephb.JavaMongo.dto.Bike;
import java.util.List;
import org.springframework.data.mongodb.repository.MongoRepository;

/**
 *
 * @author stephon
 */
public interface BikeRepository extends MongoRepository<Bike,String>{
        public Bike findByModelNumber(String modelNumber);
        @Override
        public List<Bike> findAll();
        public List<Bike> findByColor(String color);
}

运行程序

现在,你已经有了一种结构化数据的方式,可以对数据进行提取、转换和持久化,然后运行这个程序。

找到 Application.java 文件(有可能不是此名称,具体取决于你的应用程序名称,但都会包含有 “application” )。在定义此类的地方,在后面加上 implements CommandLineRunner。这将允许你实现 run 方法来创建命令行应用程序。重写 CommandLineRunner 接口提供的 run 方法,并包含如下内容用来测试 BikeRepository

package com.stephb.JavaMongo;

import com.stephb.JavaMongo.dao.BikeRepository;
import com.stephb.JavaMongo.dao.CustomerRepository;
import com.stephb.JavaMongo.dto.Bike;
import java.util.Scanner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class JavaMongoApplication implements CommandLineRunner {
                @Autowired
                private BikeRepository bikeRepo;
                private CustomerRepository custRepo;
                
    public static void main(String[] args) {
                        SpringApplication.run(JavaMongoApplication.class, args);
    }
        @Override
        public void run(String... args) throws Exception {
                Scanner scan = new Scanner(System.in);
                String response = "";
                boolean running = true;
                while(running){
                        System.out.println("What would you like to create? \n C: The Customer \n B: Bike? \n X:Close");
                        response = scan.nextLine();
                        if ("B".equals(response.toUpperCase())) {
                                String[] bikeInformation = new String[3];
                                System.out.println("Enter the information for the Bike");
                                System.out.println("Model Number");
                                bikeInformation[0] = scan.nextLine();
                                System.out.println("Color");
                                bikeInformation[1] = scan.nextLine();
                                System.out.println("Description");
                                bikeInformation[2] = scan.nextLine();

                                Bike bike = new Bike();
                                bike.setModelNumber(bikeInformation[0]);
                                bike.setColor(bikeInformation[1]);
                                bike.setDescription(bikeInformation[2]);

                                bike = bikeRepo.save(bike);
                                System.out.println(bike.toString());


                        } else if ("X".equals(response.toUpperCase())) {
                                System.out.println("Bye");
                                running = false;
                        } else {
                                System.out.println("Sorry nothing else works right now!");
                        }
                }
                
        }
}

其中的 @Autowired 注解会自动依赖注入 BikeRepositoryCustomerRepository Bean。我们将使用这些类来从数据库持久化和采集数据。

已经好了。你已经创建了一个命令行应用程序。该应用程序连接到数据库,并且能够以最少的代码执行 CRUD 操作

结论

从诸如对象和类之类的编程语言概念转换为用于在数据库中存储、检索或更改数据的调用对于构建应用程序至关重要。Java 持久化 API(JPA)正是为 Java 开发人员解决这一难题的重要工具。你正在使用 Java 操纵哪些数据库呢?请在评论中分享。


via: https://opensource.com/article/19/10/using-java-persistence-api

作者:Stephon Brown 选题:lujun9972 译者:runningwater 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出