Merge remote-tracking branch 'LCTT/master'

This commit is contained in:
Xingyu Wang 2020-01-29 21:08:41 +08:00
commit 23a50b9244
18 changed files with 2367 additions and 1168 deletions

View File

@ -0,0 +1,525 @@
[#]: collector: (lujun9972)
[#]: translator: (heguangzhi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-11828-1.html)
[#]: 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)
在你的 Python 平台类游戏中放一些奖励
======
> 这部分是关于在使用 Python 的 Pygame 模块开发的视频游戏总给你的玩家提供收集的宝物和经验值的内容。
![](https://img.linux.net.cn/data/attachment/album/202001/29/131158jkwnhgd1nnawzn86.jpg)
这是正在进行的关于使用 [Python 3][2] 的 [Pygame][3] 模块创建视频游戏的系列文章的第十部分。以前的文章有:
* [通过构建一个简单的掷骰子游戏去学习怎么用 Python 编程][4]
* [使用 Python 和 Pygame 模块构建一个游戏框架][5]
* [如何在你的 Python 游戏中添加一个玩家][6]
* [用 Pygame 使你的游戏角色移动起来][7]
* [如何向你的 Python 游戏中添加一个敌人][8]
* [在 Pygame 游戏中放置平台][13]
* [在你的 Python 游戏中模拟引力][9]
* [为你的 Python 平台类游戏添加跳跃功能][10]
* [使你的 Python 游戏玩家能够向前和向后跑][11]
如果你已经阅读了本系列的前几篇文章,那么你已经了解了编写游戏的所有基础知识。现在你可以在这些基础上,创造一个全功能的游戏。当你第一次学习时,遵循本系列代码示例,这样的“用例”是有帮助的,但是,用例也会约束你。现在是时候运用你学到的知识,以新的方式应用它们了。
如果说,说起来容易做起来难,这篇文章展示了一个如何将你已经了解的内容用于新目的的例子中。具体来说,就是它涵盖了如何使用你以前的课程中已经了解到的来实现奖励系统。
在大多数电子游戏中,你有机会在游戏世界中获得“奖励”或收集到宝物和其他物品。奖励通常会增加你的分数或者你的生命值,或者为你的下一次任务提供信息。
游戏中包含的奖励类似于编程平台。像平台一样,奖励没有用户控制,随着游戏世界的滚动进行,并且必须检查与玩家的碰撞。
### 创建奖励函数
奖励和平台非常相似,你甚至不需要一个奖励的类。你可以重用 `Platform` 类,并将结果称为“奖励”。
由于奖励类型和位置可能因关卡不同而不同,如果你还没有,请在你的 `Level` 中创建一个名为 `loot` 的新函数。因为奖励物品不是平台,你也必须创建一个新的 `loot_list` 组,然后添加奖励物品。与平台、地面和敌人一样,该组用于检查玩家碰撞:
```
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
```
你可以随意添加任意数量的奖励对象;记住把每一个都加到你的奖励清单上。`Platform` 类的参数是奖励图标的 X 位置、Y 位置、宽度和高度(通常让你的奖励精灵保持和所有其他方块一样的大小最为简单),以及你想要用作的奖励的图片。奖励的放置可以和贴图平台一样复杂,所以使用创建关卡时需要的关卡设计文档。
在脚本的设置部分调用新的奖励函数。在下面的代码中,前三行是上下文,所以只需添加第四行:
```
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)
```
正如你现在所知道的,除非你把它包含在你的主循环中,否则奖励不会被显示到屏幕上。将下面代码示例的最后一行添加到循环中:
```
    enemy_list.draw(world)
    ground_list.draw(world)
    plat_list.draw(world)
    loot_list.draw(world)
```
启动你的游戏看看会发生什么。
![Loot in Python platformer][12]
你的奖励将会显示出来,但是当你的玩家碰到它们时,它们不会做任何事情,当你的玩家经过它们时,它们也不会滚动。接下来解决这些问题。
### 滚动奖励
像平台一样,当玩家在游戏世界中移动时,奖励必须滚动。逻辑与平台滚动相同。要向前滚动奖励物品,添加最后两行:
```
        for e in enemy_list:
            e.rect.x -= scroll
        for l in loot_list:
            l.rect.x -= scroll
```
要向后滚动,请添加最后两行:
```
        for e in enemy_list:
            e.rect.x += scroll
        for l in loot_list:
            l.rect.x += scroll
```
再次启动你的游戏,看看你的奖励物品现在表现得像在游戏世界里一样了,而不是仅仅画在上面。
### 检测碰撞
就像平台和敌人一样,你可以检查奖励物品和玩家之间的碰撞。逻辑与其他碰撞相同,除了撞击不会(必然)影响重力或生命值。取而代之的是,命中会导致奖励物品会消失并增加玩家的分数。
当你的玩家触摸到一个奖励对象时,你可以从 `loot_list` 中移除该对象。这意味着当你的主循环在 `loot_list` 中重绘所有奖励物品时,它不会重绘那个特定的对象,所以看起来玩家已经获得了奖励物品。
`Player` 类的 `update` 函数中的平台碰撞检测之上添加以下代码(最后一行仅用于上下文):
```
                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)
```
当碰撞发生时,你不仅要把奖励从它的组中移除,还要给你的玩家一个分数提升。你还没有创建分数变量,所以请将它添加到你的玩家属性中,该属性是在 `Player` 类的 `__init__` 函数中创建的。在下面的代码中,前两行是上下文,所以只需添加分数变量:
```
        self.frame = 0
        self.health = 10
        self.score = 0
```
当在主循环中调用 `update` 函数时,需要包括 `loot_list`
```
        player.gravity()
        player.update()
```
如你所见,你已经掌握了所有的基本知识。你现在要做的就是用新的方式使用你所知道的。
在下一篇文章中还有一些提示,但是与此同时,用你学到的知识来制作一些简单的单关卡游戏。限制你试图创造的东西的范围是很重要的,这样你就不会埋没自己。这也使得最终的成品看起来和感觉上更容易完成。
以下是迄今为止你为这个 Python 平台编写的所有代码:
```
#!/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 > worldy and self.movey >= 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 < 0:
self.frame += 1
if self.frame > ani*3:
self.frame = 0
self.image = self.images[self.frame//ani]
# moving right
if self.movex > 0:
self.frame += 1
if self.frame > 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 > 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 > g.rect.y:
self.health -=1
print(self.health)
if self.collide_delta < 6 and self.jump_delta < 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 >= 0 and self.counter <= distance:
self.rect.x += speed
elif self.counter >= distance and self.counter <= distance*2:
self.rect.x -= speed
else:
self.counter = 0
self.counter += 1
if not self.rect.y >= 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 > 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 < 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 < len(ploc):
j=0
while j <= 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 <= (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 >= 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 <= 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]
译者:[heguangzhi](https://github.com/heguangzhi)
校对:[wxy](https://github.com/wxy)
本文由 [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://linux.cn/article-9071-1.html
[5]: https://linux.cn/article-10850-1.html
[6]: https://linux.cn/article-10858-1.html
[7]: https://linux.cn/article-10874-1.html
[8]: https://linux.cn/article-10883-1.html
[9]: https://linux.cn/article-11780-1.html
[10]: https://linux.cn/article-11790-1.html
[11]: https://linux.cn/article-11819-1.html
[12]: https://opensource.com/sites/default/files/uploads/pygame-loot.jpg (Loot in Python platformer)
[13]: https://linux.cn/article-10902-1.html

View File

@ -1,29 +1,32 @@
[#]: collector: (lujun9972)
[#]: translator: (laingke)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-11830-1.html)
[#]: subject: (Setting up passwordless Linux logins using public/private keys)
[#]: via: (https://www.networkworld.com/article/3514607/setting-up-passwordless-linux-logins-using-publicprivate-keys.html)
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
使用公钥/私钥对设定免密的 Linux 登录方式
======
使用一组公钥/私钥对让你不需要密码登录到远程 Linux 系统或使用 ssh 运行命令,这会非常方便,但是设置过程有点复杂。下面是帮助你的方法和脚本。
> 使用一组公钥/私钥对让你不需要密码登录到远程 Linux 系统或使用 ssh 运行命令,这会非常方便,但是设置过程有点复杂。下面是帮助你的方法和脚本。
![](https://img.linux.net.cn/data/attachment/album/202001/29/141343ldps4muy4kp64k4l.jpg)
在 [Linux][1] 系统上设置一个允许你无需密码即可远程登录或运行命令的帐户并不难,但是要使它正常工作,你还需要掌握一些繁琐的细节。在本文,我们将完成整个过程,然后给出一个可以帮助处理琐碎细节的脚本。
设置好之后,如果希望在脚本中运行 ssh 命令,尤其是希望配置自动运行的命令,那么免密访问特别有用。
设置好之后,如果希望在脚本中运行 `ssh` 命令,尤其是希望配置自动运行的命令,那么免密访问特别有用。
需要注意的是,你不需要在两个系统上使用相同的用户帐户。实际上,你可以把公用密钥用于系统上的多个帐户或多个系统上的不同帐户。
设置方法如下。
### which system to start on?在哪个系统上启动?
### 在哪个系统上启动?
首先,你需要从要发出命令的系统上着手。那就是你用来创建 ssh 密钥的系统。你还需要访问远程系统上的帐户并在其上运行这些命令。
首先,你需要从要发出命令的系统上着手。那就是你用来创建 `ssh` 密钥的系统。你还需要可以访问远程系统上的帐户并在其上运行这些命令。
为了使角色清晰明了我们将场景中的第一个系统称为“boss”因为它将发出要在另一个系统上运行的命令。
为了使角色清晰明了,我们将场景中的第一个系统称为 “boss”因为它将发出要在另一个系统上运行的命令。
因此,命令提示符如下:
@ -31,7 +34,7 @@
boss$
```
如果还没有在 boss 系统上为你的帐户设置公钥/私钥对请使用如下所示的命令创建一个密钥对。注意你可以在各种加密算法之间进行选择。一般使用RSA或DSA。注意要在不输入密码的情况下访问系统您需要在下面的对话框中输入两个提示符的密码。
如果还没有在 boss 系统上为你的帐户设置公钥/私钥对,请使用如下所示的命令创建一个密钥对。注意,你可以在各种加密算法之间进行选择。(一般使用 RSA DSA。注意要在不输入密码的情况下访问系统你需要在下面的对话框中的两个提示符出不输入密码。
如果你已经有一个与此帐户关联的公钥/私钥对,请跳过此步骤。
@ -59,18 +62,18 @@ The key's randomart image is:
+----[SHA256]-----+
```
上面显示的命令将创建公钥和私钥。其中公钥用于加密,私钥用于解密。因此,这些密钥之间的关系是关键的,私有密钥**绝不**应该被共享。相反,它应该保存在 boss 系统的 .ssh 文件夹中。
上面显示的命令将创建公钥和私钥。其中公钥用于加密,私钥用于解密。因此,这些密钥之间的关系是关键的,私有密钥**绝不**应该被共享。相反,它应该保存在 boss 系统的 `.ssh` 文件夹中。
注意,在创建时,你的公钥和私钥将会保存在 .ssh 文件夹中。
注意,在创建时,你的公钥和私钥将会保存在 `.ssh` 文件夹中。
下一步是将**公钥**复制到你希望从 boss 系统免密访问的系统。你可以使用 **scp** 命令来完成此操作但此时你仍然需要输入密码。在本例中该系统称为“target”。
下一步是将**公钥**复制到你希望从 boss 系统免密访问的系统。你可以使用 `scp` 命令来完成此操作,但此时你仍然需要输入密码。在本例中,该系统称为 “target”。
```
boss$ scp .ssh/id_rsa.pub myacct@target:/home/myaccount
myacct@target's password:
```
你需要安装公钥在 target 系统(将运行命令的系统)上。如果你没有 .ssh 目录(例如,你从未在该系统上使用过 ssh运行这样的命令将为你设置一个目录
你需要安装公钥在 target 系统(将运行命令的系统)上。如果你没有 `.ssh` 目录(例如,你从未在该系统上使用过 `ssh`),运行这样的命令将为你设置一个目录:
```
target$ ssh localhost date
@ -81,20 +84,20 @@ drwxr-xr-x 6 myacct myacct 4096 Jan 19 11:49 ..
-rw-r--r-- 1 myacct myacct 222 Jan 19 11:48 known_hosts
```
仍然在目标系统上你需要将从“boss”系统传输的公钥添加到 .ssh/authorized_keys 文件中。如果密钥已经存在,使用下面的命令将把它添加到文件的末尾;如果文件不存在,则创建文件并添加密钥。
仍然在目标系统上你需要将从“boss”系统传输的公钥添加到 `.ssh/authorized_keys` 文件中。如果该文件已经存在,使用下面的命令将把它添加到文件的末尾;如果文件不存在,则创建文件并添加密钥。
```
target$ cat id_rsa.pub >> .ssh/authorized_keys
```
下一步,你需要确保你的 authorized_keys 文件权限为 600。如果还不是执行命令 ```chmod 600 .ssh/authorized_keys```
下一步,你需要确保你的 `authorized_keys` 文件权限为 600。如果还不是执行命令 `chmod 600 .ssh/authorized_keys`
```
target$ ls -l authorized_keys
-rw------- 1 myself myself 569 Jan 19 12:10 authorized_keys
```
还要检查目标系统上 .ssh 目录的权限是否设置为 700。如果需要执行 ```chmod 700 .ssh``` 命令修改权限。
还要检查目标系统上 `.ssh` 目录的权限是否设置为 700。如果需要执行 `chmod 700 .ssh` 命令修改权限。
```
target$ ls -ld .ssh
@ -177,7 +180,7 @@ $ ssh lola@fruitfly
[lola@fruitfly ~]$
```
一旦设置了免密登录,你就可以不需要键入密码从 boss 系统登录到 target 系统,并且运行任意的 ssh 命令。以这种免密的方式运行并不意味着你的帐户不安全。然而,根据target 系统的性质,保护您在 boss 系统上的密码可能变得更加重要。
一旦设置了免密登录,你就可以不需要键入密码从 boss 系统登录到 target 系统,并且运行任意的 `ssh` 命令。以这种免密的方式运行并不意味着你的帐户不安全。然而,根据 target 系统的性质,保护你在 boss 系统上的密码可能变得更加重要。
--------------------------------------------------------------------------------
@ -186,7 +189,7 @@ via: https://www.networkworld.com/article/3514607/setting-up-passwordless-linux-
作者:[Sandra Henry-Stocker][a]
选题:[lujun9972][b]
译者:[laingke](https://github.com/laingke)
校对:[校对者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,60 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (IBM Power-based cloud instances available… from Google)
[#]: via: (https://www.networkworld.com/article/3516409/ibm-power-based-cloud-instances-available-from-google.html)
[#]: author: (Andy Patrizio https://www.networkworld.com/author/Andy-Patrizio/)
IBM Power-based cloud instances available… from Google
======
IBMs high-performance RISC processors are now available to Google Cloud Platform users as a service.
Oak Ridge National Laboratory
IBM and Google may be competitors in the cloud platform business, but that doesn't prevent them from working together. Google is partnering with IBM to offer "Power Systems as a service" on its Google Cloud platform.
IBMs Power processor line is the last man standing in the RISC/Unix war, surviving Sun Microsystems SPARC and HPs PA-RISC. Along with mainframes its the last server hardware business IBM has, having divested its x86 server line in 2014.
IBM already sells cloud instances of Power to its IBM Cloud customers, so this is just an expansion of existing offerings to a competitor with a considerable data center footprint. Google said that customers can run Power-based workloads on GCP on all of its operating systems save mainframes — AIX, IBM i, and Linux on IBM Power.
This gives GCP customers the option of moving legacy IT systems running on IBM Power Systems to a hybrid cloud and the option of using Google or IBM, which have their respective strengths. IBM is focused on IBM customers, while Google is more focused on containerization, AI and ML, and low latency.
IBM gains because its customers now have a second option, and customers like choice. GCP wins because it gives the company access to legacy IBM customers, something it never had as a relatively new company. It has no on-premises legacy, after all.
"For organizations using a hybrid cloud strategy, especially, IBM Power Systems are an important tool. Because of their performance and ability to support mission critical workloads—such as SAP applications and Oracle databases—enterprise customers have been consistently looking for options to run IBM Power Systems in the cloud," wrote Kevin Ichhpurani, GCP's corporate vice president of global ecosystem in a [blog post][1] announcing the deal.
"IBM Power Systems for Google Cloud offers a path to do just that, providing the best of both the cloud and on-premise worlds. You can run enterprise workloads like SAP and Oracle on the IBM Power servers that youve come to trust, while starting to take advantage of all the technical capabilities and favorable economics that Google Cloud offers," Ichhpurani added.
[[Get regularly scheduled insights by signing up for Network World newsletters.]][2]
Ichhpurani also noted several other benefits for customers:
* Integrated billing: GCP customers can deploy the solution through the Google Cloud Marketplace and get a single bill for their GCP and IBM Power use.
* Private API access: IBM Power resources can access Google Clouds Private API Access technology securely and at low latency
* Integrated customer support: Customer support for both GCP and IBM have a single point of contact for any issues.
* Rapid deployment: An intuitive new management console enables quick ramp-up and rapid deployment of the solution.
IBM Power is available to GCP customers now.
Join the Network World communities on [Facebook][3] and [LinkedIn][4] to comment on topics that are top of mind.
--------------------------------------------------------------------------------
via: https://www.networkworld.com/article/3516409/ibm-power-based-cloud-instances-available-from-google.html
作者:[Andy Patrizio][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.networkworld.com/author/Andy-Patrizio/
[b]: https://github.com/lujun9972
[1]: https://cloud.google.com/blog/products/gcp/ibm-power-systems-now-available-on-google-cloud
[2]: https://www.networkworld.com/newsletters/signup.html
[3]: https://www.facebook.com/NetworkWorld/
[4]: https://www.linkedin.com/company/network-world

View File

@ -0,0 +1,117 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Some Useful Probability Facts for Systems Programming)
[#]: via: (https://theartofmachinery.com/2020/01/27/systems_programming_probability.html)
[#]: author: (Simon Arneaud https://theartofmachinery.com)
Some Useful Probability Facts for Systems Programming
======
Probability problems come up a lot in systems programming, and Im using that term loosely to mean everything from operating systems programming and networking, to building large online services, to creating virtual worlds like in games. Heres a bunch of rough-and-ready probability rules of thumb that are deeply related and have many practical applications when designing systems.
## (\frac{1}{N}) chance tried (N) times
Retries are everywhere in systems programming. For example, imagine youre designing a world for a roleplaying game. When monsters in one particular forest are defeated, they have a small chance of dropping some special item. Suppose that chance is (\frac{1}{10}). Basic probability says that players are expected to need 10 victories before gaining a special item. But in probability, “expected value” is just a kind of average value, and theres no guarantee that players will get the item even if they do win 10 battles.
Whats a players chance of getting at least one special item after 10 battles? Lets just try getting a computer to calculate the probability of getting at least one success for (N) tries at a (\frac{1}{N}) chance, for a range of values of (N):
![Plot of probability of at least one success after trying a 1/N chance N times. The probability starts at 100% and drops, but quickly flattens out to a value just below 65%.][1]
Eyeballing the graph, it looks like the probability is roughly constant for (N) greater than about 3. In fact, it converges on (1 - e^{- 1}), where (e) is Eulers constant, 2.718281828459… This number (along with (e^{- 1})) is extremely common in engineering, so heres a table of practical values:
exp(-1.0) | 1.0-exp(-1.0)
---|---
36.7% | 63.2%
A bit over a third | A bit under two thirds
So, if you dont need an exact answer (and you often dont) you could just say that if the drop probability is (\frac{1}{10}), most players will get a special item within 10 battles, but (close enough) about a third wont. Because the monster battles are statistically independent, we can make a rough guess that about 1 in 9 players still wont have a special item after 20 battles. Also, roughly 60% wont after 5 battles because (0.6 \times 0.6 = 0.36), so 60% is close to the square root of 36.7%.
> If you have (\frac{1}{N}) chance of success, then youre more likely than not to have succeeded after (N) tries, but the probability is only about two thirds (or your favourite approximation to (1 - e^{- 1})). The value of (N) doesnt affect the approximation much as long as its at least 3.
Heres the proof: The chance of the player failing to get a special item after all (10) battles is ((\frac{9}{10})^{10} = .349), so the chance of getting at least one is (1 - .349 = .651). More generally, the chance of succeeding at least once is (1 - (1 - \frac{1}{N})^{N}), which converges on (1 - e^{- 1}) (by [one of the definitions of (e)][2]).
By the way, this rule is handy for quick mental estimates in board games, too. Suppose a player needs to get at least one 6 from rolling 8 six-sided dice. Whats probability of failure? Its about (\frac{1}{3}) for the first 6 dice, and (\frac{5}{6} \times \frac{5}{6}) for the remaining two, so all up its about (\frac{1}{3} \times \frac{25}{36} \approx \frac{8}{36} \approx \frac{1}{4}). A calculator says ((\frac{5}{6})^{8} = .233), so the rough approximation was good enough for gameplay.
## (N) balls in (N) buckets
Ill state this one up front:
> Suppose you throw (N) balls randomly (independently and one at a time) into (N) buckets. On average, a bit over a third ((e^{- 1})) of the buckets will stay empty, a bit over a third ((e^{- 1}) again) will have exactly one ball, and the remaining quarter or so ((1 - 2e^{- 1})) will contain multiple balls.
The balls-and-buckets abstract model has plenty of concrete engineering applications. For example, suppose you have a load balancer randomly assigning requests to 12 backends. If 12 requests come in during some time window, on average about 4 of the backends will be idle, only about 4 will have a balanced single-request load, and the remaining (average) 3 or 4 will be under higher load. Of course, all of these are averages, and therell be fluctuations in practice.
As another example, if a hash table has (N) slots, then if you put (N) different values into it, about a third of the slots will still be empty and about a quarter of the slots will have collisions.
If an online service has a production incident once every 20 days on average, then (assuming unrelated incidents) just over a third of 20-day periods will be dead quiet, just over a third will have the “ideal” single incident, while a quarter of 20-day periods will be extra stressful. In the real world, production incidents are even more tightly clustered because theyre not always independent.
This rule of thumb also hints at why horizontally scaled databases tend to have hot and cold shards, and why low-volume businesses (like consulting) can suffer from feast/famine patterns of customer demand.
Random allocation is much more unbalanced than we intuitively expect. A famous example comes from World War II when, late in the war, the Germans launched thousands of V-1 and V-2 flying bombs at London. Hitting a city with a rocket from across the Channel already required pushing 1940s technology to new limits, but several British analysts looked at maps of bomb damage and concluded that the Germans were somehow targetting specific areas of London, implying an incredible level of technological advancement. In 1946, however, an actuary did the proper statistical analysis and said that, no, [the clustering of bomb damage was simply what youd expect from random chance][3]. (That analysis is based on the [Poisson distribution][4], and the ratios in the rule for (N) balls and (N) buckets can be calculated from a Poisson distribution with (\lambda = \frac{N}{N} = 1).)
![25 points uniformly randomly placed on a 5x5 grid, showing spurious clustering. 8 boxes are empty, 10 boxes contain one point and 7 boxes contain two or more points.][5]
Random allocation only balances out when the number of “balls” is much larger than the number of “buckets”, i.e., when averaging over a large number of items, or a long time period. Thats one of the many reasons that engineering solutions that work well for large-scale FAANG companies can be problematic when used by companies that are orders of magnitude smaller.
Proving the third-third-quarter rule is pretty easy if you look at just one bucket. Each of the (N) balls represents a (\frac{1}{N}) chance of adding a ball to the bucket, so the chance of the bucket staying empty is just the (e^{- 1} \approx 36.7%) from the first rule. Linearity of expectation means we can combine the results for each bucket and say that 36.7% of _all_ buckets are expected to be empty, even though the bucket counts arent independent. Also, there are (N) possible ways of exactly one ball landing in the bucket, and each way requires one ball to fall in (with probability (\frac{1}{N})) and the other (N - 1) balls to miss (with probability (1 - \frac{1}{N})). So the probably of exactly one ball falling in is (\left. N \times \frac{1}{N} \times (1 - \frac{1}{N})^{N - 1}\rightarrow e^{- 1} \right.).
### Fixed points of random permutations
I dont think this rule has as many practical applications as the (N) balls/buckets rule, but its kind of a freebie.
Think of a battle game in which 6 players start from 6 spawn/home points. If the players play a second round, whats the chance that someone starts from the same point? Mathematically, thats asking about the chance of a random permutation having a “fixed point”.
> If a group of things are randomly shuffled, a bit of over a third ((e^{- 1})) of the time therell be no fixed points, a bit of over a third ((e^{- 1})) of the time therell be just one fixed point, and the remaining quarter or so of the time therell be two or more.
The number of fixed points in a random shuffle happens to approximate the same distribution as the number of balls in the buckets before, which can be [proven from first principles using the inclusion-exclusion principle][6]. But theres an even simpler proof for a related fact:
> A random permutation has exactly one fixed point on average, regardless of size.
If there are (N) things, each one has a (\frac{1}{N}) chance of ending up in its original location after the shuffle, so on average therell be (N \times \frac{1}{N} = 1) fixed points. Note that its impossible to get exactly one fixed point by shuffling a two element set (try it!) but 1 is still the average of 2 and 0. (“Average” doesnt always mean what we want it to mean.)
That proof might seem too simple, but its a demonstration of how powerful linearity of expectation is. Trying to calculate statistics for permutations can be tricky because the places any item can go depend on the places all the other items have gone. Linearity of expectation means we dont have to care about all the interactions as long as we only need to know the average. The average isnt always the most useful statistic to calculate, but its often the easiest by far.
## The coupon collectors problem
Lets look at [the common “loot box” mechanism][7]. Specifically, suppose there are 10 collector items (say, one for each hero in a franchise) that are sold in blind boxes. Lets take the fairest case in which there are no rare items and each item has an equal (\frac{1}{10}) chance of being in a given box. How many boxes will a collector buy on average before getting a complete set? This is the called the coupon collectors problem, and for 10 items the answer is about 29.
> The answer to the coupon collectors problem is a bit more than (N\ln N) (add (\frac{N}{2}) for some more accuracy).
((\ln N) is (\log) base (e), or just `log(N)` in most programming languages.)
The coupon collectors problem hints at why the loot box mechanism is so powerful. The (N) balls in (N) buckets rule tells us that the collector will have about two thirds of the items after buying 10 boxes. It feels like the collector is most of the way there, and it would be a shame to give up and let so much progress go to waste, but actually 10 boxes is only about a third of the expected number of boxes needed. Thats a simplistic model, but item rarity, variation of box type and (in computer games) making some items “unlockable” by completing sets of other items (or fulfilling other dependencies) only make it easier to get collectors to buy more than they originally expect.
The (N\ln N) rule is very rough, so heres a plot for comparison:
![Plot of approximations to the coupon collector's problem. N ln N underestimates significantly, but has the right growth rate. N ln N + N/2 still underestimates slightly, but the error is less than 10%. The 1:1 slope N is also included to show that, beyond small values of N, multiple times N purchases are needed to get all items on average.][8]
The exact value is rarely needed, but its useful to know that youll quickly need multiple times (N) trials to get all (N) hits. Any application of the (N) balls/buckets rule naturally extends to a coupon collectors problem (e.g., on average youll need to put over (N\ln N) items into a hash table before all (N) slots are full) but the coupon collectors problem comes up in other places, too. Often its tempting to use randomness to solve a problem statelessly, and then you find yourself doing a coupon collector problem. A cool example is [the FizzleFade effect in the classic 90s first-person shooter Wolfenstein 3D][9]. When the player character died, the screen would fill up with red pixels in what looks like random order. A simple and obvious way to implement that would be to plot red pixels at random coordinates in a loop, but filling the screen that way would be boring. With (320 \times 200 = 64000) pixels, most (~63.2%) of the screen would be filled red after 64000 iterations, but then the player would have to wait over (\ln(64000) \approx 11) times longer than that watching the last patches of screen fade away. The developers of Wolfenstein had to come up with a way to calculate a pseudo-random permutation of pixels on the screen, without explicitly storing the permutation in memory.
Heres a loose explanation of where the (\ln N) factor comes from: We know already that any pixel has approximately (\frac{1}{e}) chance of not being coloured by any batch of (N) pixel plots. So, after a batch of (N) pixel plots, the number of unfilled pixels goes down by a factor of (e) on average. If we assume we can multiply the average because its close enough to the geometric mean, the number of unfilled pixels will drop from (N) to something like (\frac{N}{e^{k}}) after (k) batches. That means the number of batches needed to go from (N) unfilled pixels to 1 is something like (\ln N), from the basic definition of logarithms.
In the computer age its easy to get an answer once we know we have a specific probability problem to solve. But rough rules like the ones in this post are still useful during the design phase, or for getting an intuitive understanding for why a system behaves the way it does.
--------------------------------------------------------------------------------
via: https://theartofmachinery.com/2020/01/27/systems_programming_probability.html
作者:[Simon Arneaud][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://theartofmachinery.com
[b]: https://github.com/lujun9972
[1]: https://theartofmachinery.com/images/systems_programming_probability/one_on_n_tried_n_times.svg
[2]: https://en.wikipedia.org/wiki/Characterizations_of_the_exponential_function#Characterizations
[3]: https://www.cambridge.org/core/journals/journal-of-the-institute-of-actuaries/article/an-application-of-the-poisson-distribution/F75111847FDA534103BD4941BD96A78E
[4]: https://en.wikipedia.org/wiki/Poisson_distribution
[5]: https://theartofmachinery.com/images/systems_programming_probability/london_v1_simulation.svg
[6]: https://golem.ph.utexas.edu/category/2019/11/random_permutations_part_1.html
[7]: https://www.pcgamer.com/au/the-evolution-of-loot-boxes/
[8]: https://theartofmachinery.com/images/systems_programming_probability/coupon_collector.svg
[9]: http://fabiensanglard.net/fizzlefade/index.php

View File

@ -0,0 +1,84 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Communication superstars: A model for understanding your organization's approach to new technologies)
[#]: via: (https://opensource.com/open-organization/20/1/communication-technology-superstars)
[#]: author: (Ron McFarland https://opensource.com/users/ron-mcfarland)
Communication superstars: A model for understanding your organization's approach to new technologies
======
Adopting new communication technologies can make your organization more
open. But are your people ready?
![Different cell phones][1]
Multiple books in [the _Open Organization_ series][2] discuss the many ways new communication technologies are changing the nature of both work and management. I've seen these changes firsthand during my nearly three decades working for Japanese corporations. Over time, I've been able to classify and characterize some of the impacts these technologies—particularly new telecommunication technologies and social media—are having on daily life in many organizations. And in April 2016, I shared those observations in an article called _[How new communication technologies are affecting peer-to-peer engagement][3]_.
But a lot can change in a little under four years.
[The Open Organization Ambassadors][4] have learned a great deal about the ways open principles are impacting organizational practices. In particular, we've developed an [Open Organization Definition][5] that specifies the five principles that distinguish open organizations from other types of organization—namely, more transparency, more inclusivity, greater adaptability, deeper collaboration and a sense of purpose teams/community. I've also delivered [a presentation on this topic][6] several times since 2016 and learned new insights along the way. So I'd like to update this article with a few comments that reflect those findings. And then, in a follow-up article, I'd like to offer readers some guidelines on how _they_ can determine their organization's level of comfort with communication technology and use it to increase their success relative to industry competitors.
Simply put: New communication technologies are affecting the way peer-to-peer decision-making practices function in organizations today. And that's affecting several important organizational dimensions: peers' transparency with each other when making decisions, the sense of inclusivity between members in decisions-making activities, their adaptability when situations change, their ability to collaborate with more individuals in the decision-making process, and their ability to build teams, groups, and communities to decide how to achieve their goals.
### Four approaches to communication technology
In Japan, I see companies that heavily promote today's communication technologies, as well as some that avoid them. Imagine four types of companies currently making use of today's communication technologies as they compete with other firms. These technologies are key, because they influence the environment in which certain peer-to-peer communities must work. It affects their collaboration and transparency with each other, their inclusivity with members they couldn't consider before because of location, their adaptability in a crisis, and their ability to build a sense of community among their members. This, in turn, affects members' enthusiasm, desire, and engagement—so _investment_ and _utilization_ are critical considerations. In fact, we can actually chart the four types of technology-adopters according to those two variables: investment and utilization.
Some companies are underinvested in new communication technologies, considering their needs and the relatively lower costs of these technologies today. And what they _do_ have, they're not using to capacity. I call these companies communication technology **"slow movers" (low investment/low utilization)**. Others buy whatever is available at any cost, but don't fully put what they've purchased to full use. I call these communication technology **"fashion followers" (high investment/low utilization)**. Still other companies invest in the very minimum amount of communication technology, but what they do have they use to full capacity. I call these communication technology **"conservative investors" (low investment/high utilization)**. Lastly, there are some companies that invest heavily in communication technology and work very hard to put it to full use. I call these communication technology **"communication superstars" (high investment/high utilization)**.
These "communication superstars" have the ideal environment for peer-to-peer, front-line discussions and decision making. They have greater collaboration and transparency with each other. They include members on their teams that they wouldn't (or couldn't) consider before because of location. They are more adaptable in a crisis. And they have the ability to build a stronger sense of community among their members. Unfortunately, in Japan, particularly among smaller companies, I'd say more than 70 percent are "slow movers" or "conservative investors." If companies would pay more attention to investing in communication technology, and simultaneously increase their efforts at training staff to use the technology to its full potential, then peer-to-peer, front-line employees could explode with creativity and better leverage all five of the open organization principles I mentioned above.
New communication technologies are affecting the way peer-to-peer decision-making practices function in organizations today.
These technologies affect four aspects of information today: volume, speed, quality, and distribution.
### Increased capacity for decision-making (volume)
In "communication superstar" environments, communication technologies can actually increase the amount of information that can be made available quickly. Gone are the days in which only researchers or professors have access to in-depth information. Now, front-line people can obtain volumes of information if they know what they're looking for. With more and greater in-depth information in communication superstar company environments, front-line people working there can have more educated discussions, leading to greater inclusivity and collaboration, which can allow them to make the types of decisions that only top management (supported by consultants and researchers) could have made in the past.
### Faster pace of decision-making and execution (speed)
New technologies in these "communication superstar" companies are leading to quicker information acquisition, feedback, and flow between the front-line members in the organizations, even if they are very widely disbursed.
Using the metaphor of adjusting the temperature of water coming out of a faucet, I would describe the effect this way: If you move the handle but the temperature changes very slowly, then finding the temperature you want becomes difficult, because the pace of temperature change is very slow, and differences between settings are difficult to determine. But if you move the handle and water temperature change is more immediate, you'll find that getting the correct temperature is much easier; you're moving quicker and making more rapid adjustments.
The same logic applies to peer-to-peer discussions and feedback. I have a five-minute-to-twenty-four-hour goal when replying to my worldwide customers. That means that if I receive an email from a customer (something that arrives on my desktop computer at home, my desktop computer in the office, or on my mobile phone), I like to reply within five minutes. This really surprises customers, as they're probably still sitting in front of their computer! In the worst case, I try to reply within 24 hours. This gives me a competitive advantage when attempting to get customers to work with me. Front-line, peer-to-peer communities in these "communication superstar" companies can have that same competitive advantage in making quality decisions and executing them faster. The capacity for speedier replies allows us to make more adjustments quicker. It keeps both employees and customers involved, motivated and engaged. They become more transparent with information, include members they hadn't considered before. They can adapt more rapidly when redirection is required. They can collaborate at a more in-depth level and can build tighter, more trusting project communities. Information arriving too slowly can cause people to "turn off" and direct their attention elsewhere. This weakens the passion, dedication, and engagement of the project.
### Toward wiser decisions (quality)
Information not only travels more quickly when the business communication channels are adequate, but it's also subjected to more scrutiny through greater group collaboration and inclusivity. People can share second opinions and gather additional empirical data using these technologies. Furthermore, new communication technologies allow employees and managers to deliver data in new ways. With my years in sales training around the world, I've learned that using multiple visual aids, infographics, and so forth have greatly enhanced communication when English language barriers could have impeded it. All this can lead to high levels of peer-to-peer, front-line engagement, as up-to-date status reports can be quickly distributed and easily understood, making everyone more responsive.
New technologies in these "communication superstar" companies are leading to quicker information acquisition, feedback, and flow between the front-line members in the organizations, even if they are very widely disbursed.
### Maximal reach (distribution)
Not long ago, teammates had to be physically close to one another and know each other well in order to communicate successfully. That's no longer the case, as communication channels can be developed with people literally all over the world. This has led to greater global inclusivity and collaboration. Good communication is the outcome of developing a trusting relationship. For me, building trust with people I've never met face-to-face has taken a bit longer, but I've done it with modern technology. Developing trust this way has led to great peer-to-peer transparency.
Let me explain. Good communication starts with initial contact, whether meeting someone in person or virtually (via social media or some telecommunication format). Over some period of time and through several exchanges, a relationship starts to develop, and a level of trust is reached. People evaluate one another's character and integrity, and they also judge each other's competence and skills. With this deepening of trust over time, greater communication and collaboration can evolve. At that point, open and in-depth discussions and transparency on very difficult, complex, and sometimes uncomfortable topics can take place. With the ability to communicate at that level, peer-to-peer discussions and decisions can be made. With today's communication technology, greater information exchange can be made among a group of widely disbursed members leading to an expanded team community. I currently have approximately 20 customers around the world. Some I have never met in person; most I have just met in person once. Being stationed in Japan can make regular get-togethers with Europeans and Americans rather difficult. Fortunately, with today's communication technology, I can find solutions for many problems without physically getting together, as I have built a trusting relationship with them.
### Concluding comments
With all the benefits of this "communication superstar" working environment, in open organizations that promote peer-to-peer discussions, decision-making and management, I recommend the other three groups to move in that direction. The "slow movers" more than likely have managerial barriers to open information exchange. They should be convinced of the benefits of a more opened organization and the value of greater information exchange. If they don't improve their communication environment, they may lose their competitive advantage. The "fashion followers" should more carefully study their communication needs and time their investments with their in-company training capacities. The "conservative investors" should study their communication bottlenecks and find the technologies that are available to eliminate them. That's the path to super-stardom.
As I mentioned at the beginning of this article, it's important to determine exactly which of these categories a company falls into with regard to communication technology ["slow movers" (low investment/low utilization), "fashion followers" (high investment/low utilization), "conservative investors" (low investment/high utilization) or "communication superstars" (high investment/high utilization)] against their competitors. Therefore, I would like to address that issue in a future article.
--------------------------------------------------------------------------------
via: https://opensource.com/open-organization/20/1/communication-technology-superstars
作者:[Ron McFarland][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/ron-mcfarland
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/BUSINESS_mobilemashup3.png?itok=v1gVY8RJ (Different cell phones)
[2]: https://opensource.com/open-organization/resources/book-series
[3]: https://opensource.com/open-organization/16/4/how-new-communication-technologies-are-affecting-peer-peer-engagement
[4]: https://opensource.com/open-organization/resources/meet-ambassadors
[5]: https://opensource.com/open-organization/resources/open-org-definition
[6]: https://www.slideshare.net/RonMcFarland1/competitive-advantage-through-digital-investment-utilization?qid=9fbb4c4b-f2c2-4468-9f0a-3ebaa6efc91d&v=&b=&from_search=1

View File

@ -1,496 +0,0 @@
[#]: collector: (lujun9972)
[#]: translator: (laingke)
[#]: 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]
译者:[laingke](https://github.com/laingke)
校对:[校对者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

@ -1,130 +0,0 @@
[#]: collector: (lujun9972)
[#]: translator: (robsean)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (How to Set or Change Timezone in Ubuntu Linux [Beginners Tip])
[#]: via: (https://itsfoss.com/change-timezone-ubuntu/)
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
How to Set or Change Timezone in Ubuntu Linux [Beginners Tip]
======
[When you install Ubuntu][1], it asks you to set timezone. If you chose a wrong timezone or if you have moved to some other part of the world, you can easily change it later.
### How to change Timezone in Ubuntu and other Linux distributions
There are two ways to change the timezone in Ubuntu. You can use the graphical settings or use the timedatectl command in the terminal. You may also change the /etc/timezone file directly but I wont advise that.
Ill show you both graphical and terminal way in this beginners tutorial:
* [Change timezone in Ubuntu via GUI][2] (suitable for desktop users)
* [Change timezone in Ubuntu via command line][3] (works for both desktop and servers)
![][4]
#### Method 1: Change Ubuntu timezone via terminal
[Ubuntu][5] or any other distributions using systemd can use the timedatectl command to set timezone in Linux terminal.
You can check the current date and timezone setting using timedatectl command without any option:
```
[email protected]:~$ timedatectl
Local time: Sat 2020-01-18 17:39:52 IST
Universal time: Sat 2020-01-18 12:09:52 UTC
RTC time: Sat 2020-01-18 12:09:52
Time zone: Asia/Kolkata (IST, +0530)
System clock synchronized: yes
systemd-timesyncd.service active: yes
RTC in local TZ: no
```
As you can see in the output above, my system uses Asia/Kolkata. It also tells me that it is 5:30 hours ahead of GMT.
To set a timezone in Linux, you need to know the exact timezone. You must use the correct format of the timezone (which is Continent/City).
To get the timezone list, use the _list-timezones_ option of _timedatectl_ command:
```
timedatectl list-timezones
```
It will show you a huge list of the available time zones.
![Timezones List][6]
You can use the up and down arrow or PgUp and PgDown key to move between the pages.
You may also grep the output and search for your timezone. For example, if you are looking for time zones in Europe, you may use:
```
timedatectl list-timezones | grep -i europe
```
Lets say you want to set the timezone to Paris. The timezone value to be used here is Europe/Paris:
```
timedatectl set-timezone Europe/Paris
```
It wont show any success message but the timezone is changed instantly. You dont need to restart or log out.
Keep in mind that though you dont need to become root user and use sudo with the command but your account still need to have admin rights in order to change the timezone.
You can verify the changed time and timezone by using the [date command][7]:
```
[email protected]:~$ date
Sat Jan 18 13:56:26 CET 2020
```
#### Method 2: Change Ubuntu timezone via GUI
Press the super key (Windows key) and search for Settings:
![Applications Menu Settings][8]
Scroll down a little and look for Details in the left sidebar:
![Go to Settings -> Details][9]
In Details, youll fine Date &amp; Time in the left sidebar. Here, you should turn off Automatic Time Zone option (if it is enabled) and then click on the Time Zone:
![In Details -> Date & Time, turn off the Automatic Time Zone][10]
When you click the Time Zone, it will open an interactive map and you can click on the geographical location of your choice and close the window.
![Select a timezone][11]
You dont have to do anything other than closing this map after selecting the new timezone. No need to logout or [shutdown Ubuntu][12].
I hope this quick tutorial helped you to change timezone in Ubuntu and other Linux distributions. If you have questions or suggestions, please let me know.
--------------------------------------------------------------------------------
via: https://itsfoss.com/change-timezone-ubuntu/
作者:[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/install-ubuntu/
[2]: tmp.bHvVztzy6d#change-timezone-gui
[3]: tmp.bHvVztzy6d#change-timezone-command-line
[4]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/01/Ubuntu_Change-_Time_Zone.png?ssl=1
[5]: https://ubuntu.com/
[6]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/01/timezones_in_ubuntu.jpg?ssl=1
[7]: https://linuxhandbook.com/date-command/
[8]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/08/applications_menu_settings.jpg?ssl=1
[9]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/01/settings_detail_ubuntu.jpg?ssl=1
[10]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/01/change_timezone_in_ubuntu.jpg?ssl=1
[11]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/01/change_timezone_in_ubuntu_2.jpg?ssl=1
[12]: https://itsfoss.com/schedule-shutdown-ubuntu/

View File

@ -0,0 +1,77 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (How to get started with test-driven development)
[#]: via: (https://opensource.com/article/20/1/test-driven-development)
[#]: author: (Alex Bunardzic https://opensource.com/users/alex-bunardzic)
How to get started with test-driven development
======
Learn when, what, and how to test in a TDD system.
![Penguin driving a car with a yellow background][1]
I am often approached by software developers who are on board with the switch to test-driven development (TDD). They understand that describing expectations first and then writing code to meet those expectations is the best way to write software. And they agree that writing tests first does not introduce any overhead since they must write tests anyway. Still, they find themselves stuck, not being clear on what to test, when to test it, and how to test it. This article will answer those questions.
### First, an analogy
Imagine you're working on a team that has been asked to build a race car. The goal is to deliver a product that will enable a crew to drive the car from one city (say, Portland, Oregon) to another city (say, Seattle, Washington).
Your team could go about designing and building that car in several different ways. One way would be to handcraft a unique, monolithic vehicle where all parts are home-grown and tightly coupled. Another way would be to use only prefabricated parts and stitch them together. And there are many other permutations of these two extreme approaches.
Suppose your team goes with hand-building the constituent components of the race car. A car needs a battery to run. For the purposes of this analogy, focus on the custom-made car battery. How would you go about testing it?
### Testing strategies
One way to the test custom-made car battery would be to hire a testing crew, ship the car with the battery to Portland, and then get the testing crew to drive the car from Portland to Seattle. If the car arrives in Seattle, you can confirm that, yes, the car battery functions as expected.
Another way to test the custom-made car battery would be to install it in the car and see if the engine turns over. If the engine starts, you can confirm that, yes, the car battery functions as expected.
Still another way would be to use a voltmeter and connect the positive (+) and the negative (-) terminals to see if the voltmeter registers voltage output in the range of 12.6 to 14.7 volts. If it does, you can confirm that, yes, the car battery functions as expected.
The above three hypothetical examples illustrate how different ways of testing the car battery align with three categories of testing strategies:
1. Employing the testing crew to drive the car from Portland to Seattle aligns with the **system or end-to-end testing strategy**.
2. Installing the battery in the car and verifying if the engine starts aligns with the **integration testing strategy**.
3. Measuring the voltage output of the car battery to verify if it falls within the expected range aligns with the **unit testing strategy**.
### TDD is all about unit testing
I hope these examples provide simple guiding principles for discerning between unit, integration, and system end-to-end testing.
Keeping those guidelines in mind, it is very important _never_ to include integration nor system tests in your TDD practice. In TDD, the expected outcomes are always micro-outcomes. Measuring the voltage output of a car battery is a good example of a micro-outcome. A car battery is a unit of functionality that cannot easily be broken down into a few smaller units of functionality. As such, it is a perfect candidate for writing a unit test (i.e., describing the expected measurable output).
You could also write a description of your expectations in the form of: "I expect the car engine to start on the event of turning the key." However, that description wouldn't qualify as a unit test. Why? Because the car is not at a sufficiently low level of granularity. In software engineering parlance, the car does not embody the [single responsibility principle][2] (SRP).
And of course, while you could also write a description of your expectation in the form of: "I expect the car, which begins its journey in Portland, to arrive in Seattle after x number of hours," that description wouldn't qualify as a unit test. Many aspects of the car's journey from Portland to Seattle could be measured, so such end-to-end descriptions should never be part of TDD.
### Simulating real conditions
In the case of a car battery, just by using a simple voltmeter, you can simulate the operational environment of a car battery. You don't have to go into the expense of providing a full-blown experience (e.g., a fully functional car, a long and treacherous trip from Portland to Seattle) to be convinced that, indeed, your car battery functions as expected.
That's the beauty of unit testing's simplicity. It's easy to simulate, easy to measure, easy to leave the exercise being convinced that everything works as expected.
So what is it that enables this magic? The answer is simple—the _absence of dependencies_. A car battery does not depend on anything related to the automobile. Nor does it depend on anything related to the road trip from Portland to Seattle. Keep in mind that as your decomposed system components become less and less dependent on other components, your solution gets more and more reliable.
### Conclusion
The art of software engineering consists of the ability to decompose complex systems into small constituent elements. Each individual element must be reduced to the smallest possible surface. Once you reach that point in your process of decomposing a system, you can quite easily focus your attention on describing your expectations about the output of each unit. You can do that by following a formalized pattern, in which you first describe the _preconditions_ (i.e., given that such-and-such values are present), the _action_ (i.e., given that such-and-such _event_ arrives), and the _outcome_ or the _post-condition_ (i.e., you expect such-and-such values to be measurable).
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/1/test-driven-development
作者:[Alex Bunardzic][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/alex-bunardzic
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/car-penguin-drive-linux-yellow.png?itok=twWGlYAc (Penguin driving a car with a yellow background)
[2]: https://en.wikipedia.org/wiki/Single_responsibility_principle

View File

@ -0,0 +1,157 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Managing processes on Linux with kill and killall)
[#]: via: (https://opensource.com/article/20/1/linux-kill-killall)
[#]: author: (Jim Hall https://opensource.com/users/jim-hall)
Managing processes on Linux with kill and killall
======
Know how to terminate processes and reclaim system resources with the
ps, kill, and killall commands.
![Penguin with green background][1]
In Linux, every program and daemon is a "process." Most processes represent a single running program. Other programs can fork off other processes, such as processes to listen for certain things to happen and then respond to them. And each process requires a certain amount of memory and processing power. The more processes you have running, the more memory and CPU cycles you'll need. On older systems, like my seven-year-old laptop, or smaller computers, like the Raspberry Pi, you can get the most out of your system if you keep an eye on what processes you have running in the background.
You can get a list of running processes with the **ps** command. You'll usually want to give **ps** some options to show more information in its output. I like to use the **-e** option to see every process running on my system, and the **-f** option to get full details about each process. Here are some examples:
```
$ ps
    PID TTY          TIME CMD
  88000 pts/0    00:00:00 bash
  88052 pts/0    00:00:00 ps
  88053 pts/0    00:00:00 head
[/code] [code]
$ ps -e | head
    PID TTY          TIME CMD
      1 ?        00:00:50 systemd
      2 ?        00:00:00 kthreadd
      3 ?        00:00:00 rcu_gp
      4 ?        00:00:00 rcu_par_gp
      6 ?        00:00:02 kworker/0:0H-events_highpri
      9 ?        00:00:00 mm_percpu_wq
     10 ?        00:00:01 ksoftirqd/0
     11 ?        00:00:12 rcu_sched
     12 ?        00:00:00 migration/0
[/code] [code]
$ ps -ef | head
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 13:51 ?        00:00:50 /usr/lib/systemd/systemd --switched-root --system --deserialize 36
root           2       0  0 13:51 ?        00:00:00 [kthreadd]
root           3       2  0 13:51 ?        00:00:00 [rcu_gp]
root           4       2  0 13:51 ?        00:00:00 [rcu_par_gp]
root           6       2  0 13:51 ?        00:00:02 [kworker/0:0H-kblockd]
root           9       2  0 13:51 ?        00:00:00 [mm_percpu_wq]
root          10       2  0 13:51 ?        00:00:01 [ksoftirqd/0]
root          11       2  0 13:51 ?        00:00:12 [rcu_sched]
root          12       2  0 13:51 ?        00:00:00 [migration/0]
```
The last example shows the most detail. On each line, the UID (user ID) shows the user that owns the process. The PID (process ID) represents the numerical ID of each process, and PPID (parent process ID) shows the ID of the process that spawned this one. In any Unix system, processes count up from PID 1, the first process to run once the kernel starts up. Here, **systemd** is the first process, which spawned **kthreadd**. And **kthreadd** created other processes including **rcu_gp**, **rcu_par_gp**, and a bunch of other ones.
### Process management with the kill command
The system will take care of most background processes on its own, so you don't need to worry about them. You should only have to get involved in managing any processes that you create, usually by running applications. While many applications run one process at a time (think about your music player or terminal emulator or game), other applications might create background processes. Some of these might keep running when you exit the application so they can get back to work quickly the next time you start the application.
Process management is an issue when I run Chromium, the open source base for Google's Chrome browser. Chromium works my laptop pretty hard and fires off a lot of extra processes. Right now, I can see these Chromium processes running with only five tabs open:
```
$ ps -ef | fgrep chromium
jhall      66221   [...]  /usr/lib64/chromium-browser/chromium-browser [...]
jhall      66230   [...]  /usr/lib64/chromium-browser/chromium-browser [...]
[...]
jhall      66861   [...]  /usr/lib64/chromium-browser/chromium-browser [...]
jhall      67329   65132  0 15:45 pts/0    00:00:00 grep -F chromium
```
I've omitted some lines, but there are 20 Chromium processes and one **grep** process that is searching for the string "chromium."
```
$ ps -ef | fgrep chromium | wc -l
21
```
But after I exit Chromium, those processes remain open. How do you shut them down and reclaim the memory and CPU that those processes are taking up?
The **kill** command lets you terminate a process. In the simplest case, you tell **kill** the PID of what you want to stop. For example, to terminate each of these processes, I would need to execute the **kill** command against each of the 20 Chromium process IDs. One way to do that is with a command line that gets the Chromium PIDs and another that runs **kill** against that list:
```
$ ps -ef | fgrep /usr/lib64/chromium-browser/chromium-browser | awk '{print $2}'
66221
66230
66239
66257
66262
66283
66284
66285
66324
66337
66360
66370
66386
66402
66503
66539
66595
66734
66848
66861
69702
$ ps -ef | fgrep /usr/lib64/chromium-browser/chromium-browser | awk '{print $2}' &gt; /tmp/pids
$ kill $( cat /tmp/pids)
```
Those last two lines are the key. The first command line generates a list of process IDs for the Chromium browser. The second command line runs the **kill** command against that list of process IDs.
### Introducing the killall command
A simpler way to stop a bunch of processes all at once is to use the **killall** command. As you might guess by the name, **killall** terminates all processes that match a name. That means we can use this command to stop all of our rogue Chromium processes. This is as simple as:
```
`$ killall /usr/lib64/chromium-browser/chromium-browser`
```
But be careful with **killall**. This command can terminate any process that matches what you give it. That's why I like to first use **ps -ef** to check my running processes, then run **killall** against the exact path to the command that I want to stop.
You might also want to use the **-i** or **\--interactive** option to ask **killall** to prompt you before it stops each process.
**killall** also supports options to select processes that are older than a specific time using the **-o** or **\--older-than** option. This can be helpful if you discover a set of rogue processes that have been running unattended for several days, for example. Or you can select processes that are younger than a specific time, such as runaway processes you recently started. Use the **-y** or **\--younger-than** option to select these processes.
### Other ways to manage processes
Process management can be an important part of system maintenance. In my early career as a Unix and Linux systems administrator, the ability to kill escaped jobs was a useful tool to keep systems running properly. You may not need to kill rogue processes in a modern Linux desktop, but knowing **kill** and **killall** can help you when things eventually go awry.
You can also look for other ways to manage processes. In my case, I didn't really need to use **kill** or **killall** to stop the background Chromium processes after I exited the browser. There's a simple setting in Chromium to control that:
![Chromium background processes setting][2]
Still, it's always a good idea to keep an eye on what processes are running on your system and know how to manage them when needed.
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/1/linux-kill-killall
作者:[Jim Hall][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/jim-hall
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/linux_penguin_green.png?itok=ENdVzW22 (Penguin with green background)
[2]: https://opensource.com/sites/default/files/uploads/chromium-settings-continue-running.png (Chromium background processes setting)

View File

@ -0,0 +1,112 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Use Vim to manage your task list and access Reddit and Twitter)
[#]: via: (https://opensource.com/article/20/1/vim-task-list-reddit-twitter)
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
Use Vim to manage your task list and access Reddit and Twitter
======
Handle your to-do list and get social from the text editor in the
seventeenth in our series on 20 ways to be more productive with open
source in 2020.
![Chat via email][1]
Last year, I brought you 19 days of new (to you) productivity tools for 2019. This year, I'm taking a different approach: building an environment that will allow you to be more productive in the new year, using tools you may or may not already be using.
### Doing (almost) all the things with Vim, part 2
In [yesterday's article][2], you started reading mail and checking your calendars with Vim. Today, you're going to do even more. First, you'll take care of your task tracking, and then you'll get social, directly in the Vim text editor.
#### Track your to-do's in Vim with todo.txt-vim
![to-dos and Twitter with Vim][3]
Editing a text-based to-do file with Vim is a natural fit, and the [todo.txt-vim][4] package makes it even easier. Start by installing the todo.txt-vim package:
```
git clone <https://github.com/freitass/todo.txt-vim> ~/.vim/bundle/todo.txt-vim
vim ~/path/to/your/todo.txt
```
Todo.txt-vim automatically recognizes files ending in todo.txt and done.txt as [todo.txt][5] files. It adds key bindings specific to the todo.txt format. You can mark things "done" with **\x**, set them to the current date with **\d**, and change the priority with **\a**, **\b**, and **\c**. You can bump the priorities up (**\k**) or down (**\j**) and sort (**\s**) based on project (**\s+**), context (**\s@**), or date (**\sd**). And when you are finished, you can close and save the file like normal.
The todo.txt-vim package is a great addition to the [todo.sh program][6] I wrote about a few days ago, and with the [todo edit][7] add-on, it can really supercharge your to-do list tracking.
#### Read Reddit in Vim with vim-reddit
![Reddit in Vim][8]
Vim also has a nice add-on for [Reddit][9] called [vim-reddit][10]. It isn't as nice as [Tuir][11], but for a quick review of the latest posts, it works really well. Start by installing the bundle:
```
git clone <https://github.com/DougBeney/vim-reddit.git> ~/.vim/bundle/vim-reddit
vim
```
Now type **:Reddit** and the Reddit frontpage will load. You can load a specific subreddit with **:Reddit name**. Once the article list is onscreen, navigate with the arrow keys or scroll with the mouse. Pressing **o** will open the article in Vim (unless it is a media post, in which case it opens a browser), and pressing **c** brings up the comments. If you want to go right to the page, press **O** instead of **o**. Going back a screen is as easy as **u**. And when you are done with Reddit, type **:bd**. The only drawback is vim-reddit cannot log in or post new stories or comments. Then again, sometimes that is a good thing.
#### Tweet from Vim with twitvim
![Twitter in Vim][12]
And last, we have [twitvim][13], a Vim package for reading and posting to Twitter. This one takes a bit more to set up. Start by installing twitvim from GitHub:
```
`git clone https://github.com/twitvim/twitvim.git ~/.vim/bundle/twitvim`
```
Now you need to edit the **.vimrc** file and set some options. These help the plugin know which libraries it can use to talk to Twitter. Run **vim --version** and see what languages have a **+** next to them—those languages are supported by your copy of Vim.
![Enabled and Disabled things in vim][14]
Since mine says **+perl -python +python3**, I know I can enable Perl and Python 3, but not Python 2 (python).
```
" TwitVim Settings
let twitvim_enable_perl = 1
" let twitvim_enable_python = 1
let twitvim_enable_python3 = 1
```
Now you can start up Vim and log into Twitter by running **:SetLoginTwitter**, which launches a browser window asking you to authorize VimTwit as an application with access to your account. Once you enter
the supplied PIN into Vim, you're good to go.
Twitvim's commands are not as simple as in the other packages. To load up the timeline of your friends and followers, type in **:FriendsTwitter**. To list your mentions and replies, use **:MentionsTwitter**. Posting a new tweet is **:PosttoTwitter &lt;Your message&gt;**. You can scroll through the list and reply to a specific tweet by typing **\r**, and you can start a direct message with someone using **\d**.
And there you have it; you're doing (almost) all the things in Vim!
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/1/vim-task-list-reddit-twitter
作者:[Kevin Sonney][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/ksonney
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/email_chat_communication_message.png?itok=LKjiLnQu (Chat via email)
[2]: https://opensource.com/article/20/1/send-email-and-check-your-calendar-vim
[3]: https://opensource.com/sites/default/files/uploads/productivity_17-1.png (to-dos and Twitter with Vim)
[4]: https://github.com/freitass/todo.txt-vim
[5]: http://todotxt.org
[6]: https://opensource.com/article/20/1/open-source-to-do-list
[7]: https://github.com/todotxt/todo.txt-cli/wiki/Todo.sh-Add-on-Directory#edit-open-in-text-editor
[8]: https://opensource.com/sites/default/files/uploads/productivity_17-2.png (Reddit in Vim)
[9]: https://reddit.com
[10]: https://github.com/DougBeney/vim-reddit
[11]: https://opensource.com/article/20/1/open-source-reddit-client
[12]: https://opensource.com/sites/default/files/uploads/productivity_17-3.png (Twitter in Vim)
[13]: https://github.com/twitvim/twitvim
[14]: https://opensource.com/sites/default/files/uploads/productivity_17-4.png (Enabled and Disabled things in vim)

View File

@ -0,0 +1,68 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (How I had a nerdy date night with StreetComplete quests)
[#]: via: (https://opensource.com/article/20/1/streetcomplete-crowdsource-maps)
[#]: author: (Jess Weichler https://opensource.com/users/cyanide-cupcake)
How I had a nerdy date night with StreetComplete quests
======
Find an adventure in your own backyard with this fun app.
![A map with a route highlighted][1]
StreetComplete is an Android app that makes it fun and easy to contribute to open data by completing quests.
Quests are used to fill in incomplete or inaccurate information on [OpenStreetMap][2], an open data project dedicated to mapping the world through crowdsourcing. Anyone can contribute to the map and, thanks to free culture and open source licenses, that data can then be used by anyone for anything, from video games to custom map applications and artwork.
![hands holding phone][3]
My first intro to StreetComplete was on a charmingly unique date night with my partner. Instead of dinner and a movie, we explored the streets of our town, both the familiar and unfamiliar, answering questions about features of topography, shopfronts, pedestrian crossing, and more. We got to see our town in a new light, and we felt we were ultimately helping others discover it along with us.
If this sounds like something youd like to get involved with, its super simple to get started. Just follow the steps below:
1. [Download the app][4] to your phone from F-Droid or Google Play. Its licensed under GPLv3.
2. Allow StreetComplete to access your devices location.
3. Click the menu in the upper right corner, and select Settings.
4. In the Settings menu, select Authorize OSM access. This will open OpenStreetMap in your browser, where you can register for an account or login if you already have one.
5. Authorize access to your account.
Now youre ready to go!
### Completing quests
To complete quests, walk around the area of your choosing. Quests appear as pins on the map. Symbols inside pins denote the type of task, such as a wheelchair for an accessibility quest or leaf for a plant-based quest. Quests involve simple questions about various features, with clear multiple choice answers and visuals when necessary.
Quests can be chosen at random, though the app will question your response if you try to complete a quest when you are not nearby. I live in a small town, so I especially enjoyed quests that required us to ask questions of shop owners because it allowed us to connect with the community in real life while contributing to the global community online.
![StreetComplete map image][5]
If you live in a mobile deadzone or have a limited mobile plan, you can still have fun questing for map data; StreetComplete has an offline mode. To use it, activate the offline download option in the app settings menu. Once your region has downloaded, perform a search for nearby quests, then go out and explore.
When you are back online, the data youve input as quest responses are uploaded to the OpenStreetMap servers.
StreetComplete is a great way to investigate new areas or even locations you may already be somewhat familiar with. With its graphical, flat design and simple quests, it makes a perfect activity for couples, friends, and families to complete together.
Maps touch our lives daily. Whether you are trying to find a nearby point of interest or directions...
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/1/streetcomplete-crowdsource-maps
作者:[Jess Weichler][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/cyanide-cupcake
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/map_route_location_gps_path.png?itok=RwtS4DsU (A map with a route highlighted)
[2]: https://www.openstreetmap.org
[3]: https://opensource.com/sites/default/files/uploads/image1_street.png (hands holding phone)
[4]: https://github.com/westnordost/StreetComplete
[5]: https://opensource.com/sites/default/files/uploads/image2_street.jpeg (StreetComplete map image)

View File

@ -0,0 +1,175 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (How I teach physics using open source tools)
[#]: via: (https://opensource.com/article/20/1/teach-physics-open-source)
[#]: author: (Cristiano L. Fontana https://opensource.com/users/cristianofontana)
How I teach physics using open source tools
======
A roundup of open source tools ideal for teaching physics (and other
subjects).
![Person reading a book and digital copy][1]
The nice aspect of being a physicist and a researcher is the openness of our community. There is a lot of collaboration and sharing of ideas (especially during coffee breaks). We also tend to share the software we write. Since we are very picky about algorithms, we want to modify other peoples code to fix the obvious errors that we find. It feels frustrating when I have to use proprietary tools since I cannot understand their inner workings. Having grown up professionally in such an environment, open source has been my go-to solution for all the software I use.
When I became the regular teacher of the Physics and Biophysics course at the [medical school][2] at my [university][3], I decided to use only open source software to prepare my lectures. Here is my experience so far and the solutions I found.
### Study material
Teaching is not easy. You should first understand the subject and then figure out how to communicate with somebody that knows nothing about the subject; therefore, it is of paramount importance to study the subject in depth and prepare the lectures well in advance. There are countless books about physics, but there are also some interesting, freely available resources. Most of these do not count as open source, as they cannot be modified, but they are useful anyways.
* [HyperPhysics][4] may have an outdated look, but it is a treasure trove of interesting concepts and insights by Carl R. Nave, Department of Physics and Astronomy Georgia State University.
* [Open Source Physics][5] has a fabulous collection of applets and support material. I met some of the maintainers at various conferences, and they are remarkable people.
* [OpenStax][6] is a nonprofit educational initiative based at Rice University that publishes textbooks that are free online. They have a good library and several works about physics in their [scientific section][7].
* [Open Textbook Library][8] provides a catalog of free textbooks with a [physics section][9] as well. Some of the titles have reviews by users.
* [Motion Mountain][10] is a collection of books about physics in general by C. Schiller that has also been translated into several languages.
* [Light and Matter][11] is another collection of writings about different aspects of physics, all authored by B. Crowell of Fullerton College, CA.
* [Wikipedia][12], what more can I say?
### Lecturing style
Before preparing my support material, I had to decide whether I preferred to use the blackboard or slideshows during the lectures. I opted to use both with the idea of showing hard-to-draw graphics in the slideshows and writing down equations on the blackboard. Eventually, the slideshows became much more prevalent. I use them as the draft of my lecture, helping me to keep track of what I want to say. I also added the mathematical proofs that I want to show to have a correct reference during the lecture.
Instead of using a blackboard, I ended up using a [graphics tablet][13] for all the notes I write during the lectures. I use the tablet for three main purposes: to draw additional drawings to explain myself better, to write down equations and proofs, and to write down the key messages that I want my students to remember. Even if what I write is already on the slideshows, actually writing it by hand during the lectures gives the students the time to write it down in their notes. After the lectures, I share, on my website, both the slideshows and my notes.
![Figure: Example of notes taken during class with the graphics tablet and Krita][14]
Figure: Example of notes taken during class with the graphics tablet and Krita
### Material preparation
#### Slideshows
Since math is the language of physics, I needed a practical way to write down equations in my slideshows. Probably, the best tool for that is [LaTeX][15], but it was designed to typeset books and not slides. Luckily, there is the [Beamer class][16] that allows you to typeset slideshows with LaTeX. The resulting file is a very portable PDF. The layout is nice and clean and forces me not to overstuff each slide. From the same source code, I can prepare two versions of the file. The lecture version follows the guidelines of the universitys [corporate identity][17] (_i.e.,_ with a thick red border), while the handout version has a cleaner layout (_e.g.,_ without the thick borders), thus allowing it to be printed without wasting printer toner. I have also seen students taking notes directly on the PDFs of the handouts on their tablets and computers.
The only drawback of using LaTeX and Beamer is the impossibility of embedding videos in the produced presentation. I, therefore, have to keep as a separate file the occasional videos that I show during class.
![Figure: Examples of slides created with LaTeX and Beamer][18]
Figure: Examples of slides created with LaTeX and Beamer
![Figure: Examples of slides created with LaTeX and Beamer][19]
Figure: Examples of slides created with LaTeX and Beamer
#### Images and diagrams
Something that I am careful about is the licensing of the graphics I use. As such, I never use graphics that do not allow me to redistribute my modifications. I drew most of the images in my slideshows. If I use other peoples work, I always reference it in my slide.
I prefer to use [vector graphics][20] whenever practicable because they can be easily modified and adjusted afterward. I use the exceptional [Inkscape][21] for my vector graphics. On the other hand, for my [raster graphics][22], I use [GIMP][23]. When I need a 3D looking diagram, I use [Blender][24] to draw the scene; then I trace the rendered image with Inkscape to convert it to vectorial. I recently discovered [FreeCAD][25], which has the striking feature that it can directly export the 3D scene to some vectorial format. I can then adjust the image with Inkscape without having to trace the raster image.
In all my diagrams, I am trying to keep a consistent look, and therefore I limit myself to a 10-[color palette][26], both from [d3][27] and [matplotlib][28]. I also use the same palette in my slides to highlight quantities in reference to the illustrations. To produce [plots][29] and [graphs][30], I write Python scripts and employ the matplotlib graphical library.
![Figure: Diagram example created with Inkscape by tracing a Blender 3D diagram][31]
Figure: Diagram example created with Inkscape by tracing a Blender 3D diagram
#### Multimedia support
I have prepared a few pages with applets that demonstrate some phenomena that I describe during my lectures (e.g., [modeling radioactive decay with dice][32]). I opted to offer these applets on my institutional webpage to easily reach all the students instead of requiring them to install software to run them. The necessary choice was to employ [JavaScript][33] and some supporting libraries, such as [jQuery][34] for compatibility between browsers, [MathJax][35] for typesetting math in the webpages, or [d3][27] for graphics display. Since my institution does not provide the capability of writing dynamic webpages, I am using [Jekyll][36], which is a static site generator. Jekyll allows me to have a consistent look and feel across all the pages without having to write HTML code.
![Figure: Dice modeling radioactive decay, image of the interactive simulation][37]
Figure: Dice modeling radioactive decay, image of the [interactive simulation][32]
### Lecturing software
Since my slideshows are PDF files, to show them during the lecture, I use the [default document viewer][38] of my [GNOME 3][39] desktop environment. There is also the alternative of using [Okular][40], which allows annotating the PDFs, but I prefer not to use it, as the annotations would not be carried over to the handouts. In conjunction with the graphical tablet, I use the excellent painting program [Krita][41]. I use the image layers as new pages of my notes. This approach is more practical during the lecture than creating a series of new files. I can also duplicate layers and edit them or load vectorial images and draw over them. Krita has the possibility of writing custom [Python plugins][42], so I prepared a script that exports a PDF file with a new page for each layer.
![Figure: Screenshot of Krita used in class to write notes][43]
Figure: Screenshot of Krita used in class to write notes
When we go through exercises in class, I use the calculator [Qalculate][44] to obtain numerical results. Its particular feature is that it can perform calculations with units associated with the numbers. I can focus more on the exercise resolution than on the units conversions. This is a double-edged sword, though, as the students would not learn how to do the conversions themselves. Therefore, I normally start to use Qalculate halfway through the course. [wxMaxima][45] can also support exercise resolution, symbolically solving some difficult equations.
![Figure: Screenshot of Qalculate][46]
Figure: Screenshot of Qalculate
### Video lectures
Sometimes I offer streaming lectures on YouTube, or I upload a video with additional mini-lectures. It has happened that the students have wanted a more in-depth explanation of some subjects. Offering these as a video allows them to take their time to listen and understand the subjects. For these videos, I use [OBS studio][47], which can record or directly stream videos to YouTube. OBS can put on the video scene the screen image and some additional video sources, such as a web camera. To edit the videos, I have been using [OpenShot][48].
![Figure: Screenshot of OBS studio recording the screen][49]
Figure: Screenshot of OBS studio recording the screen
### Conclusions
This is the set of open source tools that I have been using to prepare and support my lectures. Over the years, I changed some of them whenever I discovered some better fitting tools or if I changed my lecturing style. To be frank, due to laziness, one of the requirements for all the tools is that they have to be easily installable. I use [Fedora][50] on my laptop, and its repository has packages for all this software. On the [CentOS][51] installation of my desktop computer, I had worse luck. For instance, Krita and OBS are available only through [Flatpak][52].
Writing this article just made me realize how many tools I am actively using for my lectures. Maybe there are some all-in-one solutions, such as [LibreOffice Impress][53], but I am very satisfied with the results I am getting. Besides, all this software has other useful applications.
Leave comments if you have questions.
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/1/teach-physics-open-source
作者:[Cristiano L. Fontana][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/cristianofontana
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/read_book_guide_tutorial_teacher_student_apaper.png?itok=_GOufk6N (Person reading a book and digital copy)
[2]: https://www.medicinachirurgia.unipd.it/
[3]: https://www.unipd.it/
[4]: http://hyperphysics.phy-astr.gsu.edu/
[5]: https://www.compadre.org/osp/
[6]: https://openstax.org/
[7]: https://openstax.org/subjects/science
[8]: https://open.umn.edu/opentextbooks
[9]: https://open.umn.edu/opentextbooks/subjects/physics
[10]: http://www.motionmountain.net/
[11]: http://www.lightandmatter.com/
[12]: https://en.wikipedia.org/wiki/Main_Page
[13]: https://en.wikipedia.org/wiki/Graphics_tablet
[14]: https://opensource.com/sites/default/files/uploads/circuit_notes_0.jpg (Figure: Example of notes taken during class with the graphics tablet and Krita)
[15]: https://www.latex-project.org/
[16]: https://github.com/josephwright/beamer
[17]: https://en.wikipedia.org/wiki/Corporate_identity
[18]: https://opensource.com/sites/default/files/uploads/slide_laplace.png (Figure: Examples of slides created with LaTeX and Beamer)
[19]: https://opensource.com/sites/default/files/uploads/slide_faraday.png (Figure: Examples of slides created with LaTeX and Beamer)
[20]: https://en.wikipedia.org/wiki/Vector_graphics
[21]: https://inkscape.org/
[22]: https://en.wikipedia.org/wiki/Raster_graphics
[23]: https://www.gimp.org/
[24]: https://www.blender.org/
[25]: https://www.freecadweb.org/
[26]: https://github.com/d3/d3-3.x-api-reference/blob/master/Ordinal-Scales.md#category10
[27]: https://d3js.org/
[28]: https://matplotlib.org/
[29]: https://en.wikipedia.org/wiki/Plot_(graphics)
[30]: https://en.wikipedia.org/wiki/Graph_of_a_function
[31]: https://opensource.com/sites/default/files/uploads/electromagnetic_wave.png (Figure: Diagram example created with Inkscape by tracing a Blender 3D diagram)
[32]: http://www2.pd.infn.it/~fontana/project/teaching/2018/01/02/dice-decay.html
[33]: https://en.wikipedia.org/wiki/JavaScript
[34]: https://jquery.com/
[35]: https://www.mathjax.org/
[36]: https://jekyllrb.com/
[37]: https://opensource.com/sites/default/files/uploads/dice_decay.png (Figure: Dice modeling radioactive decay, image of the interactive simulation)
[38]: https://wiki.gnome.org/Apps/Evince
[39]: https://www.gnome.org/gnome-3/
[40]: https://okular.kde.org/
[41]: https://krita.org/en/
[42]: https://docs.krita.org/en/user_manual/python_scripting.html
[43]: https://opensource.com/sites/default/files/uploads/krita_screenshot_0.png (Figure: Screenshot of Krita used in class to write notes)
[44]: https://qalculate.github.io/
[45]: https://wxmaxima-developers.github.io/wxmaxima/
[46]: https://opensource.com/sites/default/files/uploads/qalculate_screenshot.png (Figure: Screenshot of Qalculate)
[47]: https://obsproject.com/
[48]: https://www.openshot.org/
[49]: https://opensource.com/sites/default/files/uploads/obs_screenshot.png (Figure: Screenshot of OBS studio recording the screen)
[50]: https://getfedora.org/
[51]: https://www.centos.org/
[52]: https://flatpak.org/
[53]: https://www.libreoffice.org/discover/impress/

View File

@ -0,0 +1,152 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Send email and check your calendar with Emacs)
[#]: via: (https://opensource.com/article/20/1/emacs-mail-calendar)
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
Send email and check your calendar with Emacs
======
Manage your email and view your schedule with the Emacs text editor in
the eighteenth in our series on 20 ways to be more productive with open
source in 2020.
![Document sending][1]
Last year, I brought you 19 days of new (to you) productivity tools for 2019. This year, I'm taking a different approach: building an environment that will allow you to be more productive in the new year, using tools you may or may not already be using.
### Doing (almost) all the things with Emacs, part 1
Two days ago, I shared that I use both [Vim][2] and [Emacs][3] regularly, and on days [16][4] and [17][5] of this series, I explained how to do almost everything in Vim. Now, it's time for Emacs!
![Mail and calendar in Emacs][6]
Before I get too far, I should explain two things. First, I'm doing everything here using the default Emacs configuration, not [Spacemacs][7], which I have [written about][8]. Why? Because I will be using the default keyboard mappings so that you can refer back to the documentation and not have to translate things from "native Emacs" to Spacemacs. Second, I'm not setting up Org mode in this series. Org mode almost needs an entire series on its own, and, while it is very powerful, the setup can be quite complex.
#### Configure Emacs
Configuring Emacs is a little bit more complicated than configuring Vim, but in my opinion, it is worth it in the long run. Start by creating a configuration file and opening it in Emacs:
```
mkdir ~/.emacs.d
emacs ~/.emacs.d/init.el
```
Next, add some additional package sources to the built-in package manager. Add the following to **init.el**:
```
(package-initialize)
(add-to-list 'package-archives '("melpa" . "<http://melpa.org/packages/>"))
(add-to-list 'package-archives '("org" . "<http://orgmode.org/elpa/>") t)
(add-to-list 'package-archives '("gnu" . "<https://elpa.gnu.org/packages/>"))
(package-refresh-contents)
```
Save the file with **Ctrl**+**x** **Ctrl**+**s**, exit with **Ctrl**+**x** **Ctrl**+**c**, and restart Emacs. It will download all the package lists at startup, and then you should be ready to install things with the built-in package manager. Start by typing **Meta**+**x** to bring up a command prompt (the **Meta** key is the **Alt** key on most keyboards or **Option** on MacOS). At the command prompt, type **package-list-packages** to bring up a list of packages you can install. Go through the list and select the following packages with the **i** key:
```
bbdb
bbdb-vcard
calfw
calfw-ical
notmuch
```
Once the packages are selected, press **x** to install them. Depending on your internet connection, this could take a while. You may see some compile errors, but it's safe to ignore them. Once it completes, open **~/.emacs.d/init.el** with the key combination **Ctrl**+**x** **Ctrl**+**f**, and add the following lines to the file after **(package-refresh-packages)** and before **(custom-set-variables**. Emacs uses the **(custom-set-variables** line internally, and you should never, ever modify anything below it. Lines beginning with **;;** are comments.
```
;; Set up bbdb
(require 'bbdb)
(bbdb-initialize 'message)
(bbdb-insinuate-message)
(add-hook 'message-setup-hook 'bbdb-insinuate-mail)
;; set up calendar
(require 'calfw)
(require 'calfw-ical)
;; Set this to the URL of your calendar. Google users will use
;; the Secret Address in iCalendar Format from the calendar settings
(cfw:open-ical-calendar "<https://path/to/my/ics/file.ics>")
;; Set up notmuch
(require 'notmuch)
;; set up mail sending using sendmail
(setq send-mail-function (quote sendmail-send-it))
(setq user-mail-address "[myemail@mydomain.com][9]"
      user-full-name "My Name")
```
Now you are ready to start Emacs with your setup! Save the **init.el** file (**Ctrl**+**x** **Ctrl**+**s**), exit Emacs (**Ctrl**+**x** **Ctrl**+**c**), and then restart it. It will take a little longer to start this time.
#### Read and write email in Emacs with Notmuch
Once you are at the Emacs splash screen, you can start reading your email with [Notmuch][10]. Type **Meta**+**x notmuch**, and you'll get Notmuch's Emacs interface.
![Reading mail with Notmuch][11]
All the items in bold type are links to email views. You can access them with either a mouse click or by tabbing between them and pressing **Return** or **Enter**. You can use the search bar to
search Notmuch's database using the [same syntax][12] as you use on Notmuch's command line. If you want, you can save any searches for later use with the **[save]** button, and they will be added to the list at the top of the screen. If you follow one of the links, you will get a list of the relevant email messages. You can navigate the list with the **Arrow** keys, and press **Enter** on the message you want to read. Pressing **r** will reply to a message, **f** will forward the message, and **q** will exit the current screen.
You can write a new message by typing **Meta**+**x compose-mail**. Composing, replying, and forwarding all bring up the mail writing interface. When you are done writing your email, press **Ctrl**+**c Ctrl**+**c** to send it. If you decide you don't want to send it, press **Ctrl**+**c Ctrl**+**k** to kill the message compose buffer (window).
#### Autocomplete email addresses in Emacs with BBDB
![Composing a message with BBDB addressing][13]
But what about your address book? That's where [BBDB][14] comes in. But first, import all your addresses from [abook][15] by opening a command line and running the following export command:
```
`abook --convert --outformat vcard --outfile ~/all-my-addresses.vcf --infile ~/.abook/addresses`
```
Once Emacs starts, run **Meta**+**x bbdb-vcard-import-file**. It will prompt you for the file name you want to import, which is **~/all-my-addresses.vcf**. After the import finishes, when you compose a message, you can start typing a name and use **Tab** to search and autocomplete the "To" field. BBDB will also open a buffer for the contact so you can make sure it's the correct one.
Why do it this way when you already have each address as a **vcf.** file from [vdirsyncer][16]? If you are like me, you have a LOT of addresses, and doing them one at a time is a lot of work. This way, you can take everything you have in abook and make one big file.
#### View your calendar in Emacs with calfw
![calfw calendar][17]
Finally, you can use Emacs to look at your calendar. In the configuration section above, you installed the [calfw][18] package and added lines to tell it where to find the calendars to load. Calfw is short for the Calendar Framework for Emacs, and it supports many calendar formats. Since I use Google calendar, that is the link I put into my config. Your calendar will auto-load at startup, and you can view it by switching the **cfw-calendar** buffer with the **Ctrl**+**x**+**b** command.
Calfw offers views by the day, week, two weeks, and month. You can select the view from the top of the calendar and navigate your calendar with the **Arrow** keys. Unfortunately, calfw can only view calendars, so you'll still need to use something like [khal][19] or a web interface to add, delete, and modify events.
So there you have it: mail, calendars, and addresses in Emacs. Tomorrow I'll do even more.
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/1/emacs-mail-calendar
作者:[Kevin Sonney][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/ksonney
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/email_paper_envelope_document.png?itok=uPj_kouJ (Document sending)
[2]: https://www.vim.org/
[3]: https://www.gnu.org/software/emacs/
[4]: https://opensource.com/article/20/1/vim-email-calendar
[5]: https://opensource.com/article/20/1/vim-task-list-reddit-twitter
[6]: https://opensource.com/sites/default/files/uploads/productivity_18-1.png (Mail and calendar in Emacs)
[7]: https://www.spacemacs.org/
[8]: https://opensource.com/article/19/12/spacemacs
[9]: mailto:myemail@mydomain.com
[10]: https://notmuchmail.org/
[11]: https://opensource.com/sites/default/files/uploads/productivity_18-2.png (Reading mail with Notmuch)
[12]: https://opensource.com/article/20/1/organize-email-notmuch
[13]: https://opensource.com/sites/default/files/uploads/productivity_18-3.png (Composing a message with BBDB addressing)
[14]: https://www.jwz.org/bbdb/
[15]: https://opensource.com/article/20/1/sync-contacts-locally
[16]: https://opensource.com/article/20/1/open-source-calendar
[17]: https://opensource.com/sites/default/files/uploads/productivity_18-4.png (calfw calendar)
[18]: https://github.com/kiwanami/emacs-calfw
[19]: https://khal.readthedocs.io/en/v0.9.2/index.html

View File

@ -0,0 +1,125 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Joplin: The True Open Source Evernote Alternative)
[#]: via: (https://itsfoss.com/joplin/)
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
Joplin: The True Open Source Evernote Alternative
======
_**Brief: Joplin is an open source note taking and to-do application. You can organize notes into notebooks and tag them. Joplin also provides a web-clipper to save articles from the internet.**_
### Joplin: Open source note organizer
![][1]
If you like [Evernote][2], you wont be too uncomfortable with the open source software, [Joplin][3].
Joplin is an excellent open source note taking application with plenty of features. You can take notes, make to-do list and sync your notes across devices by linking it with cloud services like Dropbox and NextCloud. The synchronization is protected with end to end encryption.
Joplin also has a web clipper that allows you to save webpages as notes. The web clipper is available for Firefox and Chrome/Chromium browsers.
Joplin makes the switch from Evernote easier by allowing importing Evernote files in Enex format.
Since you own the data, you can export all your files either in Joplin format or in the raw format.
### Features of Joplin
![][4]
Heres a list of all the features Joplin provides:
* Save notes into notebooks and sub-notebooks for better organization
* Create to-do list
* Notes can be tagged and searched
* Offline first, so the entire data is always available on the device even without an internet connection
* Markdown notes with pictures, math notation and checkboxes support
* File attachment support
* Application available for desktop, mobile and terminal (CLI)
* [Web Clipper][5] for Firefox and Chrome
* End To End Encryption
* Keeps note history
* Notes sorting based on name, time etc
* Synchronisation with various [cloud services][6] like [Nextcloud][7], Dropbox, WebDAV and OneDrive
* Import files from Evernote
* Export JEX files (Joplin Export format) and raw files.
* Support notes, to-dos, tags and notebooks.
* Goto Anything feature.
* Support for notifications in mobile and desktop applications.
* Geo-location support.
* Supports multiple languages
* External editor support open notes in your favorite external editor with one click in Joplin.
**Recommended Read:**
![][8]
#### [EncryptPad Encrypted Text Editor For Linux][9]
Looking for a text editor with encryption in Linux? Meet EncryptPad, a text editor with built-in encryption.
### Installing Joplin on Linux and other platforms
![][10]
[Joplin][11] is a cross-platform application available for Linux, macOS and Windows. On the mobile, you can [get the APK file][12] to install it on Android and Android-based ROMs. You can also [get it from the Google Play store][13].
For Linux, you can [use AppImage][14] file for Joplin and run the application as an executable. Youll have to give execute permission to the downloaded file.
[Download Joplin][15]
### Experiencing Joplin
Notes in Joplin use markdown but you dont have to know markdown notations to use it. The editor has a top panel that lets you graphically choose the bullet points, headings, images, link etc.
Though Joplin provides many interesting features, you have to fiddle around on your own to check things out. For example, the web clipper is not enabled by default and I had to figure out how to do it.
You have to enable the clipper from the desktop application. From the top menu, go to Tools-&gt;Options. Youll find the Web Clipper option here:
![Enable Web Clipper from the desktop application first][16]
The web clipper is not as smart as Evernotes web clipper that allows to clip portion of a web article graphically. However, you still have good enough options here.
It is an open source software under active development and I do hope that it gets more improvement over the time.
**Conclusion**
If you are looking for a good note taking application with web-clipper feature, do give Joplin a try. And if you like it and would continue using, try to help Joplin development by making a donation or improving its code and documentation. I made a sweet little [donation][17] of 25 Euro on behalf of Its FOSS.
If you have used Joplin in the past or still using it, hows your experience with it? If you use some other note taking application, would you switch to Joplin? Feel free to share your views.
--------------------------------------------------------------------------------
via: https://itsfoss.com/joplin/
作者:[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://i0.wp.com/itsfoss.com/wp-content/uploads/2020/01/joplin_logo.png?ssl=1
[2]: https://evernote.com/
[3]: https://joplinapp.org/
[4]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/01/joplin_featured.jpg?ssl=1
[5]: https://joplinapp.org/clipper/
[6]: https://itsfoss.com/cloud-services-linux/
[7]: https://nextcloud.com/
[8]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2017/02/encryptpad-text-editor-with-encryption.jpg?fit=800%2C450&ssl=1
[9]: https://itsfoss.com/encryptpad-encrypted-text-editor-linux/
[10]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/01/joplin_ubuntu.jpg?ssl=1
[11]: https://github.com/laurent22/joplin
[12]: https://itsfoss.com/download-apk-ubuntu/
[13]: https://play.google.com/store/apps/details?id=net.cozic.joplin&hl=en_US
[14]: https://itsfoss.com/use-appimage-linux/
[15]: https://github.com/laurent22/joplin/releases
[16]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/01/joplin_web_clipper.jpg?ssl=1
[17]: https://itsfoss.com/donations-foss/

View File

@ -0,0 +1,109 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (What Amazon Kindle? Heres an Open Source eBook Reader)
[#]: via: (https://itsfoss.com/open-book/)
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
What Amazon Kindle? Heres an Open Source eBook Reader
======
When it comes to an eBook reader, the choices are limited. The market is dominated by [Amazon's proprietary Kindle][1] along with a few other options like Kobo, Nook and Onyx.
An interesting news for open source enthusiasts is that a developer, [Joey Castillo][2], is working on creating an open source eBook reader appropriately named Open Book.
### Open Book: An open source eBook reader
![][3]
The [Open Book][4] aims to be a simple open device that “anyone with a soldering iron can build for themselves”.
Its hackable so if you are into DIY stuff and you have some knowledge, you may tweak it to your liking. For example, Joey use [TensorFlow Lite][5] to give voice commands for flipping the pages on Open Book. You can do things like this on your own on this open hardware device.
> Voice commands on the [#OpenBook][6] with [#TensorFlowLite][7]. When I added a mic amp for voice, I considered this a “someday” feature; I didnt imagine one could hack it together in an evening! Major credit to [@adafruit][8]; their TFL Arduino port makes this possible. <https://t.co/ix5UK03F3o> [pic.twitter.com/PfXZx99A9y][9]
>
> — joey castillo (@josecastillo) [December 13, 2019][10]
If that kind of scares you because you are not really into tinkering with hardware, I have a good news for you. Open Book was named winner of [Hackadays Take Flight with Feather contest][11]!
This means that when the hardware is ready, you should be able to purchase it from [DigiKey][12]. You should be able to fit the device as an eBook reader or experiment with it, if you feel like doing it.
It kind of reminds me of [Game Shell][13], a single board computer based retro gaming console that could be tinkered into many other things.
### Open Book specifications
![][14]
There are two versions of Open Book: Open Book Feather and E-Book Feather Wing. The eBook wing does less than the Open Book Feather, mainly because its limited to using only the pins available via the Feather header.
You may guess from the name that the project uses [Adafruits Feather development boards][15].
Here are the main specifications for the Open Book (both versions):
* 4.2 inch, 400 x 300 pixel ePaper display
* SAMD51 ARM Cortex-M4 32-bit processor
* 7 buttons for navigation (directional pad, select button and page turn buttons)
* status LED lights
* A microSD card reader
* Headphone jack
The display seems a bit small, isnt it?
### Open Book release, pricing and availability
![][16]
Open Book is the winner of [Take Flight with Feather competition by Hackaday][11]. This means that at least 100 Open Book boards will be manufactured and made available for purchase.
[Liliputing][17] noted that [Adafruit][18] will be handling the manufacturing, and [Digi-Key][19] will eventually be selling Open Book boards.
At this point, its not clear how much will it cost and exactly when it will be available.
Remember that its an open source project. You can find all the circuit designs, source code on its GitHub page and if you have the skills, get the required hardware components and build an Open Book on your own.
[Open Book on GitHub][4]
Otherwise, wait for a couple of months (hopefully) for the release of the Open Book boards and then go about experimenting with the device.
If you like the project and want to support it, you can help [Joey on Pateron][20]. You can follow the updates on the Open Book on the Patreon page, [Joeys mailing list][21] or Joeys [Twitter account][2].
_Do you think the project has potential? Would you buy one when it is available? What do you think of it?_
--------------------------------------------------------------------------------
via: https://itsfoss.com/open-book/
作者:[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://www.amazon.com/dp/B07DLPWYB7?tag=chmod7mediate-20&linkCode=ogi&th=1&psc=1 (Amazon's proprietary Kindle)
[2]: https://twitter.com/josecastillo
[3]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/01/open-book-under-development-feature.jpeg?ssl=1
[4]: https://github.com/joeycastillo/The-Open-Book
[5]: https://www.tensorflow.org/lite
[6]: https://twitter.com/hashtag/OpenBook?src=hash&ref_src=twsrc%5Etfw
[7]: https://twitter.com/hashtag/TensorFlowLite?src=hash&ref_src=twsrc%5Etfw
[8]: https://twitter.com/adafruit?ref_src=twsrc%5Etfw
[9]: https://t.co/PfXZx99A9y
[10]: https://twitter.com/josecastillo/status/1205549284403355648?ref_src=twsrc%5Etfw
[11]: https://hackaday.io/contest/168107-take-flight-with-feather
[12]: https://www.digikey.com/
[13]: https://itsfoss.com/gameshell-console/
[14]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/01/open-book-board.jpg?ssl=1
[15]: https://www.adafruit.com/feather
[16]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/01/open-book-demo.jpeg?ssl=1
[17]: https://liliputing.com/2020/01/the-open-book-ereader-will-be-a-real-thing-you-can-buy-eventually.html
[18]: https://www.adafruit.com/
[19]: https://www.digikey.com/en/resources/beta-1
[20]: https://www.patreon.com/joeycastillo
[21]: http://eepurl.com/gKOpQ9

View File

@ -0,0 +1,455 @@
[#]: collector: (lujun9972)
[#]: translator: (laingke)
[#]: 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)
Java 中的数据流和函数式编程
======
学习如何使用 Java 8 中的流 API 和函数式编程结构。
![computer screen ][1]
当 Java SE 8又名核心 Java 8在 2014 年被推出时,它引入了一些从根本上影响 IT 编程的更改。这些更改中有两个紧密相连的部分流API和功能编程构造。本文使用代码示例从基础到高级特性介绍每个部分并说明它们之间的相互作用。
### 基础特性
流 API 是在数据序列中迭代元素的简洁而高级的方法。包 `java.util.stream``java.util.function` 包含用于流 API 和相关函数式编程构造的新库。当然,一个代码示例胜过千言万语。
下面的代码段用大约 2,000 个随机整数值填充了一个 `List`
```
Random rand = new Random2();
List<Integer> list = new ArrayList<Integer>(); // 空 list
for (int i = 0; i < 2048; i++) list.add(rand.nextInt()); // 填充它
```
另一个 `for` 循环可用于遍历填充 list以将偶数值收集到另一个 list 中。流 API 提供了一种更简洁的方法来执行此操作:
```
List <Integer> evens = list
.stream() // 流化 list
.filter(n -> (n & 0x1) == 0) // 过滤出奇数值
.collect(Collectors.toList()); // 收集偶数值
```
这个例子有三个来自流 API 的函数:
> `stream` 函数可以将**集合**转换为流,而流是一个每次可访问一个值的传送带。流化是惰性的(因此也是高效的),因为值是根据需要产生的,而不是一次性产生的。
> `filter` 函数确定哪些流的值(如果有的话)通过了处理管道中的下一个阶段,即 `collect` 阶段。`filter` 函数是 _<ruby>高阶的<rt>higher-order</rt></ruby>_,因为它的参数是一个函数 —— 在这个例子中是一个 lambda 表达式,它是一个未命名的函数,并且是 Java 新的函数式编程结构的核心。
lambda 语法与传统的 Java 完全不同:
```
`n -> (n & 0x1) == 0`
```
箭头(一个减号后面紧跟着一个大于号)将左边的参数列表与右边的函数体分隔开。参数 `n` 虽未明确输入,但可以显式输入。在任何情况下,编译器都会计算出 `n``Integer`。如果有多个参数,这些参数将被括在括号中,并用逗号分隔。
在本例中,函数体检查一个整数的最低顺序(最右)位是否为零,以表示为偶数。过滤器应返回一个布尔值。尽管可以,但函数的主体中没有显式的 `return`。如果主体没有显式的 `return`,则主体的最后一个表达式是返回值。在这个例子中,主体按照 lambda 编程的思想编写,由一个简单的布尔表达式 `(n & 0x1) == 0` 组成。
> `collect` 函数将偶数值收集到引用为 `evens` 的 list 中。如下例所示,`collect` 函数是线程安全的,因此,即使在多个线程之间共享了过滤操作,该函数也可以正常工作。
### 方便的功能和轻松实现多线程
在生产环境中,数据流的源可能是文件或网络连接。为了学习流 API, Java 提供了诸如 `IntStream` 这样的类型,它可以用各种类型的元素生成流。这里有一个 `IntStream` 的例子:
```
IntStream // 整型流
.range(1, 2048) // 生成此范围内的整型流
.parallel() // 为多个线程分区数据
.filter(i -> ((i & 0x1) > 0)) // 奇偶校验 - 只允许奇数通过
.forEach(System.out::println); // 打印每个值
```
`IntStream` 类型包括一个 `range` 函数,该函数在指定的范围内生成一个整数值流,在本例中,以 1 为增量,从 1 递增到 2,048。`parallel` 函数自动工作划分到多个线程中,在各个线程中进行过滤和打印。(线程数通常与主机系统上的 CPU 数量匹配。)函数 `forEach` 参数是一个_方法引用_在本例中是对封装在 `System.out` 中的 `println` 方法的引用,方法输出类型为 `PrintStream`。方法和构造器引用的语法将在稍后讨论。
由于具有多线程,因此整数值整体上以任意顺序打印,但在给定线程中按顺序打印。例如,如果线程 T1 打印 409 和 411那么 T1 将按照顺序 409-411 打印,但是其它某个线程可能会预先打印 2,045。`parallel` 调用后面的线程是并发执行的,因此它们的输出顺序是不确定的。
### map/reduce 模式
_map/reduce_ 模式在处理大型数据集方面已变得很流行。一个 map/reduce 宏操作由两个微操作构成。首先将数据分散_mapped_到各个工作程序中然后将单独的结果收集在一起 —— 也可能收集统计起来成为一个值,即 _reduction_。Reduction 可以采用不同的形式,如以下示例所示。
下面 `Number` 类的实例用 **EVEN****ODD** 表示有奇偶校验的整数值:
```
public class Number {
enum Parity { EVEN, ODD }
private int value;
public Number(int n) { setValue(n); }
public void setValue(int value) { this.value = value; }
public int getValue() { return this.value; }
public Parity getParity() {
return ((value & 0x1) == 0) ? Parity.EVEN : Parity.ODD;
}
public void dump() {
System.out.format("Value: %2d (parity: %s)\n", getValue(),
(getParity() == Parity.ODD ? "odd" : "even"));
}
}
```
下面的代码演示了带有 `Number` 流进行 map/reduce 的情形,从而表明流 API 不仅可以处理 `int``float` 等基本类型,还可以处理程序员自定义的类类型。
在下面的代码段中,使用了 `parallelStream` 而不是 `stream` 函数对随机整数值列表进行流化处理。与前面介绍的 `parallel` 函数一样,`parallelStream` 变体也可以自动执行多线程。
```
final int howMany = 200;
Random r = new Random();
Number[] nums = new Number[howMany];
for (int i = 0; i < howMany; i++) nums[i] = new Number(r.nextInt(100));
List<Number> listOfNums = Arrays.asList(nums); // 将数组转化为 list
Integer sum4All = listOfNums
.parallelStream() // 自动执行多线程
.mapToInt(Number::getValue) // 使用方法引用,而不是 lambda
.sum(); // 将流值计算出和值
System.out.println("The sum of the randomly generated values is: " + sum4All);
```
高阶的 `mapToInt` 函数可以接受一个 lambda 作为参数,但在本例中,它接受一个方法引用,即 `Number::getValue`。`getValue` 方法不需要参数,它返回给定的 `Number` 实例的 `int` 值。语法并不复杂:类名 `Number` 后跟一个双冒号和方法名。回想一下先前的例子 `System.out::println`,它在 `System` 类中的 `static` 属性 `out` 后面有一个双冒号。
方法引用 `Number::getValue` 可以用下面的 lambda 表达式替换。参数 `n` 是流中的 `Number` 实例中的之一:
```
`mapToInt(n -> n.getValue())`
```
通常lambdas 和方法引用是可互换的:如果像 `mapToInt` 这样的高阶函数可以采用一种形式作为参数,那么这个函数也可以采用另一种形式。这两个函数式编程结构具有相同的目的 —— 对作为参数传入的数据执行一些自定义操作。在两者之间进行选择通常是为了方便。例如lambda 可以在没有封装类的情况下编写,而方法则不能。。我的习惯是使用 lambda除非已经有了适当的封装方法。
当前示例末尾的 `sum` 函数通过结合来自 `parallelStream` 线程的部分和,以线程安全的方式进行归约。但是,程序员有责任确保在 `parallelStream` 调用引发的多线程过程中,程序员自己的函数调用(在本例中为 `getValue`)是线程安全的。
最后一点值得强调。lambda 语法鼓励编写 _<ruby>纯函数<rt>pure function</rt></ruby>_,即函数的返回值仅取决于传入的参数(如果有);纯函数没有副作用,例如更新类中的 `static` 字段。因此,纯函数是线程安全的,并且如果传递给高阶函数的函数参数(例如 `filter``map` )是纯函数,则流 API 效果最佳。
对于更细粒度的控制,有另一个流 API 函数,名为 `reduce`,可用于对 `Number` 流中的值求和:
```
Integer sum4AllHarder = listOfNums
.parallelStream() // 多线程
.map(Number::getValue) // 每个 Number 的值
.reduce(0, (sofar, next) -> sofar + next); // 求和
```
此版本的 `reduce` 函数带有两个参数,第二个参数是一个函数:
> 第一个参数(在这种情况下为零)是 _特征_ 值,该值用作求和操作的初始值,并且在求和过程中流结束时用作默认值。
> 第二个参数是 _累加器_,在本例中,这个 lambda 表达式有两个参数:第一个参数(`sofar`)是正在运行的和,第二个参数(`next`)是来自流的下一个值。运行总和以及下一个值相加,然后更新累加器。请记住,由于开始时调用了 `parallelStream`,因此 `map``reduce` 函数现在都在多线程上下文中执行。
在到目前为止的示例中,流值被收集,然后被归并,但是,通常情况下,流 API 中的 `Collectors` 可以累积值,而不需要将它们减少到单个值。正如下一个代码段所示,收集活动可以生成任意丰富的数据结构。该示例使用与前面示例相同的 `listOfNums`
```
Map<Number.Parity, List<Number>> numMap = listOfNums
.parallelStream()
.collect(Collectors.groupingBy(Number::getParity));
List<Number> evens = numMap.get(Number.Parity.EVEN);
List<Number> odds = numMap.get(Number.Parity.ODD);
```
第一行中的 `numMap` 指的是一个 `Map`,它的键是一个 `Number` 奇偶校验位(**ODD** 或 **EVEN**),其值是一个具有指定奇偶校验位值的 `Number` 实例的`List`。同样,通过 `parallelStream` 调用进行多线程处理,然后 `collect` 调用(以线程安全的方式)将部分结果组装到 `numMap` 引用的 `Map` 中。然后,在 `numMap` 上调用 `get` 方法两次,一次获取 `evens`,第二次获取 `odds`
实用函数 `dumpList` 再次使用来自流 API 的高阶 `forEach` 函数:
```
private void dumpList(String msg, List<Number> list) {
System.out.println("\n" + msg);
list.stream().forEach(n -> n.dump()); // 或者使用 forEach(Number::dump)
}
```
这是示例运行中程序输出的一部分:
```
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)
```
### 用于代码简化的函数式结构
函数式结构(如方法引用和 lambdas非常适合在流 API 中使用。这些构造代表了 Java 中对高阶函数的主要简化。即使在糟糕的过去Java 也通过 `Method``Constructor` 类型在技术上支持高阶函数,这些类型的实例可以作为参数传递给其它函数。由于其复杂性,这些类型在生产级 Java 中很少使用。例如,调用 `Method` 需要对象引用(如果方法是非**静态**的)或至少一个类标识符(如果方法是**静态**的)。然后,被调用的 `Method` 的参数作为**对象**实例传递给它如果没有发生多态那会出现另一种复杂性则可能需要显式向下转换。相比之下lambda 和方法引用很容易作为参数传递给其它函数。
但是,新的函数式结构在流 API 之外具有其它用途。考虑一个 Java GUI 程序,该程序带有一个供用户按下的按钮,例如,按下以获取当前时间。按钮按下的事件处理程序可能编写如下:
```
JButton updateCurrentTime = new JButton("Update current time");
updateCurrentTime.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
currentTime.setText(new Date().toString());
}
});
```
这个简短的代码段很难解释。关注第二行,其中方法 `addActionListener` 的参数开始如下:
```
`new ActionListener() {`
```
这似乎是错误的,因为 `ActionListener` 是一个**抽象**接口,而**抽象**类型不能通过调用 `new` 实例化。但是,事实证明,还有其它一些实例被实例化了:一个实现此接口的未命名内部类。如果上面的代码封装在名为 `OldJava` 的类中,则该未命名的内部类将被编译为 `OldJava$1.class`。`actionPerformed` 方法在这个未命名的内部类中被重写。
现在考虑使用新的函数式结构进行这个令人耳目一新的更改:
```
`updateCurrentTime.addActionListener(e -> currentTime.setText(new Date().toString()));`
```
lambda 表达式中的参数 `e` 是一个 `ActionEvent` 实例,而 lambda 的主体是对按钮上的 `setText` 的简单调用。
### 函数式接口和函数组合
到目前为止,使用的 lambda 已经写好了。但是,为了方便起见,我们可以像引用封装方法一样引用 lambda 表达式。以下一系列简短示例说明了这一点。
考虑以下接口定义:
```
@FunctionalInterface // 可选,通常省略
interface BinaryIntOp {
abstract int compute(int arg1, int arg2); // abstract 声明可以被删除
}
```
注释 `@FunctionalInterface` 适用于声明 _唯一_ 抽象方法的任何接口;在本例中,这个抽象接口是 `compute`。一些标准接口,(例如具有唯一声明方法 `run``Runnable` 接口)同样符合这个要求。在此示例中,`compute` 是已声明的方法。该接口可用作引用声明中的目标类型:
```
BinaryIntOp div = (arg1, arg2) -> arg1 / arg2;
div.compute(12, 3); // 4
```
`java.util.function` 提供各种函数式接口。以下是一些示例。
下面的代码段介绍了参数化的 `Predicate` 函数式接口。在此示例中,带有参数 `String``Predicate<String>` 类型可以引用具有 `String` 参数的 lambda 表达式或诸如 `isEmpty` 之类的 `String` 方法。通常情况下_predicate_ 是一个返回布尔值的函数。
```
Predicate<String> pred = String::isEmpty; // String 方法的 predicate 声明
String[] strings = {"one", "two", "", "three", "four"};
Arrays.asList(strings)
.stream()
.filter(pred) // 过滤掉非空字符串
.forEach(System.out::println); // 只打印空字符串
```
在字符串长度为零的情况下,`isEmpty` predicate 判定结果为 `true`。 因此,只有空字符串才能进入管道的 `forEach` 阶段。
下一段代码将演示如何将简单的 lambda 或方法引用组合成更丰富的 lambda 或方法引用。考虑这一系列对 `IntUnaryOperator` 类型的引用的赋值,它接受一个整型参数并返回一个整型值:
```
IntUnaryOperator doubled = n -> n * 2;
IntUnaryOperator tripled = n -> n * 3;
IntUnaryOperator squared = n -> n * n;
```
`IntUnaryOperator` 是一个 `FunctionalInterface`,其唯一声明的方法为 `applyAsInt`。现在可以单独使用或以各种组合形式使用这三个引用 `doubled`、`tripled` 和 `squared`
```
int arg = 5;
doubled.applyAsInt(arg); // 10
tripled.applyAsInt(arg); // 15
squared.applyAsInt(arg); // 25
```
以下是一些函数组合的样例:
```
int arg = 5;
doubled.compose(squared).applyAsInt(arg); // 5 求 2 次方后乘 250
tripled.compose(doubled).applyAsInt(arg); // 5 乘 2 后再乘 330
doubled.andThen(squared).applyAsInt(arg); // 5 乘 2 后求 2 次方100
squared.andThen(tripled).applyAsInt(arg); // 5 求 2 次方后乘 375
```
函数组合可以直接使用 lambda 表达式实现,但是引用使代码更简洁。
### 构造器引用
构造器引用是另一种函数式编程构造,而这些引用在比 lambda 和方法引用更微妙的上下文中非常有用。再一次重申,代码示例似乎是最好的解释方式。
考虑这个 [POJO][13] 类:
```
public class BedRocker { // 基岩的居民
private String name;
public BedRocker(String name) { this.name = name; }
public String getName() { return this.name; }
public void dump() { System.out.println(getName()); }
}
```
该类只有一个构造函数,它需要一个 `String` 参数。给定一个名字数组,目标是生成一个 `BedRocker` 元素数组,每个名字代表一个元素。下面是使用了函数式结构的代码段:
```
String[] names = {"Fred", "Wilma", "Peebles", "Dino", "Baby Puss"};
Stream<BedRocker> bedrockers = Arrays.asList(names).stream().map(BedRocker::new);
BedRocker[] arrayBR = bedrockers.toArray(BedRocker[]::new);
Arrays.asList(arrayBR).stream().forEach(BedRocker::dump);
```
在较高的层次上,这个代码段将名字转换为 `BedRocker` 数组元素。具体来说,代码如下所示。`Stream` 接口(在包 `java.util.stream` 中)可以被参数化,而在本例中,生成了一个名为 `bedrockers``BedRocker` 流。
`Arrays.asList` 实用程序再次用于流化一个数组 `names`,然后将流的每一项传递给 `map` 函数,该函数的参数现在是构造器引用 `BedRocker::new`。这个构造器引用通过在每次调用时生成和初始化一个 `BedRocker` 实例来充当一个对象工厂。在第二行执行之后,名为 `bedrockers` 的流由五项 `BedRocker` 组成。
这个例子可以通过关注高阶 `map` 函数来进一步阐明。在通常情况下,一个映射将一个类型的值(例如,一个 `int`)转换为另一个 _相同_ 类型的值(例如,一个整数的后继):
```
map(n -> n + 1) // 将 n 映射到其后继
```
然而,在 `BedRocker` 这个例子中,转换更加戏剧化,因为一个类型的值(代表一个名字的 `String`)被映射到一个 _不同_ 类型的值,在这个例子中,就是一个 `BedRocker` 实例,这个字符串就是它的名字。转换是通过一个构造器调用来完成的,它是由构造器引用来实现的:
```
`map(BedRocker::new) // 将 String 映射到 BedRocker
```
传递给构造器的值是 `names` 数组中的其中一项。
此代码示例的第二行还演示了一个你目前已经非常熟悉的转换:先将数组先转换成 `List`,然后再转换成 `Stream`
```
`Stream<BedRocker> bedrockers = Arrays.asList(names).stream().map(BedRocker::new);`
```
第三行则是另一种方式 —— 流 `bedrockers` 通过使用_数组_构造器引用 `BedRocker[]::new` 调用 `toArray` 方法:
```
`BedRocker[ ] arrayBR = bedrockers.toArray(BedRocker[]::new);`
```
该构造器引用不会创建单个 `BedRocker` 实例,而是创建这些实例的整个数组:该构造器引用现在为 `BedRocker[]:new`,而不是 `BedRocker::new`。为了进行确认,将 `arrayBR` 转换为 `List`,再次对其进行流式处理,以便可以使用 `forEach` 来打印 `BedRocker` 的名字。
```
Fred
Wilma
Peebles
Dino
Baby Puss
```
该示例对数据结构的微妙转换仅用几行代码即可完成,从而突出了可以将 lambda方法引用或构造器引用作为参数的各种高阶函数的功能。
### <ruby>柯里化<rt>Currying</rt></ruby>
_柯里化_ 函数是指减少函数执行任何工作所需的显式参数的数量(通常减少到一个)。(该术语是为了纪念逻辑学家 Haskell Curry。一般来说函数的参数越少调用起来就越容易也更健壮。回想一下一些需要半打左右参数的噩梦般的函数因此应将柯里化视为简化函数调用的一种尝试。`java.util.function` 包中的接口类型适合于柯里化,如以下示例所示。
引用的 `IntBinaryOperator` 接口类型是为函数接受两个整型参数,并返回一个整型值:
```
IntBinaryOperator mult2 = (n1, n2) -> n1 * n2;
mult2.applyAsInt(10, 20); // 200
mult2.applyAsInt(10, 30); // 300
```
引用 `mult2` 强调了需要两个显式参数,在本例中是 10 和 20。
前面介绍的 `IntUnaryOperator``IntBinaryOperator` 简单,因为前者只需要一个参数,而后者则需要两个参数。两者均返回整数值。因此,目标是将名为 `mult2` 的两个参数 `IntBinraryOperator` 柯里化成一个单一的 `IntUnaryOperator` 版本 `curriedMult2`
考虑 `IntFunction<R>` 类型。此类型的函数采用整型参数,并返回类型为 `R` 的结果,该结果可以是另一个函数 —— 更准确地说,是 `IntBinaryOperator`。让一个 lambda 返回另一个 lambda 很简单:
```
arg1 -> (arg2 -> arg1 * arg2) // 括号可以省略
```
完整的 lambda 以 `arg1,` 开头,而该 lambda 的主体以及返回的值是另一个以 `arg2` 开头的 lambda。返回的 lambda 仅接受一个参数(`arg2`),但返回了两个数字的乘积(`arg1` 和 `arg2`)。下面的概述,再加上代码,应该可以更好地进行说明。
以下是如何柯里化 `mult2` 的概述:
> 类型为 `IntFunction<IntUnaryOperator>` 的 lambda 被写入并调用,其整型值为 10。返回的 `IntUnaryOperator` 缓存了值 10因此变成了已柯里化版本的 `mult2`,在本例中为 `curriedMult2`
> 然后使用单个显式参数例如20调用 `curriedMult2` 函数,该参数与缓存的参数(在本例中为 10相乘以生成返回的乘积。。
这是代码的详细信息:
```
// 创建一个接受一个参数 n1 并返回一个单参数 n2 -> n1 * n2 的函数该函数返回一个n1 * n2 乘积的)整型数。
IntFunction<IntUnaryOperator> curriedMult2Maker = n1 -> (n2 -> n1 * n2);
```
调用 `curriedMult2Maker` 生成所需的 `IntUnaryOperator` 函数:
```
// 使用 curriedMult2Maker 获取已柯里化版本的 mult2。
// 参数 10 是上面的 lambda 的 n1。
IntUnaryOperator curriedMult2 = curriedMult2Maker2.apply(10);
```
值 10 现在缓存在 `curriedMult2` 函数中,以便 `curriedMult2` 调用中的显式整型参数乘以 10
```
curriedMult2.applyAsInt(20); // 200 = 10 * 20
curriedMult2.applyAsInt(80); // 800 = 10 * 80
```
缓存的值可以随意更改:
```
curriedMult2 = curriedMult2Maker.apply(50); // 缓存 50
curriedMult2.applyAsInt(101); // 5050 = 101 * 50
```
当然,可以通过这种方式创建多个已柯里化版本的 `mult2`,每个版本都有一个 `IntUnaryOperator`
柯里化充分利用了 lambda 的强大功能:可以很容易地编写 lambda 表达式来返回需要的任何类型的值,包括另一个 lambda。
### 总结
Java 仍然是基于类的面向对象的编程语言。但是,借助流 API 及其支持的函数式构造Java 向函数式语言(例如 Lisp迈出了决定性的同时也是受欢迎的一步。结果是 Java 更适合处理现代编程中常见的海量数据流。在函数式方向上的这一步还使以在前面的代码示例中突出显示的管道的方式编写清晰简洁的 Java 代码更加容易:
```
dataStream
.parallelStream() // 多线程以提高效率
.filter(...) // 阶段 1
.map(...) // 阶段 2
.filter(...) // 阶段 3
...
.collect(...); // 或者,也可以进行归约:阶段 N
```
自动多线程,以 `parallel``parallelStream` 调用为例,建立在 Java 的 fork/join 框架上,该框架支持 _<ruby>任务窃取<rt>task stealing</rt></ruby>_ 以提高效率。假设 `parallelStream` 调用后面的线程池由八个线程组成,并且 `dataStream` 被八种方式分区。某个线程例如T1可能比另一个线程例如T7工作更快这意味着应该将 T7 的某些任务移到 T1 的工作队列中。这会在运行时自动发生。
在这个简单的多线程世界中,程序员的主要职责是编写线程安全函数,这些函数作为参数传递给在流 API 中占主导地位的高阶函数。 尤其是 lambda 鼓励编写纯函数(因此是线程安全的)函数。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/1/javastream
作者:[Marty Kalin][a]
选题:[lujun9972][b]
译者:[laingke](https://github.com/laingke)
校对:[校对者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

@ -1,524 +0,0 @@
[#]: collector: (lujun9972)
[#]: translator: (heguangzhi)
[#]: 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
在你的 Python 平台类游戏中放一些奖励
======
这部分是关于在使用 Python 的 Pygame 模块开发视频游戏给你的玩家提供收集的宝物和经验值的内容。
![Hearts, stars, and dollar signs][1]
这是正在进行的关于使用 [Python 3][2]的[Pygame][3]模块创建视频游戏的系列文章的第9部分。以前的文章有:
* [通过构建一个简单的骰子游戏学习如何用 Python 编程][4]
* [使用 Pygame 模块用 Python 构建游戏框架][5]
* [如何在 Python 游戏中添加玩家][6]
* [使用 Pygame 移动你的游戏角色][7]
* [没有恶棍的哪里来的英雄?如何在您的 Python 游戏中添加一个][8]
* [在你的 Python 游戏中模拟重力][9]
* [将跳跃添加到您的 Python 平台游戏中][10]
* [使你的 Python 游戏玩家能够向前和向后跑][11]
如果你已经阅读了本系列的前几篇文章,那么你已经了解了编写游戏的所有基础知识。现在你可以在这些基础上,创造一个全功能的游戏。当你第一次学习时,遵循本系列代码示例,这样的“用例”是有帮助的,但是,用例也会约束你。现在是时候运用你学到的知识,以新的方式应用它们了。
如果说,说起来容易做起来难,这篇文章展示了一个如何将你已经了解的内容用于新目的的例子中。具体来说,就是它涵盖了如何使用你以前的课程中已经了解到的来实现奖励系统。
在大多数电子游戏中,你有机会在游戏世界中获得“奖励”或收集到宝物和其他物品。奖励通常会增加你的分数或者你的健康指数,或者为你的下一次任务提供信息。
游戏中包含的奖励类似于编程平台。像平台一样,奖励没有用户控制,随着游戏世界的滚动进行,并且必须检查与玩家的碰撞。
### 创建奖励函数
奖励和平台非常相似,你甚至不需要奖励类。您可以重用 **Platform** 类,并将结果称为奖励。
由于奖励类型和位置可能因关卡不同而不同,如果你还没有一个新的功能,请在你的 **Level** 中创建一个名为 **Level** 的新功能。因为奖励物品不是平台,你也必须创建一个新的 **loot_list** 组,然后添加奖励物品。与平台、地面和敌人一样,该组用于检查玩家碰撞:
```
    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
```
你可以随意添加任意数量的奖励对象;记住把每一个都加到你的奖励清单上。***Platform** 类的参数是奖励图标的X位置、Y位置、宽度和高度(通常最容易让你的奖励图标保持和所有其他方块一样的大小),以及你想要用作的奖励图标。奖励的放置可以和贴图平台一样复杂,所以使用创建关卡时需要创建关卡设计文档。
在脚本的 **Setup** 部分调用新的奖励函数。在下面的代码中,前三行是上下文,所以只需添加第四行:
```
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)
```
正如你现在所知道的,除非你把它包含在你的主循环中,否则奖励不会被显示到屏幕上。将下面代码示例的最后一行添加到循环中:
```
    enemy_list.draw(world)
    ground_list.draw(world)
    plat_list.draw(world)
    loot_list.draw(world)
```
启动你的游戏看看会发生什么。
![Loot in Python platformer][12]
你的奖励将会显示出来,但是当你的玩家碰到它们时,它们不会做任何事情,当你的玩家经过它们时,它们也不会滚动。接下来解决这些问题。
### 滚动奖励
像平台一样,当玩家在游戏世界中移动时,奖励必须滚动。逻辑与平台滚动相同。要向前滚动奖励物品,添加最后两行:
```
        for e in enemy_list:
            e.rect.x -= scroll
        for l in loot_list:
            l.rect.x -= scroll
```
要向后滚动,请添加最后两行:
```
        for e in enemy_list:
            e.rect.x += scroll
        for l in loot_list:
            l.rect.x += scroll
```
再次启动你的游戏,看看你的奖励物品现在表现得像在游戏世界里一样了,而不是仅仅画在上面。
### 检测碰撞
就像平台和敌人一样,你可以检查奖励物品和玩家之间的碰撞。逻辑与其他碰撞相同,除了撞击不会(必然)影响重力或健康。取而代之的是,命中会导致奖励物品会消失并增加玩家的分数。
当你的玩家触摸到一个奖励对象时,你可以从 **奖励列表** 中移除该对象。这意味着当你的主循环在 **loot_list** 中重绘所有奖励物品时,它不会重绘那个特定的对象,所以看起来玩家已经获得了奖励物品。
**Player** 类的 **update** 函数中的平台碰撞检测之上添加以下代码(最后一行仅用于上下文):
```
                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)
```
当碰撞发生时,你不仅要把奖励从它的组中移除,还要给你的玩家一个分数提升。你还没有创建分数变量,所以请将它添加到你的玩家属性中,该属性是在***Player** 类的**__init__**函数中创建的。在下面的代码中,前两行是上下文,所以只需添加分数变量:
```
        self.frame = 0
        self.health = 10
        self.score = 0
```
当在主循环中调用**update**函数时,需要包括**loot_list**:
```
        player.gravity()
        player.update()
```
如你所见,你已经掌握了所有的基本知识。你现在要做的就是用新的方式使用你所知道的。
在下一篇文章中还有一些提示,但是与此同时,用你学到的知识来制作一些简单的单层游戏。限制你试图创造的东西的范围是很重要的,这样你就不会埋没自己。这也使得最终的成品看起来和感觉上更容易完成。
以下是迄今为止你为这个 Python 平台编写的所有代码:
```
#!/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]
译者:[heguangzhi](https://github.com/heguangzhi)
校对:[校对者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,130 @@
[#]: collector: (lujun9972)
[#]: translator: (robsean)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (How to Set or Change Timezone in Ubuntu Linux [Beginners Tip])
[#]: via: (https://itsfoss.com/change-timezone-ubuntu/)
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
如何在 Ubuntu Linux 中设置或更改时区 [初学者技巧]
======
[当你安装 Ubuntu 时][1],它要求你设置时区。如果你选择一个错误的时区,或者你移动到世界的一些其它地方,你可以很容易地在以后更改它。
### 如何在 Ubuntu 和其它 Linux 发行版中更改时区
这里有两种方法来更改 Ubuntu 中的时区。你可以使用图形化设置或在终端中使用 timedatectl 命令。你也可以直接更改 /etc/timezone 文件,但是我不建议这样做。
在这篇初学者教程中,我将向你展示图形化和终端两种方法:
* [通过 GUI 更改 Ubuntu 中的时区][2] (适合桌面用户)
* [通过命令行更改 Ubuntu 中的时区][3] (桌面和服务器都工作)
![][4]
#### 方法 1: 通过终端更改 Ubuntu 时区
[Ubuntu][5] 或一些使用 systemd 的其它发行版可以在 Linux 终端中使用 timedatectl 命令来设置时区。
你可以使用没有任何参数的 timedatectl 命令来检查当前是日期和时区设置:
```
[email protected]:~$ timedatectl
Local time: Sat 2020-01-18 17:39:52 IST
Universal time: Sat 2020-01-18 12:09:52 UTC
RTC time: Sat 2020-01-18 12:09:52
Time zone: Asia/Kolkata (IST, +0530)
System clock synchronized: yes
systemd-timesyncd.service active: yes
RTC in local TZ: no
```
正如你在上面的输出中所看,我的系统使用 Asia/Kolkata 。它也告诉我现在比世界时早 5 小时 30 分钟。
为在 Linux 中设置时区,你需要知道准确的时区。你必需使用时区的正确的格式 (时区格式是 大陆/城市)。
为获取时区列表,使用 _timedatectl_ 命令的 _list-timezones_ 参数:
```
timedatectl list-timezones
```
它将向你显示大量可用的时区列表。
![Timezones List][6]
你可以使用向上箭头和向下箭头或 PgUp 和 PgDown 键来在页面之间移动。
你也可以 grep 输出,并搜索你的时区。例如,假如你正在寻找欧洲的时区,你可以使用:
```
timedatectl list-timezones | grep -i europe
```
比方说,你想设置时区为巴黎。在这里,使用的时区值的 Europe/Paris
```
timedatectl set-timezone Europe/Paris
```
它虽然不显示任何成功信息,但是时区会立即更改。你不需要重新启动或注销。
记住,虽然你不需要成为 root 用户,并且对命令使用 sudo ,但是你的账户仍然需要拥有管理器权限来更改时区。
你可以使用 [date 命令][7] 来验证更改的时间好时区:
```
[email protected]:~$ date
Sat Jan 18 13:56:26 CET 2020
```
#### 方法 2: 通过 GUI 更改 Ubuntu 时区
按下 super 键 (Windows 键) ,并搜索设置:
![Applications Menu Settings][8]
在左侧边栏中,向下滚动一点,查看详细信息:
![Go to Settings -> Details][9]
在详细信息中,你将在左侧边栏中找到 日期和时间 。在这里,你应该关闭自动时区选项(如果它已经被启用),然后在时区上单击:
![In Details -> Date & Time, turn off the Automatic Time Zone][10]
当你单击时区时,它将打开一个交互式地图,你可以在你选择的地理位置上单击,关闭窗口。
![Select a timezone][11]
在选择新的时区后,除了关闭这个地图后,你不必做任何事情。不需要注销或 [关闭 Ubuntu][12] 。
我希望这篇快速教程能帮助你在 Ubuntu 和其它 Linux 发行版中更改时区。如果你有问题或建议,请告诉我。
--------------------------------------------------------------------------------
via: https://itsfoss.com/change-timezone-ubuntu/
作者:[Abhishek Prakash][a]
选题:[lujun9972][b]
译者:[robsean](https://github.com/robsean)
校对:[校对者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/install-ubuntu/
[2]: tmp.bHvVztzy6d#change-timezone-gui
[3]: tmp.bHvVztzy6d#change-timezone-command-line
[4]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/01/Ubuntu_Change-_Time_Zone.png?ssl=1
[5]: https://ubuntu.com/
[6]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/01/timezones_in_ubuntu.jpg?ssl=1
[7]: https://linuxhandbook.com/date-command/
[8]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/08/applications_menu_settings.jpg?ssl=1
[9]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/01/settings_detail_ubuntu.jpg?ssl=1
[10]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/01/change_timezone_in_ubuntu.jpg?ssl=1
[11]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/01/change_timezone_in_ubuntu_2.jpg?ssl=1
[12]: https://itsfoss.com/schedule-shutdown-ubuntu/