Merge remote-tracking branch 'LCTT/master'

This commit is contained in:
Xingyu Wang 2020-01-03 16:56:04 +08:00
commit 6ae54a1267
9 changed files with 1412 additions and 208 deletions

View File

@ -1,8 +1,8 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-11744-1.html)
[#]: subject: (Pop!_OS vs Ubuntu: Which One is Better?)
[#]: via: (https://itsfoss.com/pop-os-vs-ubuntu/)
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
@ -12,7 +12,7 @@ Pop!_OS 与 Ubuntu哪个更棒
好吧,你可能会发现从[最佳 Linux 发行版][1]列表中选择一个发行版很容易,但是,将两个类似的 Linux 发行版进行比较通常会令人困惑,就像 Pop!_OS 与 Ubuntu 一样。
有趣的是Pop!\_OS 基于 [Ubuntu][2]。那么Pop!\_OS 和 Ubuntu 之间有什么区别呢?为什么要从中选择一个呢?
有趣的是Pop!\_OS 基于 [Ubuntu][2]。那么Pop!\_OS 和 Ubuntu 之间有什么区别呢?为什么要从中选择一个呢?
在本文中,我将比较 Pop!_OS 和 Ubuntu两者都是我的最爱
@ -24,7 +24,7 @@ Pop!_OS 与 Ubuntu哪个更棒
发现相似之处可帮助你区分其他差异之处。因此,让我们从一些明显的相似之处开始。
就像我提到的Pop!\_OS 是基于 Ubuntu 之上的 Linux 发行版。因此,当你使用 Pop!_OS 时,你将获得使用 Ubuntu 的所有好处(从技术上说,其核心是一样的)。
就像我提到的Pop!\_OS 是基于 Ubuntu 之上的 Linux 发行版。因此,当你使用 Pop!\_OS 时,你将获得使用 Ubuntu 的所有好处(从技术上说,其核心是一样的)。
它们都默认带有 [GNOME 桌面环境][4]因此它们具有相似的用户界面UI
@ -42,7 +42,7 @@ Pop!_OS 与 Ubuntu哪个更棒
除了外观之外,[Ubuntu 还通过添加程序坞和其他一些小花巧来定制了 GNOME 的体验][6]。如果你喜欢定制的 GNOME 体验,可能会发现它更好。
但是,如果你更喜欢纯粹的 GNOME 体验,默认情况下 Pop!_OS 会为你提供
但是,如果你更喜欢纯粹的 GNOME 体验,Pop!_OS 默认情况下为你提供的就是这样
在你亲自尝试之前我无法说服你。但是Pop!_OS 中的总体配色方案、图标和主题可以说是令人愉悦的高级用户体验。
@ -60,7 +60,7 @@ Ubuntu 非常重视 Snap 软件包。这增加了它提供的应用程序的数
我为什么要说这个呢?
因为 Pop!_OS 具有其[自己的官方 PPA][8],并在默认情况下已启用。你会在此处找到一些有用的应用程序,例如 Android Studio、TensorFlow。无需下载 Android Studio 的 1GB 大的 Snap 程序包。只需使用 [apt-get install][9]就可以了。
因为 Pop!_OS 具有其[自己的官方 PPA][8],并已默认启用。你会在此处找到一些有用的应用程序,例如 Android Studio、TensorFlow。无需下载 Android Studio 的 1GB 大的 Snap 程序包。只需使用 [apt-get install][9]就可以了。
#### 预装应用
@ -76,13 +76,13 @@ Ubuntu 非常重视 Snap 软件包。这增加了它提供的应用程序的数
![][11]
对于熟悉 Snap 程序包的用户来说Ubuntu 的软件中心是比 Pop!_OS 商店更好的解决方案,因为你可以在软件中心中列出快照程序包。
对于熟悉 Snap 程序包的用户来说Ubuntu 的软件中心是比 Pop!_OS 商店更好的解决方案,因为你可以在软件中心中列出 Snap 程序包。
你无法在软件中心中过滤快照包,但是当你在软件中心中发现一个 Snap 包(查看应用程序来源的详细信息为 Snap store ”/“Snapcraft”时安装它就更容易了。
你无法在软件中心中过滤 Snap 软件包,但是当你在软件中心中发现一个 Snap 软件包(查看应用程序来源的详细信息为 Snap store”/“Snapcraft”时安装它就更容易了。
如果你感到困惑Pop!\_OS 也确实支持快照包。但是,你不会在 Pop!_OS 商店中找到它们,这是唯一的区别。
可能你会感到困惑Pop!\_OS 也确实支持 Snap 软件包。但是,你不会在 Pop!\_OS 商店中找到它们,这是唯一的区别。
如果不确定什么是 Snap 软件包及其功能,可以查看我们的文章[在 Linux 上安装 Snap 应用][12]。
如果不确定什么是 Snap 软件包及其功能,可以查看我们的文章[在 Linux 上安装 Snap 应用][12]
#### 单独的 NVIDIA/AMD ISO 文件
@ -96,9 +96,9 @@ Ubuntu 非常重视 Snap 软件包。这增加了它提供的应用程序的数
#### 可靠性与问题
毫无疑问,这两个[发行版都适合初学者][14]并且相当可靠。如果你想要更好的可靠性和更少的问题则可能希望一直用长期支持LTS版本。
毫无疑问,这两个[发行版都适合初学者][14],并且相当可靠。如果你想要更好的可靠性和更少的问题,则可能希望一直使用长期支持LTS版本。
当出现新版本的 Ubuntu 时Pop!_OS 将在其上开发,并有可能解决用户在 Ubuntu 原始发行版上遇到的问题,然后再进行新的升级。这给们带来了一点优势,但这没什么实质性的不同,因为这些修复最终都可以运用于 Ubuntu。
当出现新版本的 Ubuntu 时Pop!_OS 将在其上开发,并有可能解决用户在 Ubuntu 原始发行版上遇到的问题,然后再进行新的升级。这给们带来了一点优势,但这没什么实质性的不同,因为这些修复最终都可以运用于 Ubuntu。
#### 性能
@ -110,7 +110,7 @@ Ubuntu 非常重视 Snap 软件包。这增加了它提供的应用程序的数
当然,你可以手动进行一些优化调整以满足要求——无论它们中的哪个不满足你的硬件配置。
但是,如果你想使用 System76 笔记本电脑,那么 Pop!\_OS 将可以证明自己是 [Linux 领域的苹果][15],因为 Pop!_OS 是针对其硬件量身定制的,与 Ubuntu 有所不同。
但是,如果你想使用 System76 笔记本电脑,那么 Pop!\_OS 将可以证明自己是 [Linux 领域的苹果][15],因为 Pop!\_OS 是针对其硬件量身定制的,与 Ubuntu 有所不同。
#### 硬件兼容性
@ -131,7 +131,7 @@ via: https://itsfoss.com/pop-os-vs-ubuntu/
作者:[Ankush Das][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/) 荣誉推出

View File

@ -0,0 +1,92 @@
[#]: collector: "lujun9972"
[#]: translator: "nacyro"
[#]: reviewer: "wxy"
[#]: publisher: "wxy"
[#]: url: "https://linux.cn/article-11742-1.html"
[#]: subject: "10 articles to enhance your security aptitude"
[#]: via: "https://opensource.com/article/19/12/security-resources"
[#]: author: "Ben Cotton https://opensource.com/users/bcotton"
10 篇强化你的安全能力的文章
======
> 无论你是新手还是想要增加技能,这十篇安全文章中都有适合你的内容。
![](https://img.linux.net.cn/data/attachment/album/202001/03/004344rco51cnc153ns1zz.jpg)
如果安全是一个过程(确实如此),那么理所当然的,不同的项目(及其贡献者)的情况各有不同。有些应用程序经历了多年的安全测试,由在信息安全领域工作了几十年的人员所设计。而另外一些则是由开发人员在他们的第一个开源项目中开发的全新项目。毫不奇怪,这十大安全文章囊括了代表这一范围的经验。我们有介绍基本安全实践的文章,也有深入探讨更高级主题的文章。
无论你是新手还是想要增加你在传奇职业生涯中获得的技能2019 年十大安全文章中都有适合你的内容。
### 《安全强化你的 Linux 服务器的七个步骤》
安全如舍地基不牢房屋不稳。Patrick H. Mullins 的杰作《[安全强化你的 Linux 服务器的七个步骤][2]》让你从 Linux 服务器的基本安全步骤开始。即使你有很多管理服务器的经验,本文也提供了一个很好的清单以确保你掌握了基础知识。在此基础上,你可以开始添加额外的安全层。
### 《使用防火墙让你的 Linux 更加强大》
七步捍卫你的 Linux 服务器中的一步即是启用防火墙。但什么**是**防火墙它是如何工作的呢 Seth Kenlon 在《[使用防火墙让你的 Linux 更加强大][3]》一文中回答了这些问题,然后详细描述了为了更好的安全性应如何配置你的防火墙。使用 firewalld 与 Network Manager你可以为不同的网络设置不同的防火墙配置。例如这允许你在家庭网络上进行信任配置并在你最喜欢的咖啡店的 WiFi 网络上进行更多疑的配置。
### 《用集中日志减少安全风险》
保护系统安全,只有开始,没有结束:安全是一个过程而不是状态。**保持**系统安全工作的一部分即是密切关注所发生的事情。集中化日志是实现这一点的一种方法,尤其是在管理多系统时。在《[减少集中日志的安全风险][4]》中 Hannah Suarez 分享了要如何开始(她这篇文章基于她在 FOSDEM'19 [自由及开源软件开发者欧洲会议] 中的闪电演讲)。
### 《在 SSH 中使用 GPG 密钥》
大多数人都会为 SSH 的密钥认证使用 SSH 密钥。为什么不呢?毕竟 SSH 就在名字里。从安全的角度来看这些方法非常好。但若想简化某些形式的密钥分发与备份还有另一种方法Brian Exelbierd 的三部曲系列介绍了《[如何启用使用 GPG 子钥的 SSH 访问][5]》、《[如何导入现有 SSH 密钥][6]》、《[如何将备份量减少到单个密钥文件][7]》
### 《使用 Seahorse 图形化管理 SSH 密钥》
并不是所有人都喜欢用 GPG 作为 SSH 密钥但这并不意味着你在密钥管理上会不顺利。Seahorse 是一个在 GNOME 桌面中用于管理 SSH 密钥及其他身份验证方法的图形化工具。Alan Formy-Duval 的《[使用 Seahorse 图形化管理 SSH 密钥》对新手用户特别有帮助。
### 《安全扫描你的 DevOps 流程》
如今到处都是容器。但它们容纳着什么了解容器满足你的安全策略是保持安全性的重要部分。幸运的是你可以使用开源工具来帮助自动化合规检查。Jessica Cherry原名: Repka的《[安全扫描你的 DevOps 流程][9]》是一个循序渐进的教程,向你展示了如何使用 Jenkins 构建系统和 Anchore 检查服务为容器镜像和注册库创建扫描流程。
### 《4 种开源云安全工具》
云服务的一大优点是你的数据可以从任何地方访问。云服务的一个缺点是你的数据可以从任何地方访问。如果你使用的是 “-as-a-Service”LCTT 译注: 某某即服务,如 IaaS、PaaS、Saa产品那么你需要确保它们是经过安全配置的。Anderson Silva、Alison Naylor、Travis McPeak 和 Rich Monk 联合推出《[4 种开源云安全工具][10]》以帮助在使用 GitHub 和 AWS 时提高安全性。如果你正在寻找被不小心提交的机密信息,或尝试从一开始就阻止这些机密信息被提交,这篇文章提供了工具。
### 《如何使用 OpenSSL哈希、数字签名等》
许多信息安全是基于数学的:特别是用于加密数据和验证用户或文件内容的加密函数。在《[开始使用 OpenSSL密码学基础][11]》中进行介绍后Marty Kalin 深入讨论了《[如何使用 OpenSSL哈希、数字签名等][12]》的细节,解释了如何使用 OpenSSL 实用程序来探索这些常用但不常被理解的概念。
### 《使用树莓派和 Kali Linux 学习计算机安全》
廉价硬件与开源软件构成了一个很好的组合,特别是对于那些希望边做边学的人来说。在《[使用树莓派和 Kali Linux 学习计算机安全][13]》这篇文章中Anderson Silva 介绍了面向安全的 Kali Linux 发行版。这是一篇短文,但它满是关于文档和安全相关项目的有用的链接,你可以在自己的树莓派上使用它们。
### 《量子计算会打破现有的安全体系吗?》
这篇文章的余下部分是浪费吗?量子计算会让我们对安全的所知变得过时吗?好消息是:回答是否定的,但是量子计算仍然可以在更广泛的范围内对安全和计算世界产生深远的影响。在《[量子计算会打破现有的安全体系吗?][14]》一文中Mike Bursell 剖析了它好坏两方面的影响,当然,量子计算可能会让加密的破解变得更容易,但如果坏人一开始就无法获得你的数据,那也没有关系。
### 展望 2020
安全永远是重要的,(正如那篇量子计算文章所建议的)未来几年将是该领域的一个有趣时期。在 2020 年,我们的文章将着眼于开源安全的前沿,并帮助向不断增长的开源社区解释基础知识。如果你有一个你想要我们报导的主题,请在评论中分享它,或者更进一步 —— 如果你想写一篇文章,就写给我们吧。
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/12/security-resources
作者:[Ben Cotton][a]
选题:[lujun9972][b]
译者:[nacyro](https://github.com/nacyro)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/bcotton
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003601_05_mech_osyearbook2016_security_cc.png?itok=3V07Lpko "A secure lock."
[2]: https://linux.cn/article-11444-1.html
[3]: https://linux.cn/article-11093-1.html
[4]: https://opensource.com/article/19/2/reducing-security-risks-centralized-logging
[5]: https://opensource.com/article/19/4/gpg-subkeys-ssh
[6]: https://opensource.com/article/19/4/gpg-subkeys-ssh-multiples
[7]: https://opensource.com/article/19/4/gpg-subkeys-ssh-manage
[8]: https://opensource.com/article/19/4/ssh-keys-seahorse
[9]: https://opensource.com/article/19/7/security-scanning-your-devops-pipeline
[10]: https://linux.cn/article-11432-1.html
[11]: https://opensource.com/article/19/6/cryptography-basics-openssl-part-1
[12]: https://opensource.com/article/19/6/cryptography-basics-openssl-part-2
[13]: https://opensource.com/article/19/3/computer-security-raspberry-pi
[14]: https://linux.cn/article-10566-1.html
[15]: https://opensource.com/how-submit-article

View File

@ -1,102 +0,0 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Fixing “VLC is Unable to Open the MRL” Error [Quick Tip])
[#]: via: (https://itsfoss.com/vlc-is-unable-to-open-the-mrl/)
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
Fixing “VLC is Unable to Open the MRL” Error [Quick Tip]
======
One of the [VLC tips][1] is to play YouTube and other online videos with [VLC][2]. This could help you [watch online videos with subtitles][3].
But things may not always be simple because at times youll encounter this error when trying to open YouTube video with VLC:
**Your input cant be opened:
VLC is unable to open the MRL <https://youtubeurl.com>. Check the log for details.**
![VLC error while playing YouTube videos][4]
The thing here is that Google doesnt want you to use any third party application for watching YouTube because then they cannot collect data properly.
So, they keep changing stuff from their side to make it harder for third party devs to work with YouTube.
Take [youtube-dl][5] for example. Youll notice that you cannot [download YouTube videos][6] with it all of a sudden and the simplest solution is to have the latest version of youtube-dl installed.
Same goes for VLC. If you [install the latest VLC in Ubuntu][7] or whichever operating system you are using, you probably wont see this error.
### Fixing “VLC is unable to open the MRL” error
Let me show you the steps to fix this problem for YouTube at least.
Go to this page and use Ctrl+S to save the file from the official GitHub repository of VLC media player:
[Download youtube.lua file][8]
Now, what you need to do is to replace the youtube.luac (mind the c in luac) in lib/vlc/lua/playlist directory with this downloaded file.
#### Steps for Linux
If you are using Linux, open the terminal and use the [locate command][9] to find the exact location of youtube.luac file:
```
locate youtube.luac
```
When you get the path of the file, you just replace that file with your downloaded file. I trust you to handle this simple task.
For me, it showed the path of the file here:
```
[email protected]:~$ locate youtube.lua
/usr/lib/x86_64-linux-gnu/vlc/lua/playlist/youtube.luac
```
So all I did was to move the downloaded file to this location and replace the content of the file:
```
sudo cp ~/Downloads/youtube.lua /usr/lib/x86_64-linux-gnu/vlc/lua/playlist/youtube.luac
```
You should be able to play the YouTube videos in VLC now.
#### Steps for Windows
If you are using Windows, you should follow these steps:
* Rename the downloaded youtube.lua file to youtube.luac
* Now copy this file and paste it to C:\Program Files (x86)\VideoLAN\VLC\lua\playlist\
Thats it.
If you have trouble with Dailymotion or other video streaming websites, you can download their respective lua files from the VLC repository [here][10] and replace the existing one in your VLC install.
I hope this quick tip fixed the problem with VLC unable to play YouTube videos for you.
--------------------------------------------------------------------------------
via: https://itsfoss.com/vlc-is-unable-to-open-the-mrl/
作者:[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/simple-vlc-tips/
[2]: https://www.videolan.org/index.html
[3]: https://itsfoss.com/penguin-subtitle-player/
[4]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/12/vlc_error_input_cant_be_played.png?ssl=1
[5]: https://itsfoss.com/download-youtube-linux/
[6]: https://itsfoss.com/download-youtube-videos-ubuntu/
[7]: https://itsfoss.com/install-latest-vlc/
[8]: https://raw.githubusercontent.com/videolan/vlc/master/share/lua/playlist/youtube.lua
[9]: https://linuxhandbook.com/locate-command/
[10]: https://github.com/videolan/vlc/tree/master/share/lua/playlist

View File

@ -0,0 +1,70 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (10 open source software alternatives for the new year)
[#]: via: (https://opensource.com/article/20/1/open-source-alternatives)
[#]: author: (Scott Nesbitt https://opensource.com/users/scottnesbitt)
10 open source software alternatives for the new year
======
Open source software can help you become better organized, more
productive, more secure, and even healthier.
![Multi-colored and directional network computer cables][1]
Open source isn't just for techies. On your desktop (regardless of your operating system), on your phone, and in your business, open source software can help you become better organized, more productive, more secure, and healthier. Best of all, you don't need to worry about the shackles of proprietary licenses.
Throughout 2019, Opensource.com's team of [Correspondents][2] and community of writers have highlighted top-notch open source alternatives to proprietary software. Take a quick look at the best 10 of those articles.
In _[Intro to Corteza, an open source alternative to Salesforce][3]_, Dennis Arh introduces us to Corteza, a powerful and flexible customer relationship management (CRM) system. Dennis outlines what Corteza has to offer, then walks us through how to install and configure the system. While Corteza might not pack all the features of the bigger closed source CRM systems, it's more than enough for the majority of users.
Opensource.com Correspondent Chris Hermansen whips up an overview of a half-dozen instant messaging apps for mobile devices in _[Choosing an open messenger client: Alternatives to WhatsApp][4]_. While each of the six apps has its strengths, Chris recommends Signal for "its open-by-design approach, its serious and ongoing privacy and security stance, and having a Signal app on our GNOME (and Windows) desktops."
In _[5 social media alternatives to protect your privacy][5]_, privacy advocate Dan Arel walks through several open source replacements for Twitter, Facebook, Instagram, WhatsApp, and Facebook Messenger. Dan also shares how he cut his ties with those privacy-crushing services without losing touch with the people who matter. His approach might work for you, too.
You don't need an expensive application like Adobe Acrobat to work with PDF files on the Linux desktop, as I show in _[Two graphical tools for manipulating PDFs on the Linux desktop][6]_. These tools are simple, but they pack a lot of punch and take care of most of your PDF manipulation needs.
In _[How to create an automated calendar with Google Apps Script with open source on top][7]_, Correspondent Dan Barker explores how to manage conference submissions by stitching together a Google Sheet with Google Calendar using a script he wrote. OK, the services Dan's script interacts with aren't open source, but you can grab that script from [Dan's GitLab repository][8] and modify it to your heart's content.
In _[4 open source apps for plant-based diets][9]_, Correspondent Joshua Allen Holm uncovers some mobile apps that can help you plan meatless meals, shop more effectively for the ingredients for those meals, and find vegan and vegetarian restaurants nearby. As someone who's shifting to a more plant-based diet, I can see myself using a couple of these apps in the near future. And that they're available on [F-Droid][10] is a bonus.
I dive into a very useful spreadsheet editor that's built for collaboration in _[Get going with EtherCalc, a web-based alternative to Google Sheets][11]_. If you're of a technical bent, you can run your own instance; otherwise, you can use one of several hosted editions. EtherCalc does take a bit of getting used to, but if your needs are simple, you'll find (as I did) that it's a flexible tool.
Opensource.com's Seth Kenlon examines _[CBZ and DjVu: Open source alternatives to PDFs][12]_. This pair of digital archive formats can do everything PDF can do but are easier to manipulate. Seth also shows how to use command-line tools to create archives in the CBZ and DjVu formats and, with DjVu files, offers some advanced tips and tricks.
I explain how a good open source application can exist quite nicely in a proprietary environment in _[Organize your information on the Mac desktop with nvALT][13]_. In this article, I discuss how to how to manage notes and more with this _very_ useful tool. What makes nvALT all the more attractive to me is that [plain text][14] is at its core, so it's a solid fit for my workflow whenever I'm working in MacOS.
In _[Getting started with Pimcore: An open source alternative for product information management][15]_, Dietmar Rietsch introduces a tool for businesses of all sizes to manage, mold, and share data about their products. In the past, I worked for a company or two that specialized in this type of software. It's great to see an open source alternative that's as flexible, polished, and easy to use as its closed source cousins.
These articles give you a taste of the open source alternatives to proprietary software that are out there. Are there any substitutes for proprietary software that you think we should cover in the coming months? Feel free to leave a comment or, better yet, [submit an article proposal][16].
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/1/open-source-alternatives
作者:[Scott Nesbitt][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/scottnesbitt
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/connections_wires_sysadmin_cable.png?itok=d5WqHmnJ (Multi-colored and directional network computer cables)
[2]: https://opensource.com/correspondent-program
[3]: https://opensource.com/article/19/8/corteza-open-source-alternative-salesforce
[4]: https://opensource.com/article/19/3/open-messenger-client
[5]: https://opensource.com/article/19/1/open-source-social-media-alternatives
[6]: https://opensource.com/article/19/2/manipulating-pdfs-linux
[7]: https://opensource.com/article/19/1/automate-calendar
[8]: https://gitlab.com/barkerd427/conference-scripts
[9]: https://opensource.com/article/19/4/apps-plant-based-diets
[10]: https://f-droid.org/
[11]: https://opensource.com/article/19/7/get-going-ethercalc
[12]: https://opensource.com/article/19/3/comic-book-archive-djvu
[13]: https://opensource.com/article/19/1/nvalt
[14]: https://plaintextproject.online/
[15]: https://opensource.com/article/19/11/pimcore-alternative-product-information-management
[16]: https://opensource.com/how-submit-article

View File

@ -0,0 +1,496 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Data streaming and functional programming in Java)
[#]: via: (https://opensource.com/article/20/1/javastream)
[#]: author: (Marty Kalin https://opensource.com/users/mkalindepauledu)
Data streaming and functional programming in Java
======
Learn how to use the stream API and functional programming constructs in
Java 8.
![computer screen ][1]
When Java SE 8 (aka core Java 8) was introduced in 2014, it introduced changes that fundamentally impact programming in it. The changes have two closely linked parts: the stream API and the functional programming constructs. This article uses code examples, from the basics through advanced features, to introduce each part and illustrate the interplay between them.
### The basics
The stream API is a concise and high-level way to iterate over the elements in a data sequence. The packages **java.util.stream** and **java.util.function** house the new libraries for the stream API and related functional programming constructs. Of course, a code example is worth a thousand words.
The code segment below populates a **List** with about 2,000 random integer values:
```
[Random][2] rand = new [Random][2]();
List&lt;Integer&gt; list = new ArrayList&lt;Integer&gt;();           // empty list
for (int i = 0; i &lt; 2048; i++) list.add(rand.nextInt()); // populate it
```
Another **for** loop could be used to iterate over the populated list to collect the even values into another list. The stream API is a cleaner way to do the same:
```
[List][3] &lt;Integer&gt; evens = list
   .stream()                      // streamify the list
   .filter(n -&gt; (n &amp; 0x1) == 0)   // filter out odd values
   .collect(Collectors.toList()); // collect even values
```
The example has three functions from the stream API:
* The **stream** function can turn a **Collection** into a stream, which is a conveyor belt of values accessible one at a time. The streamification is lazy (and therefore efficient) in that the values are produced as needed rather than all at once.
* The **filter** function determines which streamed values, if any, get through to the next stage in the processing pipeline, the **collect** stage. The **filter** function is _higher-order_ in that its argument is a function—in this example, a lambda, which is an unnamed function and at the center of Java's new functional programming constructs.
The lambda syntax departs radically from traditional Java:
```
`n -> (n & 0x1) == 0`
```
The arrow (a minus sign followed immediately by a greater-than sign) separates the argument list on the left from the function's body on the right. The argument **n** is not explicitly typed, although it could be; in any case, the compiler figures out that **n** is an **Integer**. If there were multiple arguments, these would be enclosed in parentheses and separated by commas.
The body, in this example, checks whether an integer's lowest-order (rightmost) bit is a zero, which indicates an even value. A filter should return a boolean value. There is no explicit **return** in the function's body, although there could be. If the body has no explicit **return**, then the body's last expression is the returned value. In this example, written in the spirit of lambda programming, the body consists of the single, simple boolean expression **(n &amp; 0x1) == 0**.
* The **collect** function gathers the even values into a list whose reference is **evens**. As an example below illustrates, the **collect** function is thread-safe and, therefore, would work correctly even if the filtering operation was shared among multiple threads.
### Convenience functions and easy multi-threading
In a production environment, a data stream might have a file or a network connection as its source. For learning the stream API, Java provides types such as **IntStream**, which can generate streams with elements of various types. Here is an **IntStream** example:
```
IntStream                         // integer stream
   .range(1, 2048)                // generate a stream of ints in this range
   .parallel()                    // partition the data for multiple threads
   .filter(i -&gt; ((i &amp; 0x1) &gt; 0))  // odd parity? pass through only odds
   .forEach([System][4].out::println); // print each
```
The **IntStream** type includes a **range** function that generates a stream of integer values within a specified range, in this case, from 1 through 2,048, with increments of 1. The **parallel** function automatically partitions the work to be done among multiple threads, each of which does the filtering and printing. (The number of threads typically matches the number of CPUs on the host system.) The argument to the **forEach** function is a _method reference_, in this case, a reference to the **println** method encapsulated in **System.out**, which is of type **PrintStream**. The syntax for method and constructor references will be discussed shortly.
Because of the multi-threading, the integer values are printed in an arbitrary order overall but in sequence within a given thread. For example, if thread T1 prints 409 and 411, then T1 does so in the order 409411, but some other thread might print 2,045 beforehand. The threads behind the **parallel** call execute concurrently, and the order of their output is therefore indeterminate.
### The map/reduce pattern
The _map/reduce_ pattern has become popular in processing large datasets. A map/reduce macro operation is built from two micro-operations. The data first are scattered (_mapped_) among various workers, and the separate results then are gathered together—perhaps as a single value, which would be the _reduction_. Reduction can take different forms, as the following examples illustrate.
Instances of the **Number** class below represent integer values with either **EVEN** or **ODD** parity:
```
public class [Number][5] {
    enum Parity { EVEN, ODD }
    private int value;
    public [Number][5](int n) { setValue(n); }
    public void setValue(int value) { this.value = value; }
    public int getValue() { return this.value; }
    public Parity getParity() {
        return ((value &amp; 0x1) == 0) ? Parity.EVEN : Parity.ODD;
    }
    public void dump() {
        [System][4].out.format("Value: %2d (parity: %s)\n", getValue(),
                          (getParity() == Parity.ODD ? "odd" : "even"));
    }
}
```
The following code illustrates map/reduce with a **Number** stream, thereby showing that the stream API can handle not only primitive types such as **int** and **float** but programmer-defined class types as well.
In the code segment below, a list of random integer values is streamified using the **parallelStream** rather than the **stream** function. The **parallelStream** variant, like the **parallel** function introduced earlier, does automatic multithreading.
```
final int howMany = 200;
[Random][2] r = new [Random][2]();
[Number][5][ ] nums = new [Number][5][howMany];
for (int i = 0; i &lt; howMany; i++) nums[i] = new [Number][5](r.nextInt(100));
List&lt;Number&gt; listOfNums = [Arrays][6].asList(nums);  // listify the array
[Integer][7] sum4All = listOfNums
   .parallelStream()           // automatic multi-threading
   .mapToInt([Number][5]::getValue) // method reference rather than lambda
   .sum();                     // reduce streamed values to a single value
[System][4].out.println("The sum of the randomly generated values is: " + sum4All);
```
The higher-order **mapToInt** function could take a lambda as an argument, but in this case, it takes a method reference instead, which is **Number::getValue**. The **getValue** method expects no arguments and returns its **int** value for a given **Number** instance. The syntax is uncomplicated: the class name **Number** followed by a double colon and the method's name. Recall the earlier **System.out::println** example, which has the double colon after the **static** field **out** in the **System** class.
The method reference **Number::getValue** could be replaced by the lambda below. The argument **n** is one of the **Number** instances in the stream:
```
`mapToInt(n -> n.getValue())`
```
In general, lambdas and method references are interchangeable: if a higher-order function such as **mapToInt** can take one form as an argument, then this function could take the other as well. The two functional programming constructs have the same purpose—to perform some customized operation on data passed in as arguments. Choosing between the two is often a matter of convenience. For example, a lambda can be written without an encapsulating class, whereas a method cannot. My habit is to use a lambda unless the appropriate encapsulated method is already at hand.
The **sum** function at the end of the current example does the reduction in a thread-safe manner by combining the partial sums from the **parallelStream** threads. However, the programmer is responsible for ensuring that, in the course of the multi-threading induced by the **parallelStream** call, the programmer's own function calls (in this case, to **getValue**) are thread-safe.
The last point deserves emphasis. Lambda syntax encourages the writing of _pure functions_, which are functions whose return values depend only on the arguments, if any, passed in; a pure function has no side effects such as updating a **static** field in a class. Pure functions are thereby thread-safe, and the stream API works best if the functional arguments passed to higher-order functions, such as **filter** and **map**, are pure functions.
For finer-grained control, there is another stream API function, named **reduce**, that could be used for summing the values in the **Number** stream:
```
[Integer][7] sum4AllHarder = listOfNums
   .parallelStream()                           // multi-threading
   .map([Number][5]::getValue)                      // value per Number
   .reduce(0, (sofar, next) -&gt; sofar + next);  // reduction to a sum
```
This version of the **reduce** function takes two arguments, the second of which is a function:
* The first argument (in this case, zero) is the _identity_ value, which serves as the initial value for the reduction operation and as the default value should the stream run dry during the reduction.
* The second argument is the _accumulator_, in this case, a lambda with two arguments: the first argument (**sofar**) is the running sum, and the second argument (**next**) is the next value from the stream. The running sum and next value then are added to update the accumulator. Keep in mind that both the **map** and the **reduce** functions now execute in a multi-threaded context because of the **parallelStream** call at the start.
In the examples so far, stream values are collected and then reduced, but, in general, the **Collectors** in the stream API can accumulate values without reducing them to a single value. The collection activity can produce arbitrarily rich data structures, as the next code segment illustrates. The example uses the same **listOfNums** as the preceding examples:
```
Map&lt;[Number][5].Parity, List&lt;Number&gt;&gt; numMap = listOfNums
   .parallelStream()
   .collect(Collectors.groupingBy([Number][5]::getParity));
List&lt;Number&gt; evens = numMap.get([Number][5].Parity.EVEN);
List&lt;Number&gt; odds = numMap.get([Number][5].Parity.ODD);
```
The **numMap** in the first line refers to a **Map** whose key is a **Number** parity (**ODD** or **EVEN**) and whose value is a **List** of **Number** instances with values having the designated parity. Once again, the processing is multi-threaded through the **parallelStream** call, and the **collect** call then assembles (in a thread-safe manner) the partial results into the single **Map** to which **numMap** refers. The **get** method then is called twice on the **numMap**, once to get the **evens** and a second time to get the **odds**.
The utility function **dumpList** again uses the higher-order **forEach** function from the stream API:
```
private void dumpList([String][8] msg, List&lt;Number&gt; list) {
   [System][4].out.println("\n" + msg);
   list.stream().forEach(n -&gt; n.dump()); // or: forEach(Number::dump)
}
```
Here is a slice of the program's output from a sample run:
```
The sum of the randomly generated values is: 3322
The sum again, using a different method:     3322
Evens:
Value: 72 (parity: even)
Value: 54 (parity: even)
...
Value: 92 (parity: even)
Odds:
Value: 35 (parity: odd)
Value: 37 (parity: odd)
...
Value: 41 (parity: odd)
```
### Functional constructs for code simplification
Functional constructs, such as method references and lambdas, fit nicely into the stream API. These constructs represent a major simplification of higher-order functions in Java. Even in the bad old days, Java technically supported higher-order functions through the **Method** and **Constructor** types, instances of which could be passed as arguments to other functions. These types were used—but rarely in production-grade Java precisely because of their complexity. Invoking a **Method**, for example, requires either an object reference (if the method is non-**static**) or at least a class identifier (if the method is **static**). The arguments for the invoked **Method** then are passed to it as **Object** instances, which may require explicit downcasting if polymorphism (another complexity!) is not in play. By contrast, lambdas and method references are easy to pass as arguments to other functions.
The new functional constructs have uses beyond the stream API, however. Consider a Java GUI program with a button for the user to push, for example, to get the current time. The event handler for the button push might be written as follows:
```
[JButton][9] updateCurrentTime = new [JButton][9]("Update current time");
updateCurrentTime.addActionListener(new [ActionListener][10]() {
   @Override
   public void actionPerformed([ActionEvent][11] e) {
      currentTime.setText(new [Date][12]().toString());
   }
});
```
This short code segment is a challenge to explain. Consider the second line in which the argument to the method **addActionListener** begins as follows:
```
`new ActionListener() {`
```
This seems wrong in that **ActionListener** is an **abstract** interface, and **abstract** types cannot be instantiated with a call to **new**. However, it turns out that something else entirely is being instantiated: an unnamed inner class that implements this interface. If the code above were encapsulated in a class named **OldJava**, then this unnamed inner class would be compiled as **OldJava$1.class**. The **actionPerformed** method is overridden in the unnamed inner class.
Now consider this refreshing change with the new functional constructs:
```
`updateCurrentTime.addActionListener(e -> currentTime.setText(new Date().toString()));`
```
The argument **e** in the lambda is an **ActionEvent** instance, and the lambda's body is a simple call to **setText** on the button.
### Functional interfaces and composition
The lambdas used so far have been written in place. For convenience, however, there can be references to lambdas just as there are to encapsulated methods. The following series of short examples illustrate this.
Consider this interface definition:
```
@FunctionalInterface // optional, usually omitted
interface BinaryIntOp {
    abstract int compute(int arg1, int arg2); // abstract could be dropped
}
```
The annotation **@FunctionalInterface** applies to any interface that declares a _single_ abstract method; in this case, **compute**. Several standard interfaces (e.g., the **Runnable** interface with its single declared method, **run**) fit the bill. In this example, **compute** is the declared method. The interface can be used as the target type in a reference declaration:
```
BinaryIntOp div = (arg1, arg2) -&gt; arg1 / arg2;
div.compute(12, 3); // 4
```
The package **java.util.function** provides various functional interfaces. Some examples follow.
The code segment below introduces the parameterized **Predicate** functional interface. In this example, the type **Predicate&lt;String&gt;** with parameter **String** can refer to either a lambda with a **String** argument or a **String** method such as **isEmpty**. In general, a _predicate_ is a function that returns a boolean value.
```
Predicate&lt;String&gt; pred = [String][8]::isEmpty; // predicate for a String method
[String][8][ ] strings = {"one", "two", "", "three", "four"};
[Arrays][6].asList(strings)
   .stream()
   .filter(pred)                  // filter out non-empty strings
   .forEach([System][4].out::println); // only the empty string is printed
```
The **isEmpty** predicate evaluates to **true** just in case a string's length is zero; hence, only the empty string makes it through to the **forEach** stage in the pipeline.
The next code segments illustrate how simple lambdas or method references can be composed into richer ones. Consider this series of assignments to references of the **IntUnaryOperator** type, which takes an integer argument and returns an integer value:
```
IntUnaryOperator doubled = n -&gt; n * 2;
IntUnaryOperator tripled = n -&gt; n * 3;
IntUnaryOperator squared = n -&gt; n * n;
```
**IntUnaryOperator** is a **FunctionalInterface** whose single declared method is **applyAsInt**. The three references **doubled**, **tripled**, and **squared** now can be used standalone or in various compositions:
```
int arg = 5;
doubled.applyAsInt(arg); // 10
tripled.applyAsInt(arg); // 15
squared.applyAsInt(arg); // 25
```
Here are some sample compositions:
```
int arg = 5;
doubled.compose(squared).applyAsInt(arg); // doubled-the-squared: 50
tripled.compose(doubled).applyAsInt(arg); // tripled-the-doubled: 30
doubled.andThen(squared).applyAsInt(arg); // doubled-andThen-squared: 100
squared.andThen(tripled).applyAsInt(arg); // squared-andThen-tripled: 75
```
Compositions could be done with in-place lambdas, but the references make the code cleaner.
### Constructor references
Constructor references are yet another of the functional programming constructs, but these references are useful in more subtle contexts than lambdas and method references. Once again, a code example seems the best way to clarify.
Consider this [POJO][13] class:
```
public class BedRocker { // resident of Bedrock
    private [String][8] name;
    public BedRocker([String][8] name) { this.name = name; }
    public [String][8] getName() { return this.name; }
    public void dump() { [System][4].out.println(getName()); }
}
```
The class has a single constructor, which requires a **String** argument. Given an array of names, the goal is to generate an array of **BedRocker** elements, one per name. Here is the code segment that uses functional constructs to do so:
```
[String][8][ ] names = {"Fred", "Wilma", "Peebles", "Dino", "Baby Puss"};
Stream&lt;BedRocker&gt; bedrockers = [Arrays][6].asList(names).stream().map(BedRocker::new);
BedRocker[ ] arrayBR = bedrockers.toArray(BedRocker[]::new);
[Arrays][6].asList(arrayBR).stream().forEach(BedRocker::dump);
```
At a high level, this code segment transforms names into **BedRocker** array elements. In detail, the code works as follows. The **Stream** interface (in the package **java.util.stream**) can be parameterized, in this case, to generate a stream of **BedRocker** items named **bedrockers**.
The **Arrays.asList** utility again is used to streamify an array, **names**, with each stream item then passed to the **map** function whose argument now is the constructor reference **BedRocker::new**. This constructor reference acts as an object factory by generating and initializing, on each call, a **BedRocker** instance. After the second line executes, the stream named **bedrockers** consists of five **BedRocker** items.
The example can be clarified further by focusing on the higher-order **map** function. In a typical case, a mapping transforms a value of one type (e.g., an **int**) into a different value of the _same_ type (e.g., an integer's successor):
```
`map(n -> n + 1) // map n to its successor`
```
In the **BedRocker** example, however, the transformation is more dramatic because a value of one type (a **String** representing a name) is mapped to a value of a _different_ type, in this case, a **BedRocker** instance with the string as its name. The transformation is done through a constructor call, which is enabled by the constructor reference:
```
`map(BedRocker::new) // map a String to a BedRocker`
```
The value passed to the constructor is one of the names in the **names** array.
The second line of this code example also illustrates the by-now-familiar transformation of an array first into a **List** and then into a **Stream**:
```
`Stream<BedRocker> bedrockers = Arrays.asList(names).stream().map(BedRocker::new);`
```
The third line goes the other way—the stream **bedrockers** is transformed into an array by invoking the **toArray** method with the _array_ constructor reference **BedRocker[]::new**:
```
`BedRocker[ ] arrayBR = bedrockers.toArray(BedRocker[]::new);`
```
This constructor reference does not create a single **BedRocker** instance, but rather an entire array of these: the constructor reference is now **BedRocker[]::new** rather than **BedRocker::new**. For confirmation, the **arrayBR** is transformed into a **List**, which again is streamified so that **forEach** can be used to print the **BedRocker** names:
```
Fred
Wilma
Peebles
Dino
Baby Puss
```
The example's subtle transformations of data structures are done with but few lines of code, underscoring the power of various higher-order functions that can take a lambda, a method reference, or a constructor reference as an argument
### Currying
To _curry_ a function is to reduce (typically by one) the number of explicit arguments required for whatever work the function does. (The term honors the logician Haskell Curry.) In general, functions are easier to call and are more robust if they have fewer arguments. (Recall some nightmarish function that expects a half-dozen or so arguments!) Accordingly, currying should be seen as an effort to simplify a function call. The interface types in the **java.util.function** package are suited for currying, as the next example shows.
References of the **IntBinaryOperator** interface type are for functions that take two integer arguments and return an integer value:
```
IntBinaryOperator mult2 = (n1, n2) -&gt; n1 * n2;
mult2.applyAsInt(10, 20); // 200
mult2.applyAsInt(10, 30); // 300
```
The reference name **mult2** underscores that two explicit arguments are required, in this example, 10 and 20.
The previously introduced **IntUnaryOperator** is simpler than an **IntBinaryOperator** because the former requires just one argument, whereas the latter requires two arguments. Both return an integer value. The goal, therefore, is to curry the two-argument **IntBinraryOperator** named **mult2** into a one-argument **IntUnaryOperator** version **curriedMult2**.
Consider the type **IntFunction&lt;R&gt;**. A function of this type takes an integer argument and returns a result of type **R**, which could be another function—indeed, an **IntBinaryOperator**. Having a lambda return another lambda is straightforward:
```
`arg1 -> (arg2 -> arg1 * arg2) // parentheses could be omitted`
```
The full lambda starts with **arg1,** and this lambda's body—and returned value—is another lambda, which starts with **arg2**. The returned lambda takes just one argument (**arg2**) but returns the product of two numbers (**arg1** and **arg2**). The following overview, followed by the code, should clarify.
Here is an overview of how **mult2** can be curried:
* A lambda of type **IntFunction&lt;IntUnaryOperator&gt;** is written and called with an integer value such as 10. The returned **IntUnaryOperator** caches the value 10 and thereby becomes the curried version of **mult2**, in this example, **curriedMult2**.
* The **curriedMult2** function then is called with a single explicit argument (e.g., 20), which is multiplied with the cached argument (in this case, 10) to produce the product returned.
Here are the details in code:
```
// Create a function that takes one argument n1 and returns a one-argument
// function n2 -&gt; n1 * n2 that returns an int (the product n1 * n2).
IntFunction&lt;IntUnaryOperator&gt; curriedMult2Maker = n1 -&gt; (n2 -&gt; n1 * n2);
```
Calling the **curriedMult2Maker** generates the desired **IntUnaryOperator** function:
```
// Use the curriedMult2Maker to get a curried version of mult2.
// The argument 10 is n1 from the lambda above.
IntUnaryOperator curriedMult2 = curriedMult2Maker2.apply(10);
```
The value 10 is now cached in the **curriedMult2** function so that the explicit integer argument in a **curriedMult2** call will be multiplied by 10:
```
curriedMult2.applyAsInt(20); // 200 = 10 * 20
curriedMult2.applyAsInt(80); // 800 = 10 * 80
```
The cached value can be changed at will:
```
curriedMult2 = curriedMult2Maker.apply(50); // cache 50
curriedMult2.applyAsInt(101);               // 5050 = 101 * 50
```
Of course, multiple curried versions of **mult2**, each an **IntUnaryOperator**, can be created in this way.
Currying takes advantage of a powerful feature about lambdas: a lambda is easily written to return whatever type of value is needed, including another lambda.
### Wrapping up
Java remains a class-based object-oriented programming language. But with the stream API and its supporting functional constructs, Java takes a decisive (and welcomed) step toward functional languages such as Lisp. The result is a Java better suited to process the massive data streams so common in modern programming. This step in the functional direction also makes it easier to write clear, concise Java in the pipeline style highlighted in previous code examples:
```
dataStream
   .parallelStream() // multi-threaded for efficiency
   .filter(...)      // stage 1
   .map(...)         // stage 2
   .filter(...)      // stage 3
   ...
   .collect(...);    // or, perhaps, reduce: stage N
```
The automatic multi-threading, illustrated with the **parallel** and **parallelStream** calls, is built upon Java's fork/join framework, which supports _task stealing_ for efficiency. Suppose that the thread pool behind a **parallelStream** call consists of eight threads and that the **dataStream** is partitioned eight ways. Some thread (e.g., T1) might work faster than another (e.g., T7), which means that some of T7's tasks ought to be moved into T1's work queue. This happens automatically at runtime.
The programmer's chief responsibility in this easy multi-threading world is to write thread-safe functions passed as arguments to the higher-order functions that dominate in the stream API. Lambdas, in particular, encourage the writing of pure—and, therefore, thread-safe—functions.
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/1/javastream
作者:[Marty Kalin][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/mkalindepauledu
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/features_solutions_command_data.png?itok=4_VQN3RK (computer screen )
[2]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+random
[3]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+list
[4]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+system
[5]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+number
[6]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+arrays
[7]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+integer
[8]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+string
[9]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+jbutton
[10]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+actionlistener
[11]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+actionevent
[12]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+date
[13]: https://en.wikipedia.org/wiki/Plain_old_Java_object

View File

@ -0,0 +1,535 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Put some loot in your Python platformer game)
[#]: via: (https://opensource.com/article/20/1/loot-python-platformer-game)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
Put some loot in your Python platformer game
======
Give your players some treasures to collect and boost their score in
this installment on programming video games with Python's Pygame module.
![Hearts, stars, and dollar signs][1]
This is part 9 in an ongoing series about creating video games in [Python 3][2] using the [Pygame][3] module. Previous articles are:
* [Learn how to program in Python by building a simple dice game][4]
* [Build a game framework with Python using the Pygame module][5]
* [How to add a player to your Python game][6]
* [Using Pygame to move your game character around][7]
* [What's a hero without a villain? How to add one to your Python game][8]
* [Simulate gravity in your Python game][9]
* [Add jumping to your Python platformer game][10]
* [Enable your Python game player to run forward and backward][11]
If you've followed along with the previous articles in this series, then you know all the basics of programming video game mechanics. You can build upon these basics to create a fully functional video game all your own. Following a "recipe" like the code samples in this series is helpful when you're first learning, but eventually, the recipe becomes a constraint. It's time to use the principles you've learned and apply them in new ways.
If that sounds easier said than done, this article demonstrates an example of how to leverage what you already know for new purposes. Specifically, it covers how to implement a looting system
using what you have already learned about platforms from previous lessons.
In most video games, you have the opportunity to "loot," or collect treasures and other items within the game world. Loot usually increases your score or your health or provides information leading to your next quest.
Including loot in your game is similar to programming platforms. Like platforms, loot has no user controls, scrolls with the game world, and must check for collisions with the player sprite.
### Creating the loot function
Loot is so similar to platforms that you don't even need a Loot class. You can just reuse the **Platform** class and call the results loot.
Since loot type and placement probably differ from level to level, create a new function called **loot** in your **Level** class, if you don't already have one. Since loot items are not platforms, you must also create a new **loot_list** group and then add loot objects to it. As with platforms, ground, and enemies, this group is used when checking for collisions:
```
    def loot(lvl,lloc):
        if lvl == 1:
            loot_list = pygame.sprite.Group()
            loot = Platform(300,ty*7,tx,ty, 'loot_1.png')
            loot_list.add(loot)
        if lvl == 2:
            print(lvl)
        return loot_list
```
You can add as many loot objects as you like; just remember to add each one to your loot list. The arguments for the **Platform** class are the X position, the Y position, the width and height of the loot sprite (it's usually easiest to keep your loot sprite the same size as all other tiles), and the image you want to use as loot. Placement of loot can be just as complex as mapping platforms, so use the level design document you created when creating the level.
Call your new loot function in the **Setup** section of your script. In the following code, the first three lines are for context, so just add the fourth:
```
enemy_list = Level.bad( 1, eloc )
ground_list = Level.ground( 1,gloc,tx,ty )
plat_list = Level.platform( 1,tx,ty )
loot_list = Level.loot(1,tx,ty)
```
As you know by now, the loot won't get drawn to the screen unless you include it in your main loop. Add the final line from the following code sample to your loop:
```
    enemy_list.draw(world)
    ground_list.draw(world)
    plat_list.draw(world)
    loot_list.draw(world)
```
Launch your game to see what happens.
![Loot in Python platformer][12]
Your loot objects are spawned, but they don't do anything when your player runs into them, nor do they scroll when your player runs past them. Fix these issues next.
### Scrolling loot
Like platforms, loot has to scroll when the player moves through the game world. The logic is identical to platform scrolling. To scroll the loot forward, add the last two lines:
```
        for e in enemy_list:
            e.rect.x -= scroll
        for l in loot_list:
            l.rect.x -= scroll
```
To scroll it backward, add the last two lines:
```
        for e in enemy_list:
            e.rect.x += scroll
        for l in loot_list:
            l.rect.x += scroll
```
Launch your game again to see that your loot objects now act like they're _in_ the game world instead of just painted on top of it.
### Detecting collisions
As with platforms and enemies, you can check for collisions between loot and your player. The logic is the same as other collisions, except that a hit doesn't (necessarily) affect gravity or health. Instead, a hit causes the loot to disappear and increment the player's score.
When your player touches a loot object, you can remove that object from the **loot_list**. This means that when your main loop redraws all loot items in **loot_list**, it won't redraw that particular object, so it will look like the player has grabbed the loot.
Add the following code above the platform collision detection in the **update** function of your **Player** class (the last line is just for context):
```
                loot_hit_list = pygame.sprite.spritecollide(self, loot_list, False)
                for loot in loot_hit_list:
                        loot_list.remove(loot)
                        self.score += 1
                print(self.score)
 
        plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
```
Not only do you remove the loot object from its group when a collision happens, but you also award your player a bump in score. You haven't created a score variable yet, so add that to your player's properties, created in the **__init__** function of the **Player** class. In the following code, the first two lines are for context, so just add the score variable:
```
        self.frame = 0
        self.health = 10
        self.score = 0
```
When calling the **update** function in your main loop, include the **loot_list**:
```
        player.gravity()
        player.update()
```
As you can see, you've got all the basics. All you have to do now is use what you know in new ways.
There are a few more tips in the next article, but in the meantime, use what you've learned to make a few simple, single-level games. Limiting the scope of what you are trying to create is important so that you don't overwhelm yourself. It also makes it easier to end up with a finished product that looks and feels finished.
Here's all the code you've written for this Python platformer so far:
```
#!/usr/bin/env python3
# draw a world
# add a player and player control
# add player movement
# add enemy and basic collision
# add platform
# add gravity
# add jumping
# add scrolling
# GNU All-Permissive License
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved.  This file is offered as-is,
# without any warranty.
import pygame
import sys
import os
'''
Objects
'''
class Platform(pygame.sprite.Sprite):
    # x location, y location, img width, img height, img file    
    def __init__(self,xloc,yloc,imgw,imgh,img):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(os.path.join('images',img)).convert()
        self.image.convert_alpha()
        self.rect = self.image.get_rect()
        self.rect.y = yloc
        self.rect.x = xloc
class Player(pygame.sprite.Sprite):
    '''
    Spawn a player
    '''
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.movex = 0
        self.movey = 0
        self.frame = 0
        self.health = 10
        self.collide_delta = 0
        self.jump_delta = 6
        self.score = 1
        self.images = []
        for i in range(1,9):
            img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
            img.convert_alpha()
            img.set_colorkey(ALPHA)
            self.images.append(img)
            self.image = self.images[0]
            self.rect  = self.image.get_rect()
    def jump(self,platform_list):
        self.jump_delta = 0
    def gravity(self):
        self.movey += 3.2 # how fast player falls
       
        if self.rect.y &gt; worldy and self.movey &gt;= 0:
            self.movey = 0
            self.rect.y = worldy-ty
       
    def control(self,x,y):
        '''
        control player movement
        '''
        self.movex += x
        self.movey += y
       
    def update(self):
        '''
        Update sprite position
        '''
       
        self.rect.x = self.rect.x + self.movex
        self.rect.y = self.rect.y + self.movey
        # moving left
        if self.movex &lt; 0:
            self.frame += 1
            if self.frame &gt; ani*3:
                self.frame = 0
            self.image = self.images[self.frame//ani]
        # moving right
        if self.movex &gt; 0:
            self.frame += 1
            if self.frame &gt; ani*3:
                self.frame = 0
            self.image = self.images[(self.frame//ani)+4]
        # collisions
        enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
        for enemy in enemy_hit_list:
            self.health -= 1
            #print(self.health)
        loot_hit_list = pygame.sprite.spritecollide(self, loot_list, False)
        for loot in loot_hit_list:
            loot_list.remove(loot)
            self.score += 1
            print(self.score)
        plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
        for p in plat_hit_list:
            self.collide_delta = 0 # stop jumping
            self.movey = 0
            if self.rect.y &gt; p.rect.y:
                self.rect.y = p.rect.y+ty
            else:
                self.rect.y = p.rect.y-ty
           
        ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
        for g in ground_hit_list:
            self.movey = 0
            self.rect.y = worldy-ty-ty
            self.collide_delta = 0 # stop jumping
            if self.rect.y &gt; g.rect.y:
                self.health -=1
                print(self.health)
               
        if self.collide_delta &lt; 6 and self.jump_delta &lt; 6:
            self.jump_delta = 6*2
            self.movey -= 33  # how high to jump
            self.collide_delta += 6
            self.jump_delta    += 6
           
class Enemy(pygame.sprite.Sprite):
    '''
    Spawn an enemy
    '''
    def __init__(self,x,y,img):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(os.path.join('images',img))
        self.movey = 0
        #self.image.convert_alpha()
        #self.image.set_colorkey(ALPHA)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.counter = 0
               
    def move(self):
        '''
        enemy movement
        '''
        distance = 80
        speed = 8
        self.movey += 3.2
       
        if self.counter &gt;= 0 and self.counter &lt;= distance:
            self.rect.x += speed
        elif self.counter &gt;= distance and self.counter &lt;= distance*2:
            self.rect.x -= speed
        else:
            self.counter = 0
       
        self.counter += 1
        if not self.rect.y &gt;= worldy-ty-ty:
            self.rect.y += self.movey
        plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
        for p in plat_hit_list:
            self.movey = 0
            if self.rect.y &gt; p.rect.y:
                self.rect.y = p.rect.y+ty
            else:
                self.rect.y = p.rect.y-ty
        ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
        for g in ground_hit_list:
            self.rect.y = worldy-ty-ty
       
class Level():
    def bad(lvl,eloc):
        if lvl == 1:
            enemy = Enemy(eloc[0],eloc[1],'yeti.png') # spawn enemy
            enemy_list = pygame.sprite.Group() # create enemy group
            enemy_list.add(enemy)              # add enemy to group
           
        if lvl == 2:
            print("Level " + str(lvl) )
        return enemy_list
    def loot(lvl,tx,ty):
        if lvl == 1:
            loot_list = pygame.sprite.Group()
            loot = Platform(200,ty*7,tx,ty, 'loot_1.png')
            loot_list.add(loot)
        if lvl == 2:
            print(lvl)
        return loot_list
    def ground(lvl,gloc,tx,ty):
        ground_list = pygame.sprite.Group()
        i=0
        if lvl == 1:
            while i &lt; len(gloc):
                ground = Platform(gloc[i],worldy-ty,tx,ty,'ground.png')
                ground_list.add(ground)
                i=i+1
        if lvl == 2:
            print("Level " + str(lvl) )
        return ground_list
    def platform(lvl,tx,ty):
        plat_list = pygame.sprite.Group()
        ploc = []
        i=0
        if lvl == 1:
            ploc.append((20,worldy-ty-128,3))
            ploc.append((300,worldy-ty-256,3))
            ploc.append((500,worldy-ty-128,4))
            while i &lt; len(ploc):
                j=0
                while j &lt;= ploc[i][2]:
                    plat = Platform((ploc[i][0]+(j*tx)),ploc[i][1],tx,ty,'ground.png')
                    plat_list.add(plat)
                    j=j+1
                print('run' + str(i) + str(ploc[i]))
                i=i+1
        if lvl == 2:
            print("Level " + str(lvl) )
        return plat_list
'''
Setup
'''
worldx = 960
worldy = 720
fps = 40 # frame rate
ani = 4  # animation cycles
clock = pygame.time.Clock()
pygame.init()
main = True
BLUE  = (25,25,200)
BLACK = (23,23,23 )
WHITE = (254,254,254)
ALPHA = (0,255,0)
world = pygame.display.set_mode([worldx,worldy])
backdrop = pygame.image.load(os.path.join('images','stage.png')).convert()
backdropbox = world.get_rect()
player = Player() # spawn player
player.rect.x = 0
player.rect.y = 0
player_list = pygame.sprite.Group()
player_list.add(player)
steps = 10
forwardx = 600
backwardx = 230
eloc = []
eloc = [200,20]
gloc = []
#gloc = [0,630,64,630,128,630,192,630,256,630,320,630,384,630]
tx = 64 #tile size
ty = 64 #tile size
i=0
while i &lt;= (worldx/tx)+tx:
    gloc.append(i*tx)
    i=i+1
enemy_list = Level.bad( 1, eloc )
ground_list = Level.ground( 1,gloc,tx,ty )
plat_list = Level.platform( 1,tx,ty )
loot_list = Level.loot(1,tx,ty)
'''
Main loop
'''
while main == True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit(); sys.exit()
            main = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT or event.key == ord('a'):
                print("LEFT")
                player.control(-steps,0)
            if event.key == pygame.K_RIGHT or event.key == ord('d'):
                print("RIGHT")
                player.control(steps,0)
            if event.key == pygame.K_UP or event.key == ord('w'):
                print('jump')
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT or event.key == ord('a'):
                player.control(steps,0)
            if event.key == pygame.K_RIGHT or event.key == ord('d'):
                player.control(-steps,0)
            if event.key == pygame.K_UP or event.key == ord('w'):
                player.jump(plat_list)
            if event.key == ord('q'):
                pygame.quit()
                sys.exit()
                main = False
    # scroll the world forward
    if player.rect.x &gt;= forwardx:
        scroll = player.rect.x - forwardx
        player.rect.x = forwardx
        for p in plat_list:
            p.rect.x -= scroll
        for e in enemy_list:
            e.rect.x -= scroll
        for l in loot_list:
            l.rect.x -= scroll
               
    # scroll the world backward
    if player.rect.x &lt;= backwardx:
        scroll = backwardx - player.rect.x
        player.rect.x = backwardx
        for p in plat_list:
            p.rect.x += scroll
        for e in enemy_list:
            e.rect.x += scroll
        for l in loot_list:
            l.rect.x += scroll
    world.blit(backdrop, backdropbox)    
    player.gravity() # check gravity
    player.update()
    player_list.draw(world) #refresh player position
    enemy_list.draw(world)  # refresh enemies
    ground_list.draw(world)  # refresh enemies
    plat_list.draw(world)   # refresh platforms
    loot_list.draw(world)   # refresh loot
    for e in enemy_list:
        e.move()
    pygame.display.flip()
    clock.tick(fps)
```
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/1/loot-python-platformer-game
作者:[Seth Kenlon][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/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/BUS_lovemoneyglory2.png?itok=AvneLxFp (Hearts, stars, and dollar signs)
[2]: https://www.python.org/
[3]: https://www.pygame.org/news
[4]: https://opensource.com/article/17/10/python-101
[5]: https://opensource.com/article/17/12/game-framework-python
[6]: https://opensource.com/article/17/12/game-python-add-a-player
[7]: https://opensource.com/article/17/12/game-python-moving-player
[8]: https://opensource.com/article/18/5/pygame-enemy
[9]: https://opensource.com/article/19/11/simulate-gravity-python
[10]: https://opensource.com/article/19/12/jumping-python-platformer-game
[11]: https://opensource.com/article/19/12/python-platformer-game-run
[12]: https://opensource.com/sites/default/files/uploads/pygame-loot.jpg (Loot in Python platformer)

View File

@ -0,0 +1,103 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (GNOME has a Secret Screen Recorder. Heres How to Use it!)
[#]: via: (https://itsfoss.com/gnome-screen-recorder/)
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
GNOME has a Secret Screen Recorder. Heres How to Use it!
======
[GNOME][1] is one of the [most popular desktop environments][2] and for good reasons. It has a modern UI and it comes with a number of GNOME-specific applications that blend well with the overall desktop appearance.
You can [tweak GNOME][3] to your liking as much as you want but I am not here to discuss that. GNOME desktop has some hidden features that you probably are not aware of.
One of such not-so-obvious feature is a built in screen recorder.
Yes, you read that right. If you are using GNOME desktop, you dont necessarily need to install other [screen recorders in Linux][4]. You just need to know the correct keyboard shortcut.
### Instantly record your screen with GNOME Screen Recorder
To quickly access the GNOME screen recorder, you have to press this [keyboard shortcut in Ubuntu][5] or other distributions using GNOME desktop:
```
Ctrl + Alt + Shift + R
```
This will immediately start recording your desktop. You can tell that the screen recording is in progress by looking at the red dot in the system tray area of the top panel:
![The red dot in the system tray area indicates that screen recording is in progress][6]
#### Increase the screencast duration
The default maximum record time is just 30 seconds. It can be increased though.
Open a terminal and use the following command:
```
gsettings set org.gnome.settings-daemon.plugins.media-keys max-screencast-length 300
```
In the above command, I have increased the maximum length of the recording to 300 seconds (i.e. 5 minutes). You can change it to any other value but it should be in seconds.
If you **dont want any limit on the maximum recording time, set it to 0** and then the recording wont stop until you manually stop it or your disk runs out of space.
#### Stop the screen recording
As I mentioned, your desktop recording will stop automatically after it reaches the maximum time limit.
To stop the recording before that, you can press the same key combination:
```
Ctrl + Alt + Shift + R
```
Your recordings are saved in [webm][7] format in the Videos folder of your Home directory.
#### Limitations
While it might be handy to record your desktop quickly with this handy little tool, it has its several limitations when compared to a full-fledged screen recording tool like [Simple Screen Recorder][8].
* There is no time delay option before the recording starts
* There is no pause and play option
* It records the entire screen. No option to record only an application window or a ceratin area or a certain monitor (if you have a multi-monitor setup).
* Videos are saved in webm format in the users Videos directory. You cannot change it. Youll have to use a tool like [HandBrake to convert the videos to other format][9].
As you can see, the secret GNOME screen recorder is no where near to the features provided by the likes of [Kazam][10] or other such tools.
But it doesnt try to be a full-fledged screen recorder. It just provides you a quick way of recording a small screencast. Thats it.
GNOME is a versatile modern desktop environments. You can [tweak GNOME][3] extensively. The [GNOME Extensions][11] provide another dimension to the desktop customization.
This screen recorder is one of the hidden features of GNOME like the suspend option that you wont easily find on your own.
_How do you like it? Do you know some other hidden GNOME features that you would like to share with us? The comment section is all yours._
--------------------------------------------------------------------------------
via: https://itsfoss.com/gnome-screen-recorder/
作者:[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://gnome.org/
[2]: https://itsfoss.com/best-linux-desktop-environments/
[3]: https://itsfoss.com/gnome-tweak-tool/
[4]: https://itsfoss.com/best-linux-screen-recorders/
[5]: https://itsfoss.com/ubuntu-shortcuts/
[6]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/01/gnome_screen_recording.jpg?ssl=1
[7]: https://www.webmproject.org/about/
[8]: https://itsfoss.com/record-screen-ubuntu-simplescreenrecorder/
[9]: https://itsfoss.com/handbrake/
[10]: https://itsfoss.com/kazam-screen-recorder/
[11]: https://itsfoss.com/best-gnome-extensions/

View File

@ -1,91 +0,0 @@
[#]: collector: "lujun9972"
[#]: translator: "nacyro"
[#]: reviewer: " "
[#]: publisher: " "
[#]: url: " "
[#]: subject: "10 articles to enhance your security aptitude"
[#]: via: "https://opensource.com/article/19/12/security-resources"
[#]: author: "Ben Cotton https://opensource.com/users/bcotton"
10 篇文章强化你的安全能力
======
无论你是新手还是想要增加技能Opensource.com 2019 年十大安全文章中都有适合你的内容。
![A secure lock.][1]
如果安全是一个过程确实如此那么理所当然的不同的项目及其贡献者情况各有不同。有些应用程序经历了多年的安全测试由在信息安全领域工作了几十年的人员所设计。其他的则是由开发人员在他们的第一个开源项目中开发的全新项目。毫不奇怪Opensource.com 2019 年十大安全文章囊括了代表这一范围的经验。我们有介绍基本安全实践的文章,也有深入探讨更高级主题的文章。
无论你是新手还是想要增加你在传奇职业生涯中获得的技能2019 年十大安全文章中都有适合你的内容。
### 《七步捍卫你的 Linux 服务器7 steps to securing your Linux server
安全如舍地基不牢房屋不稳。Patrick H. Mullins 的杰作《[七步捍卫你的 Linux 服务器7 steps to securing your Linux server][2]》让您从Linux服务器的基本安全步骤开始。即使您有很多管理服务器的经验本文也提供了一个很好的清单以确保您掌握了基础知识。在此基础上您可以开始添加额外的安全层。
### 《用防火墙使 Linux 更健壮Make Linux stronger with firewalls
七步捍卫你的 Linux 服务器中的一步即是启用防火墙。但什么**是**防火墙它是如何工作的呢 Seth Kenlon 在《[用防火墙使 Linux 更健壮Make Linux stronger with firewalls][3]》一文中回答了这些问题,然后详细描述了为了更好的安全性应如何配置你的防火墙。使用 `firewalld``Network Manager`,您可以为不同的网络设置不同的防火墙配置。例如,这允许您在您的家庭网络上进行信任配置,并在您最喜欢的咖啡店的 WiFi 网络上进行更多疑的配置。
### 《减少集中日志的安全风险Reducing security risks with centralized logging
保护系统安全,只有开始,没有结束:安全是一个过程而不是状态。**保持**系统安全工作的一部分即是密切关注所发生的事情。集中化日志是实现这一点的一种方法,尤其是在管理多系统时。在《[减少集中日志的安全风险Reducing security risks with centralized logging][4]》中 Hannah Suarez 分享了要如何开始(她这篇文章基于她在 FOSDEM'19 (自由及开源软件开发者欧洲会议) 中的闪电演讲)
### 《为 SSH 使用 GPG 密钥Using GPG keys for SSH
大多数人都会为 `SSH` 的密钥认证使用 `SSH 密钥`。为什么不呢毕竟就在名字里。从安全的角度来看这些方法非常好。但若想简化某些形式的密钥分发与备份还有另一种方法Brian Exelbierd 的三部曲系列介绍了《[如何启用使用 GPG 子钥的 SSH 访问How to enable SSH access with a GPG subkey][5]》、《[如何导入现有 SSH 密钥How to import existing SSH keys][6]》、《[如何将备份量减少到单个密钥文件How to reduce your backup needs to a single key file][7]》
### 《使用 `Seahorse` 图形化管理 SSH 密钥Graphically manage SSH keys with Seahorse
并不是所有人都喜欢用 `GPG` 作为 `SSH 密钥`,但这并不意味着您在密钥管理上会不顺。`Seahorse` 是一个在 `GNOME` 桌面中用于管理 `SSH 密钥` 及其他身份验证方法的图形化工具。Alan Formy-Duval 的《[使用 `Seahorse` 图形化管理 SSH 密钥Graphically manage SSH keys with Seahorse][8]》对新手用户特别有帮助。
### 《安全扫描你的 DevOps 管线Security scanning your DevOps pipeline
如今到处都是容器。但它们容纳着什么了解容器满足您的安全策略是保持安全性的重要部分。幸运的是您可以使用开源工具来帮助自动化符合性检查。Jessica Cherry (原名: Repka) 的《[安全扫描你的 DevOps 管线Security scanning your DevOps pipeline][9]》是一个循序渐进的教程,向您展示了如何使用 `Jenkins` 构建系统和 `Anchore` 检查服务为容器镜像和 `registries` 创建扫描管线。
### 《四个开源云安全工具4 open source cloud security tools
云服务的一大优点是你的数据可以从任何地方访问。云服务的一个缺点是你的数据可以从任何地方访问。如果您使用的是 `"-as-a-Service" (译注: IaaS, PaaS, SaaS)` 产品那么您需要确保它们是经过安全配置的。Anderson Silva、Alison Naylor、Travis McPeak 和 Rich Monk 联合推出《[四个开源云安全工具4 open source cloud security tools][10]》以帮助在使用 `GitHub``AWS` 时提高安全性。如果你正在寻找被不小心提交的秘密,或尝试从一开始就阻止这些秘密被提交,这篇文章提供了工具。
### 《如何使用OpenSSL哈希数字签名等等How to use OpenSSL: hashes, digital signatures, and more
许多信息安全是基于数学的:特别是用于加密数据和验证用户或文件内容的加密函数。在《[开始使用 OpenSSL密码学基础Getting started with OpenSSL: Cryptography basics][11]》中进行介绍后Marty Kalin 深入讨论了《[如何使用 OpenSSL哈希数字签名等等How to use OpenSSL: hashes, digital signatures, and more][12]》的细节,解释了如何使用 `OpenSSL` 实用程序来探索这些常用但不常被理解的概念。
### 《使用树莓派和 Kali Linux 学习计算机安全Learn about computer security with the Raspberry Pi and Kali Linux
廉价硬件与开源软件构成了一个很好的组合,特别是对于那些希望边做边学的人来说。在《[使用树莓派和 Kali Linux 学习计算机安全Learn about computer security with the Raspberry Pi and Kali Linux][13]》这篇文章中Anderson Silva 介绍了面向安全的 `Kali Linux` 发行版。这是一篇短文,但它满是关于文档和安全相关项目的有用的链接,您可以在自己的树莓派上使用它们。
### 《量子计算会破坏安全吗Will quantum computing break security?)》
这篇文章的余下部分是浪费吗?量子计算会让我们对安全的所知变得过时吗?好消息是:回答是否定的,但是量子计算仍然可以在更广泛的范围内对安全和计算世界产生深远的影响。在《[量子计算会破坏安全吗Will quantum computing break security?][14]》一文中Mike Bursell 剖析了它好坏两方面的影响,当然,量子计算可能会让加密的破解变得更容易,但如果坏人一开始就无法获得你的数据,那也没有关系。
### 《展望 2020Looking to 2020
安全永远是重要的,(正如那篇量子计算文章所建议的) 未来几年将是该领域的一个有趣时期。在 2020 年Opensource.com 的文章将着眼于开源安全的前沿,并帮助向不断增长的开源社区解释基础知识。如果你有一个你想要我们报导的主题,请在评论中分享它,或者更进一步 —— 如果你想写一篇文章,就写给我们吧。
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/12/security-resources
作者:[Ben Cotton][a]
选题:[lujun9972][b]
译者:[nacyro](https://github.com/nacyro)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/bcotton
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003601_05_mech_osyearbook2016_security_cc.png?itok=3V07Lpko "A secure lock."
[2]: https://opensource.com/article/19/10/linux-server-security
[3]: https://opensource.com/article/19/7/make-linux-stronger-firewalls
[4]: https://opensource.com/article/19/2/reducing-security-risks-centralized-logging
[5]: https://opensource.com/article/19/4/gpg-subkeys-ssh
[6]: https://opensource.com/article/19/4/gpg-subkeys-ssh-multiples
[7]: https://opensource.com/article/19/4/gpg-subkeys-ssh-manage
[8]: https://opensource.com/article/19/4/ssh-keys-seahorse
[9]: https://opensource.com/article/19/7/security-scanning-your-devops-pipeline
[10]: https://opensource.com/article/19/9/open-source-cloud-security
[11]: https://opensource.com/article/19/6/cryptography-basics-openssl-part-1
[12]: https://opensource.com/article/19/6/cryptography-basics-openssl-part-2
[13]: https://opensource.com/article/19/3/computer-security-raspberry-pi
[14]: https://opensource.com/article/19/1/will-quantum-computing-break-security
[15]: https://opensource.com/how-submit-article

View File

@ -0,0 +1,101 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Fixing “VLC is Unable to Open the MRL” Error [Quick Tip])
[#]: via: (https://itsfoss.com/vlc-is-unable-to-open-the-mrl/)
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
修复 “VLC is Unable to Open the MRL” 错误
======
一个使用 [VLC 的技巧][1]是使用 [VLC] [2] 播放 YouTube 和其他在线视频。这可以帮助你[观看带有字幕的在线视频][3]。
但是事情并不总是这么简单,因为有时使用 VLC 打开 YouTube 视频时会遇到此错误:
**Your input cant be opened: VLC is unable to open the MRL <https://youtubeurl.com>. Check the log for details.**
![VLC error while playing YouTube videos][4]
这是因为 Google 不想让你使用任何第三方应用观看 YouTube因为这样他们就无法正常收集数据。
因此,他们不断修改服务端,以使第三发开发更难与 Youtube 集成。
以 [youtube-dl][5] 为例。你会发现自己无法突然[下载 YouTube 视频] [6],最简单的方案是安装最新版本的 youtube-dl。
对于 VLC 也是如此。如果你[在 Ubuntu 或任何你用的系统中安装了最新的 VLC][7],那么可能不会看到此错误。
### 修复 ”VLC is unable to open the MRL“ 错误
让我向你展示对于 YouTube 的修复步骤。
进入 VLC 媒体播放器的官方 Github 仓库页面,并使用 Ctrl+S 保存文件:
[Download youtube.lua file][8]
现在,你需要做的是用此下载文件替换 lib/vlc/lua/playlist 目录中的 youtube.luac注意 luac 中的 “c”
#### Linux 中的步骤
如果你使用的是 Linux请打开终端并使用 [locate 命令][9]查找 youtube.luac 文件的确切位置:
```
locate youtube.luac
```
当你得到文件的路径时,只需将该文件替换为下载的文件即可。我相信你可以完成这项简单的任务。
对我而言,以下是文件路径:
```
[email protected]:~$ locate youtube.lua
/usr/lib/x86_64-linux-gnu/vlc/lua/playlist/youtube.luac
```
因此,我要做的就是将下载的文件移到该位置并替换它的内容:
```
sudo cp ~/Downloads/youtube.lua /usr/lib/x86_64-linux-gnu/vlc/lua/playlist/youtube.luac
```
你现在应该可以在 VLC 中播放 YouTube 视频了。
#### Windows 中的步骤
如果你使用的是 Windows那么应遵循以下步骤
* 将下载的 youtube.lua 文件重命名为 youtube.luac
* 复制此文件并将其粘贴到 C:\Program Files (x86)\VideoLAN\VLC\lua\playlist\
就是这些了。
如果你在 Dailymotion 或其他视频流网站上遇到问题,那么可以从 VLC 仓库的[此处][10]下载它们各自的 lua 文件,并替换 VLC 安装中的现有 lua 文件。
我希望这个快速提示可以解决 VLC 无法为你播放 YouTube 视频的问题。
--------------------------------------------------------------------------------
via: https://itsfoss.com/vlc-is-unable-to-open-the-mrl/
作者:[Abhishek Prakash][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[校对者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/simple-vlc-tips/
[2]: https://www.videolan.org/index.html
[3]: https://itsfoss.com/penguin-subtitle-player/
[4]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/12/vlc_error_input_cant_be_played.png?ssl=1
[5]: https://itsfoss.com/download-youtube-linux/
[6]: https://itsfoss.com/download-youtube-videos-ubuntu/
[7]: https://itsfoss.com/install-latest-vlc/
[8]: https://raw.githubusercontent.com/videolan/vlc/master/share/lua/playlist/youtube.lua
[9]: https://linuxhandbook.com/locate-command/
[10]: https://github.com/videolan/vlc/tree/master/share/lua/playlist