分类 技术 下的文章

学习如何使用 Redis 和 Python 构建一个位置感知的应用程序。

我经常出差。但不是一个汽车狂热分子,所以当我有空闲时,我更喜欢在城市中散步或者骑单车。我参观过的许多城市都有共享单车系统,你可以租个单车用几个小时。大多数系统都有一个应用程序来帮助用户定位和租用他们的单车,但对于像我这样的用户来说,在一个地方可以获得可租赁的城市中所有单车的信息会更有帮助。

为了解决这个问题并且展示开源的强大还有为 Web 应用程序添加位置感知的功能,我组合了可用的公开的共享单车数据、Python 编程语言以及开源的 Redis 内存数据结构服务,用来索引和查询地理空间数据。

由此诞生的共享单车应用程序包含来自很多不同的共享系统的数据,包括纽约市的 Citi Bike 共享单车系统(LCTT 译注:Citi Bike 是纽约市的一个私营公共单车系统。在 2013 年 5 月 27 日正式营运,是美国最大的公共单车系统。Citi Bike 的名称有两层意思。Citi 是计划赞助商花旗银行(CitiBank)的名字。同时,Citi 和英文中“城市(city)”一词的读音相同)。它利用了花旗单车系统提供的 通用共享单车数据流 General Bikeshare Feed ,并利用其数据演示了一些使用 Redis 地理空间数据索引的功能。 花旗单车数据可按照 花旗单车数据许可协议 提供。

通用共享单车数据流规范

通用共享单车数据流规范 General Bikeshare Feed Specification (GBFS)是由 北美共享单车协会 开发的 开放数据规范,旨在使地图程序和运输程序更容易的将共享单车系统添加到对应平台中。 目前世界上有 60 多个不同的共享系统使用该规范。

Feed 流由几个简单的 JSON 数据文件组成,其中包含系统状态的信息。 Feed 流以一个顶级 JSON 文件开头,其引用了子数据流的 URL:

{
    "data": {
        "en": {
            "feeds": [
                {
                    "name": "system_information",
                    "url": "https://gbfs.citibikenyc.com/gbfs/en/system_information.json"
                },
                {
                    "name": "station_information",
                    "url": "https://gbfs.citibikenyc.com/gbfs/en/station_information.json"
                },
                . . .
            ]
        }
    },
    "last_updated": 1506370010,
    "ttl": 10
}

第一步是使用 system_informationstation_information 的数据将共享单车站的信息加载到 Redis 中。

system_information 提供系统 ID,系统 ID 是一个简短编码,可用于为 Redis 键名创建命名空间。 GBFS 规范没有指定系统 ID 的格式,但确保它是全局唯一的。许多共享单车数据流使用诸如“coastbikeshare”,“boisegreenbike” 或者 “topekametro\_bikes” 这样的短名称作为系统 ID。其他的使用常见的有地理缩写,例如 NYC 或者 BA,并且使用通用唯一标识符(UUID)。 这个共享单车应用程序使用该标识符作为前缀来为指定系统构造唯一键。

station_information 数据流提供组成整个系统的共享单车站的静态信息。车站由具有多个字段的 JSON 对象表示。车站对象中有几个必填字段,用于提供物理单车站的 ID、名称和位置。还有几个可选字段提供有用的信息,例如最近的十字路口、可接受的付款方式。这是共享单车应用程序这一部分的主要信息来源。

建立数据库

我编写了一个示例应用程序 loadstationdata.py,它模仿后端进程中从外部源加载数据时会发生什么。

查找共享单车站

GitHub 上 GBFS 仓库中的 systems.csv 文件开始加载共享单车数据。

仓库中的 systems.csv 文件提供已注册的共享单车系统及可用的 GBFS 数据流的 发现 URL discovery URL 。 这个发现 URL 是处理共享单车信息的起点。

load_station_data 程序获取系统文件中找到的每个发现 URL,并使用它来查找两个子数据流的 URL:系统信息和车站信息。 系统信息提供提供了一条关键信息:系统的唯一 ID。 (注意:系统 ID 也在 systems.csv 文件中提供,但文件中的某些标识符与数据流中的标识符不匹配,因此我总是从数据流中获取标识符。)系统上的详细信息,比如共享单车 URL、电话号码和电子邮件, 可以在程序的后续版本中添加,因此使用 ${system_id}:system_info 这个键名将数据存储在 Redis 中。

载入车站数据

车站信息提供系统中每个车站的数据,包括该系统的位置。load_station_data 程序遍历车站数据流中的每个车站,并使用 ${system_id}:station:${station_id} 形式的键名将每个车站的数据存储到 Redis 中。 使用 GEOADD 命令将每个车站的位置添加到共享单车的地理空间索引中。

更新数据

在后续运行中,我不希望代码从 Redis 中删除所有 Feed 数据并将其重新加载到空的 Redis 数据库中,因此我仔细考虑了如何处理数据的原地更新。

代码首先加载所有需要系统在内存中处理的共享单车站的信息数据集。 当加载了一个车站的信息时,该站就会按照 Redis 键名从内存中的车站集合中删除。 加载完所有车站数据后,我们就剩下一个包含该系统所有必须删除的车站数据的集合。

程序迭代处理该数据集,并创建一个事务删除车站的信息,从地理空间索引中删除该车站的键名,并从系统的车站列表中删除该车站。

代码重点

示例代码中有一些值得注意的地方。 首先,使用 GEOADD 命令将所有数据项添加到地理空间索引中,而使用 ZREM 命令将其删除。 由于地理空间类型的底层实现使用了有序集合,因此需要使用 ZREM 删除数据项。 需要注意的是:为简单起见,示例代码演示了如何在单个 Redis 节点工作; 为了在集群环境中运行,需要重新构建事务块。

如果你使用的是 Redis 4.0(或更高版本),则可以在代码中使用 DELETEHMSET 命令。 Redis 4.0 提供 UNLINK 命令作为 DELETE 命令的异步版本的替代。 UNLINK 命令将从键空间中删除键,但它会在另外的线程中回收内存。 在 Redis 4.0 中 HMSET 命令已经被弃用了而且 HSET 命令现在接收可变参数(即,它接受的参数个数不定)。

通知客户端

处理结束时,会向依赖我们数据的客户端发送通知。 使用 Redis 发布/订阅机制,通知将通过 geobike:station_changed 通道和系统 ID 一起发出。

数据模型

在 Redis 中构建数据时,最重要的考虑因素是如何查询信息。 共享单车程序需要支持的两个主要查询是:

  • 找到我们附近的车站
  • 显示车站相关的信息

Redis 提供了两种主要数据类型用于存储数据:哈希和有序集。 哈希类型很好地映射到表示车站的 JSON 对象;由于 Redis 哈希不使用固定的数据结构,因此它们可用于存储可变的车站信息。

当然,在地理位置上寻找站点需要地理空间索引来搜索相对于某些坐标的站点。 Redis 提供了几个使用有序集数据结构构建地理空间索引的命令。

我们使用 ${system_id}:station:${station_id} 这种格式的键名存储车站相关的信息,使用 ${system_id}:stations:location 这种格式的键名查找车站的地理空间索引。

获取用户位置

构建应用程序的下一步是确定用户的当前位置。 大多数应用程序通过操作系统提供的内置服务来实现此目的。 操作系统可以基于设备内置的 GPS 硬件为应用程序提供定位,或者从设备的可用 WiFi 网络提供近似的定位。

查找车站

找到用户的位置后,下一步是找到附近的共享单车站。 Redis 的地理空间功能可以返回用户当前坐标在给定距离内的所有车站信息。 以下是使用 Redis 命令行界面的示例。

想象一下,我正在纽约市第五大道的苹果零售店,我想要向市中心方向前往位于西 37 街的 MOOD 布料店,与我的好友 Swatch 相遇。 我可以坐出租车或地铁,但我更喜欢骑单车。 附近有没有我可以使用的单车共享站呢?

苹果零售店位于 40.76384,-73.97297。 根据地图显示,在零售店 500 英尺半径范围内(地图上方的蓝色)有两个单车站,分别是陆军广场中央公园南单车站和东 58 街麦迪逊单车站。

我可以使用 Redis 的 GEORADIUS 命令查询 500 英尺半径范围内的车站的 NYC 系统索引:

127.0.0.1:6379> GEORADIUS NYC:stations:location -73.97297 40.76384 500 ft
1) "NYC:station:3457"
2) "NYC:station:281"

Redis 使用地理空间索引中的元素作为特定车站的元数据的键名,返回在该半径内找到的两个共享单车站。 下一步是查找两个站的名称:

127.0.0.1:6379> hget NYC:station:281 name
"Grand Army Plaza & Central Park S"

127.0.0.1:6379> hget NYC:station:3457 name
"E 58 St & Madison Ave"

这些键名对应于上面地图上标识的车站。 如果需要,可以在 GEORADIUS 命令中添加更多标志来获取元素列表,每个元素的坐标以及它们与当前点的距离:

127.0.0.1:6379> GEORADIUS NYC:stations:location -73.97297 40.76384 500 ft WITHDIST WITHCOORD ASC 
1) 1) "NYC:station:281"
   2) "289.1995"
   3) 1) "-73.97371262311935425"
      2) "40.76439830559216659"
2) 1) "NYC:station:3457"
   2) "383.1782"
   3) 1) "-73.97209256887435913"
      2) "40.76302702144496237"

查找与这些键名关联的名称会生成一个我可以从中选择的车站的有序列表。 Redis 不提供方向和路线的功能,因此我使用设备操作系统的路线功能绘制从当前位置到所选单车站的路线。

GEORADIUS 函数可以很轻松的在你喜欢的开发框架的 API 里实现,这样就可以向应用程序添加位置功能了。

其他的查询命令

除了 GEORADIUS 命令外,Redis 还提供了另外三个用于查询索引数据的命令:GEOPOSGEODISTGEORADIUSBYMEMBER

GEOPOS 命令可以为 地理哈希 geohash 中的给定元素提供坐标(LCTT 译注:geohash 是一种将二维的经纬度编码为一位的字符串的一种算法,常用于基于距离的查找算法和推荐算法)。 例如,如果我知道西 38 街 8 号有一个共享单车站,ID 是 523,那么该站的元素名称是 NYC:station:523。 使用 Redis,我可以找到该站的经度和纬度:

127.0.0.1:6379> geopos NYC:stations:location NYC:station:523
1) 1) "-73.99138301610946655"
   2) "40.75466497634030105"

GEODIST 命令提供两个索引元素之间的距离。 如果我想找到陆军广场中央公园南单车站与东 58 街麦迪逊单车站之间的距离,我会使用以下命令:

127.0.0.1:6379> GEODIST NYC:stations:location NYC:station:281 NYC:station:3457 ft 
"671.4900"

最后,GEORADIUSBYMEMBER 命令与 GEORADIUS 命令类似,但该命令不是采用一组坐标,而是采用索引的另一个成员的名称,并返回以该成员为中心的给定半径内的所有成员。 要查找陆军广场中央公园南单车站 1000 英尺范围内的所有车站,请输入以下内容:

127.0.0.1:6379> GEORADIUSBYMEMBER NYC:stations:location NYC:station:281 1000 ft WITHDIST
1) 1) "NYC:station:281"
   2) "0.0000"
2) 1) "NYC:station:3132"
   2) "793.4223"
3) 1) "NYC:station:2006"
   2) "911.9752"
4) 1) "NYC:station:3136"
   2) "940.3399"
5) 1) "NYC:station:3457"
   2) "671.4900"

虽然此示例侧重于使用 Python 和 Redis 来解析数据并构建共享单车系统位置的索引,但可以很容易地衍生为定位餐馆、公共交通或者是开发人员希望帮助用户找到的任何其他类型的场所。

本文基于今年我在北卡罗来纳州罗利市的开源 101 会议上的演讲


via: https://opensource.com/article/18/2/building-bikesharing-application-open-source-tools

作者:Tague Griffith 译者:Flowsnow 校对:wxy

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

通过不断分析代码以了解潜在的质量问题,开源的 SonarQube 项目支持了 DevOps 的“尽早发布和经常发布” 的思维模式。

越来越多的组织正在实施 DevOps 以便在通过中间开发和测试环境以后更快更好的将新代码引入到生产环境。虽然版本控制、持续集成和部署以及自动化测试都属于 DevOps 的范畴,但仍然存在一个关键问题:组织如何量化代码质量,而不仅仅是部署的速度?

SonarQube 是用来填补这个空隙的一种选择。它是一个开源平台,通过代码的自动化静态分析不断的检查代码质量。 SonarQube 支持 20 多种语言的分析,并在各种类型的项目中输出和存储问题。

SonarQube 同时也提供了一个可同时维护和管理不同项目、不同代码的集中的环境。可以为每个项目定制规则。持续的检查和分析代码的健康轨迹。

SonarQube 还可以集成到可持续集成和开发(CI/CD)流程中,协助和自动确定代码是否为生产环境做好了准备的过程。

它可以衡量什么

开箱即用,SonarQube 可以测量的关键指标,包括代码错误、 代码异味 code smells 、安全漏洞和重复的代码。

  • 代码错误 是代码中的一部分不正确或无法正常运行、可能会导致错误的结果,是指那些在代码发布到生产环境之前应该被修复的明显的错误。
  • 代码异味 不同于代码错误,被检测到的代码是可能能正确执行并符合预期。然而,它不容易被修复,也不能被单元测试覆盖,却可能会导致一些未知的错误,或是一些其它的问题。从长期的可维护性来讲,立即修复代码异味是明智之举。通常在编写代码的时候,代码异味并不容易被发现,而 SonarQube 的静态分析是一种发现它们的很好的方式。
  • 安全漏洞 正如听起来的一样:指的是现在的代码中可能存在的安全问题的缺陷。这些缺陷应该立即修复来防止黑客利用它们。
  • 重复的代码 也和听起来的一样:指的是源代码中重复的部分。代码重复在软件设计中是一种很不好的做法。总的来说,如果对一部分代码进行更改而另一部分没有,则会导致一些维护性的问题。例如,识别重复的代码可以很容易的将重复的代码打包成一个库来重复的使用。

可自定义的选项

因为它是开源的,所以 SonarQube 鼓励用户开发和提供可定制的选项。目前有超过 60 个插件 可用于增强 SonarQube 开箱即用的分析功能。

大多数的插件是为了增加 SonarQube 可以分析的编程语言的数量。另一些插件可以分析一些额外的指标甚至包括一些显示的仪表盘视图。实际上,如果组织需要检查一些自定义指标,或是想要在自己的仪表盘和以特定的方式查看分析数据,或使用 SonarQube 不支持的编程语言,则可能存在一些自定义的选项可以使用。如果你想要的功能并不支持,SonarQube 源码的开放也为你自己开发新的功能提供了可能性。

用户还可以定制适用于每种特定编程语言分析器的规则。通过 SonarQube 用户界面,可以按语言和按项目选择和取消规则。这些为特定的项目指定的规则,可以很好的在一个集中的位置维护所有的数据和配置。

为什么它那么重要

SonarQube 为组织提供了一个集中的位置来管理和跟踪多个项目代码中的问题。它还可以把持续的检查与质量门限相结合。一旦项目分析过一次以后,更进一步的分析会参考软件最新的修改来更新原始的统计信息,以反映最新的变化。这些跟踪可以让用户看到问题解决的程度和速度。这与 “尽早发布并经常发布”不谋而合。

另外,SonarQube 可使用 可持续集成流程,比如像 Hudson) 和 Jenkins) 这样的工具。这个质量门限可以很好的反映代码的整体运行状况,并且通过 Jenkins 等集成工具,在发布代码到生产环境时担任一个重要的角色。

本着 DevOps 的精神, SonarQube 可以量化代码质量,来达到组织内部的要求。为了加快代码生产和发布的周期,组织必须意识到它们自己的技术债务和软件问题。通过发现这些信息, SonarQube 可以帮助组织更快的生成高质量的软件。

想要了解更多吗?

SonarQube 基于 GUN 通用公共许可证发布,它的源码可以在 GitHub 上查看。越来越多的用户对 SonarQube 的特性和功能感兴趣。 TwitterGoogle 上有活跃的社区。这些社区以及 SonarQube 博客 对任何有兴趣开始和使用 SonarQube 的人有很有帮助。


via: https://opensource.com/article/17/10/sonarqube

作者:Sophie Polson 译者:Jamkr 校对:wxy

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

这篇指南介绍如何使用 Pandoc 将文档转换为多种不同的格式。

Pandoc 是一个命令行工具,用于将文件从一种标记语言转换为另一种标记语言。标记语言使用标签来标记文档的各个部分。常用的标记语言包括 Markdown、ReStructuredText、HTML、LaTex、ePub 和 Microsoft Word DOCX。

简单来说,Pandoc 允许你将一些文件从一种标记语言转换为另一种标记语言。典型的例子包括将 Markdown 文件转换为演示文稿、LaTeX,PDF 甚至是 ePub。

本文将解释如何使用 Pandoc 从单一标记语言(在本文中为 Markdown)生成多种格式的文档,引导你完成从 Pandoc 安装,到展示如何创建多种类型的文档,再到提供有关如何编写易于移植到其他格式的文档的提示。

文中还将解释使用元信息文件对文档内容和元信息(例如,作者姓名、使用的模板、书目样式等)进行分离的意义。

Pandoc 安装和要求

Pandoc 默认安装在大多数 Linux 发行版中。本教程使用 pandoc-2.2.3.2 和 pandoc-citeproc-0.14.3。如果不打算生成 PDF,那么这两个包就足够了。但是,我建议也安装 texlive,这样就可以选择生成 PDF 了。

通过以下命令在 Linux 上安装这些程序:

sudo apt-get install pandoc pandoc-citeproc texlive

您可以在 Pandoc 的网站上找到其他平台的 安装说明

我强烈建议安装 pandoc-crossref,这是一个“用于对图表,方程式,表格和交叉引用进行编号的过滤器”。最简单的安装方式是下载 预构建的可执行文件,但也可以通过以下命令从 Haskell 的软件包管理器 cabal 安装它:

cabal update
cabal install pandoc-crossref

如果需要额外的 Haskell 安装信息,请参考 pandoc-crossref 的 GitHub 仓库。

几个例子

我将通过解释如何生成三种类型的文档来演示 Pandoc 的工作原理:

  • 由包含数学公式的 LaTeX 文件创建的网页
  • 由 Markdown 文件生成的 Reveal.js 幻灯片
  • 混合 Markdown 和 LaTeX 的合同文件

创建一个包含数学公式的网站

Pandoc 的优势之一是以不同的输出文件格式显示数学公式。例如,我们可以从包含一些数学符号(用 LaTeX 编写)的 LaTeX 文档(名为 math.tex)生成一个网页。

math.tex 文档如下所示:

% Pandoc math demos

$a^2 + b^2 = c^2$

$v(t) = v_0 + \frac{1}{2}at^2$

$\gamma = \frac{1}{\sqrt{1 - v^2/c^2}}$

$\exists x \forall y (Rxy \equiv Ryx)$

$p \wedge q \models p$

$\Box\diamond p\equiv\diamond p$

$\int_{0}^{1} x dx = \left[ \frac{1}{2}x^2 \right]_{0}^{1} = \frac{1}{2}$

$e^x = \sum_{n=0}^\infty \frac{x^n}{n!} = \lim_{n\rightarrow\infty} (1+x/n)^n$

通过输入以下命令将 LaTeX 文档转换为名为 mathMathML.html 的网站:

pandoc math.tex -s --mathml  -o mathMathML.html

参数 -s 告诉 Pandoc 生成一个独立的网页(而不是网页片段,因此它将包括 HTML 中的 head 和 body 标签),-mathml 参数强制 Pandoc 将 LaTeX 中的数学公式转换成 MathML,从而可以由现代浏览器进行渲染。

看一下 网页效果代码,代码仓库中的 Makefile 使得运行更加简单。

制作一个 Reveal.js 幻灯片

使用 Pandoc 从 Markdown 文件生成简单的演示文稿很容易。幻灯片包含顶级幻灯片和下面的嵌套幻灯片。可以通过键盘控制演示文稿,从一个顶级幻灯片跳转到下一个顶级幻灯片,或者显示顶级幻灯片下面的嵌套幻灯片。 这种结构在基于 HTML 的演示文稿框架中很常见。

创建一个名为 SLIDES 的幻灯片文档(参见 代码仓库)。首先,在 后面添加幻灯片的元信息(例如,标题、作者和日期):

% Case Study
% Kiko Fernandez Reyes
% Sept 27, 2017

这些元信息同时也创建了第一张幻灯片。要添加更多幻灯片,使用 Markdown 的一级标题(在下面例子中的第5行,参考 Markdown 的一级标题 )生成顶级幻灯片。

例如,可以通过以下命令创建一个标题为 “Case Study”、顶级幻灯片名为 “Wine Management System” 的演示文稿:

% Case Study
% Kiko Fernandez Reyes
% Sept 27, 2017

# Wine Management System

使用 Markdown 的二级标题将内容(比如包含一个新管理系统的说明和实现的幻灯片)放入刚刚创建的顶级幻灯片。下面添加另外两张幻灯片(在下面例子中的第 7 行和 14 行 ,参考 Markdown 的二级标题 )。

  • 第一个二级幻灯片的标题为 “Idea”,并显示瑞士国旗的图像
  • 第二个二级幻灯片的标题为 “Implementation”
% Case Study
% Kiko Fernandez Reyes
% Sept 27, 2017

# Wine Management System

## <img src="img/SwissFlag.png" style="vertical-align:middle"/> Idea

## Implementation

我们现在有一个顶级幻灯片(#Wine Management System),其中包含两张幻灯片(## Idea## Implementation)。

通过创建一个由符号 > 开头的 Markdown 列表,在这两张幻灯片中添加一些内容。在上面代码的基础上,在第一张幻灯片中添加两个项目(第 9-10 行),第二张幻灯片中添加五个项目(第 16-20 行):

% Case Study
% Kiko Fernandez Reyes
% Sept 27, 2017

# Wine Management System

## <img src="img/SwissFlag.png" style="vertical-align:middle"/> Idea

>- Swiss love their **wine** and cheese
>- Create a *simple* wine tracker system

![](img/matterhorn.jpg)

## Implementation

>- Bottles have a RFID tag
>- RFID reader (emits and read signal)
>- **Raspberry Pi**
>- **Server (online shop)**
>- Mobile app

上面的代码添加了马特洪峰的图像,也可以使用纯 Markdown 语法或添加 HTML 标签来改进幻灯片。

要生成幻灯片,Pandoc 需要引用 Reveal.js 库,因此它必须与 SLIDES 文件位于同一文件夹中。生成幻灯片的命令如下所示:

pandoc -t revealjs -s --self-contained SLIDES \
-V theme=white -V slideNumber=true -o index.html

上面的 Pandoc 命令使用了以下参数:

  • -t revealjs 表示将输出一个 revealjs 演示文稿
  • -s 告诉 Pandoc 生成一个独立的文档
  • --self-contained 生成没有外部依赖关系的 HTML 文件
  • -V 设置以下变量:

    • theme=white 将幻灯片的主题设为白色
    • slideNumber=true 显示幻灯片编号
  • -o index.html 在名为 index.html 的文件中生成幻灯片

为了简化操作并避免键入如此长的命令,创建以下 Makefile:

all: generate

generate:
    pandoc -t revealjs -s --self-contained SLIDES \
    -V theme=white -V slideNumber=true -o index.html

clean: index.html
    rm index.html

.PHONY: all clean generate

可以在 这个仓库 中找到所有代码。

制作一份多种格式的合同

假设你正在准备一份文件,并且(这样的情况现在很常见)有些人想用 Microsoft Word 格式,其他人使用自由软件,想要 ODT 格式,而另外一些人则需要 PDF。你不必使用 OpenOffice 或 LibreOffice 来生成 DOCX 或 PDF 格式的文件,可以用 Markdown 创建一份文档(如果需要高级格式,可以使用一些 LaTeX 语法),并生成任何这些文件类型。

和以前一样,首先声明文档的元信息(标题、作者和日期):

% Contract Agreement for Software X
% Kiko Fernandez-Reyes
% August 28th, 2018

然后在 Markdown 中编写文档(如果需要高级格式,则添加 LaTeX)。例如,创建一个固定间隔的表格(在 LaTeX 中用 \hspace{3cm} 声明)以及客户端和承包商应填写的行(在 LaTeX 中用 \hrulefill 声明)。之后,添加一个用 Markdown 编写的表格。

创建的文档如下所示:

创建此文档的代码如下:

% Contract Agreement for Software X
% Kiko Fernandez-Reyes
% August 28th, 2018

...

### Work Order

\begin{table}[h]
\begin{tabular}{ccc}
The Contractor & \hspace{3cm} & The Customer \\
& & \\
& & \\
\hrulefill & \hspace{3cm} & \hrulefill \\
%
Name & \hspace{3cm} & Name \\
& & \\
& & \\
\hrulefill & \hspace{3cm} & \hrulefill \\
...
\end{tabular}
\end{table}

\vspace{1cm}

+--------------------------------------------|----------|-------------+
| Type of Service                            | Cost     |     Total   |
+:===========================================+=========:+:===========:+
| Game Engine                                | 70.0     | 70.0        |
|                                            |          |             |
+--------------------------------------------|----------|-------------+
|                                            |          |             |
+--------------------------------------------|----------|-------------+
| Extra: Comply with defined API functions   | 10.0     | 10.0        |
|        and expected returned format        |          |             |
+--------------------------------------------|----------|-------------+
|                                            |          |             |
+--------------------------------------------|----------|-------------+
| **Total Cost**                             |          | **80.0**    |
+--------------------------------------------|----------|-------------+

要生成此文档所需的三种不同输出格式,编写如下的 Makefile:

DOCS=contract-agreement.md

all: $(DOCS)
    pandoc -s $(DOCS) -o $(DOCS:md=pdf)
    pandoc -s $(DOCS) -o $(DOCS:md=docx)
    pandoc -s $(DOCS) -o $(DOCS:md=odt)

clean:
    rm *.pdf *.docx *.odt

.PHONY: all clean

4 到 7 行是生成三种不同输出格式的具体命令:

如果有多个 Markdown 文件并想将它们合并到一个文档中,需要按照希望它们出现的顺序编写命令。例如,在撰写本文时,我创建了三个文档:一个介绍文档、三个示例和一些高级用法。以下命令告诉 Pandoc 按指定的顺序将这些文件合并在一起,并生成一个名为 document.pdf 的 PDF 文件。

pandoc -s introduction.md examples.md advanced-uses.md -o document.pdf

模板和元信息

编写复杂的文档并非易事,你需要遵循一系列独立于内容的规则,例如使用特定的模板、编写摘要、嵌入特定字体,甚至可能要声明关键字。所有这些都与内容无关:简单地说,它就是元信息。

Pandoc 使用模板生成不同的输出格式。例如,有一个 LaTeX 的模板,还有一个 ePub 的模板,等等。这些模板的元信息中有未赋值的变量。使用以下命令找出 Pandoc 模板中可用的元信息:

pandoc -D FORMAT

例如,LaTex 的模版是:

pandoc -D latex

按照以下格式输出:

$if(title)$
\title{$title$$if(thanks)$\thanks{$thanks$}$endif$}
$endif$
$if(subtitle)$
\providecommand{\subtitle}[1]{}
\subtitle{$subtitle$}
$endif$
$if(author)$
\author{$for(author)$$author$$sep$ \and $endfor$}
$endif$
$if(institute)$
\providecommand{\institute}[1]{}
\institute{$for(institute)$$institute$$sep$ \and $endfor$}
$endif$
\date{$date$}
$if(beamer)$
$if(titlegraphic)$
\titlegraphic{\includegraphics{$titlegraphic$}}
$endif$
$if(logo)$
\logo{\includegraphics{$logo$}}
$endif$
$endif$

\begin{document}

如你所见,输出的内容中有标题、致谢、作者、副标题和机构模板变量(还有许多其他可用的变量)。可以使用 YAML 元区块轻松设置这些内容。 在下面例子的第 1-5 行中,我们声明了一个 YAML 元区块并设置了一些变量(使用上面合同协议的例子):

---
title: Contract Agreement for Software X
author: Kiko Fernandez-Reyes
date: August 28th, 2018
---

(continue writing document as in the previous example)

这样做非常奏效,相当于以前的代码:

% Contract Agreement for Software X
% Kiko Fernandez-Reyes
% August 28th, 2018

然而,这样做将元信息与内容联系起来,也即 Pandoc 将始终使用此信息以新格式输出文件。如果你将要生成多种文件格式,最好要小心一点。例如,如果你需要以 ePub 和 HTML 的格式生成合同,并且 ePub 和 HTML 需要不同的样式规则,该怎么办?

考虑一下这些情况:

  • 如果你只是尝试嵌入 YAML 变量 css:style-epub.css,那么将从 HTML 版本中移除该变量。这不起作用。
  • 复制文档显然也不是一个好的解决方案,因为一个版本的更改不会与另一个版本同步。
  • 你也可以像下面这样将变量添加到 Pandoc 命令中:
pandoc -s -V css=style-epub.css document.md document.epub
pandoc -s -V css=style-html.css document.md document.html

我的观点是,这样做很容易从命令行忽略这些变量,特别是当你需要设置数十个变量时(这可能出现在编写复杂文档的情况中)。现在,如果将它们放在同一文件中(meta.yaml 文件),则只需更新或创建新的元信息文件即可生成所需的输出格式。然后你会编写这样的命令:

pandoc -s meta-pub.yaml document.md document.epub
pandoc -s meta-html.yaml document.md document.html

这是一个更简洁的版本,你可以从单个文件更新所有元信息,而无需更新文档的内容。

结语

通过以上的基本示例,我展示了 Pandoc 在将 Markdown 文档转换为其他格式方面是多么出色。


via: https://opensource.com/article/18/9/intro-pandoc

作者:Kiko Fernandez-Reyes 选题:lujun9972 译者:jlztan 校对:wxy

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

虽然我们经常听到 系统管理器 System Manager 这词,但很少有人深究其确切意义。现在我们将向你展示其区别。

我会尽自己所能来解释清楚一切。我们大多都知道 System V 和 systemd 两种系统管理器。 System V (简写 SysV) 是老式系统所使用的古老且传统的初始化系统及系统管理器。

Systemd 是全新的初始化系统及系统管理器,并且已被大部分主流 Linux 发行版所采用。

Linux 系统中主要有三种有名而仍在使用的初始化系统。大多数 Linux 发行版都使用其中之一。

什么是初始化系统管理器?

在基于 Linux/Unix 的操作系统中,init (初始化的简称) 是内核启动系统时开启的第一个进程。

它持有的进程 ID(PID)号为 1,其在后台一直运行着,直到关机。

init 会查找 /etc/inittab 文件中相应配置信息来确定系统的运行级别,然后根据运行级别在后台启动所有的其它进程和应用。

作为 Linux 启动过程的一部分,BIOS、MBR、GRUB 和内核进程在此进程之前就被激活了。

下面列出的是 Linux 的可用运行级别(存在七个运行级别,从 0 到 6)。

  • 0:停机
  • 1:单用户模式
  • 2:多用户,无 NFS(LCTT 译注:NFS 即 Network File System,网络文件系统)
  • 3:全功能多用户模式
  • 4:未使用
  • 5:X11(GUI – 图形用户界面)
  • 6:重启

下面列出的是 Linux 系统中广泛使用的三种初始化系统。

  • System V (Sys V):是类 Unix 操作系统传统的也是首款初始化系统。
  • Upstart:基于事件驱动,是 /sbin/init 守护进程的替代品。
  • Systemd:是一款全新的初始化系统及系统管理器,它被所有主流的 Linux 发行版实现/采用,以替代传统的 SysV 初始化系统。

什么是 System V (Sys V)?

System V(Sys V)是类 Unix 操作系统传统的也是首款初始化系统。init 是系统由内核启动期间启动的第一个进程,它是所有进程的父进程。

起初,大多数 Linux 发行版都使用名为 System V(SysV)的传统的初始化系统。多年来,为了解决标准版本中的设计限制,发布了几个替代的初始化系统,例如 launchd、Service Management Facility、systemd 和 Upstart。

但只有 systemd 最终被几个主流 Linux 发行版所采用,以替代传统的 SysV。

什么是 Upstart?

Upstart 基于事件驱动,是 /sbin/init 守护进程的替代品。用来在启动期间控制任务和服务的启动,在关机期间停止它们,及在系统运行过程中监视它们。

它最初是为 Ubuntu 发行版开发的,但也可以在所有的 Linux 发行版中部署运行,以替代古老的 System V 初始化系统。

它用于 Ubuntu 9.10 到 14.10 版本和基于 RHEL 6 的系统中,之后的被 systemd 取代了。

什么是 systemd?

systemd 是一款全新的初始化系统及系统管理器,它被所有主流的 Linux 发行版实现/采用,以替代传统的 SysV 初始化系统。

systemd 与 SysV 和 LSB(LCTT 译注:Linux Standards Base) 初始化脚本兼容。它可以作为 SysV 初始化系统的直接替代品。其是内核启动的第一个进程并占有数字 1 的 PID,它是所有进程的父进程。

Fedora 15 是第一个采用 systemd 而不是 upstart 的发行版。systemctl 是一款命令行工具,它是管理 systemd 守护进程/服务(如 startrestartstopenabledisablereloadstatus)的主要工具。

systemd 使用 .service 文件而不是(SysV 初始化系统使用的) bash 脚本。systemd 把所有守护进程按顺序排列到自己 Cgroups (LCTT 译注:Cgroups 是 control groups 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离进程组所使用的物理资源,如:cpu、memory、IO 等的机制。最初由 Google 的工程师提出,后来被整合进 Linux 内核。Cgroups 也是 LXC 为实现虚拟化所使用的资源管理手段,可以说没有 cgroups 就没有 LXC)中,所以通过查看 /cgroup/systemd 文件就可以查看系统层次结构。

在 Linux 上如何识别出系统管理器

在系统上运行如下命令来查看运行着什么系统管理器:

(LCTT 译注:原文繁冗啰嗦,翻译时进行了裁剪整理。)

方法 1:使用 ps 命令

ps – 显示当前进程快照。ps 会显示选定的活动进程的信息。其输出不能确切区分出是 System V(SysV) 还是 upstart,所以我建议使用其它方法。

# ps -p1 | grep "init\|upstart\|systemd"
 1 ? 00:00:00 init

方法 2:使用 rpm 命令

RPM 即 Red Hat Package Manager (红帽包管理),是一款功能强大的安装包管理命令行工具,在基于 Red Hat 的发行版中使用,如 RHEL、CentOS、Fedora、openSUSE 和 Mageia。此工具可以在系统/服务上对软件进行安装、更新、删除、查询及验证等操作。通常 RPM 文件都带有 .rpm 后缀。

RPM 会使用必要的库和依赖库来构建软件,并且不会与系统上安装的其它包冲突。

# rpm -qf /sbin/init
SysVinit-2.86-17.el5

方法 3:使用 /sbin/init 文件

/sbin/init 程序会将根文件系统从内存加载或切换到磁盘。

这是启动过程的主要部分。这个进程开始时的运行级别为 “N”(无)。/sbin/init 程序会按照 /etc/inittab 配制文件的描述来初始化系统。

# /sbin/init --version
init (upstart 0.6.5)
Copyright (C) 2010 Canonical Ltd.

This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

via: https://www.2daygeek.com/how-to-determine-which-init-system-manager-is-running-on-linux-system/

作者:Prakash Subramanian 选题:lujun9972 译者:runningwater 校对:wxy

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

你是否想过尝试一些经典的 MS-DOS 游戏和像 Turbo C++ 这样的废弃的 C++ 编译器?这篇教程将会介绍如何使用 DOSBox 在 Linux 环境下运行 MS-DOS 的游戏和程序。DOSBox 是一个 x86 平台的 DOS 模拟器,可以用来运行经典的 DOS 游戏和程序。 DOSBox 可以模拟带有声音、图形、鼠标、操纵杆和调制解调器等的因特尔 x86 电脑,它允许你运行许多旧的 MS-DOS 游戏和程序,这些游戏和程序根本无法在任何现代 PC 和操作系统上运行,例如 Microsoft Windows XP 及更高版本、Linux 和FreeBSD。 DOSBox 是免费的,使用 C++ 编程语言编写并在 GPL 下分发。

在 Linux 上安装 DOSBox

DOSBox 在大多数 Linux 发行版的默认仓库中都能找的到。

在 Arch Linux 及其衍生版如 Antergos、Manjaro Linux 上:

$ sudo pacman -S dosbox

在 Debian、Ubuntu、Linux Mint 上:

$ sudo apt-get install dosbox

在 Fedora 上:

$ sudo dnf install dosbox

配置 DOSBox

DOSBox 是一个开箱即用的软件,它不需要进行初始化配置。它的配置文件位于 ~/.dosbox 文件夹中,名为 dosbox-x.xx.conf。 在此配置文件中,你可以编辑/修改各种设置,例如以全屏模式启动 DOSBox,全屏使用双缓冲,设置首选分辨率,鼠标灵敏度,启用或禁用声音,扬声器,操纵杆等等。如前所述,默认设置即可正常工作。你可以不用进行任何更改。

在 Linux 中运行 MS-DOS 上的游戏和程序

在终端运行以下命令启动 DOSBox:

$ dosbox

下图就是 DOSBox 的界面

正如你所看到的,DOSBox 带有自己的类似 DOS 的命令提示符和一个虚拟的 Z:\ 的驱动器,如果你熟悉 MS-DOS 的话,你会发现在 DOSBox 环境下工作不会有任何问题。

这是 dir 命令(在 Linux 中等同于 ls 命令)的输出:

如果你是第一次使用 DOSBox,你可以通过在 DOSBox 提示符中输入以下命令来查看关于 DOSBox 的简介:

intro

在介绍部分按回车进入下一页。

要查看 DOS 中最常用命令的列表,请使用此命令:

help

要查看 DOSBox 中所有支持的命令的列表,请键入:

help /all

记好了这些命令应该在 DOSBox 提示符中使用,而不是在 Linux 终端中使用。

DOSBox 还支持一些实用的键盘组合键。下图是能有效使用 DOSBox 的默认键盘快捷键。

要退出 DOSBox,只需键入如下命令并按回车:

exit

默认情况下,DOSBox 开始运行时的正常屏幕窗口大小如上所示。

要直接在全屏启动 DOSBox,请编辑 dosbox-x.xx.conf 文件并将fullscreen 变量的值设置为 enable。 之后,DOSBox 将以全屏模式启动。 如果要返回正常屏幕,请按 ALT+ENTER

希望你掌握了 DOSBox 的这些基本用法。

让我们继续安装一些 DOS 程序和游戏。

首先,我们需要在 Linux 系统中创建目录来保存程序和游戏。我将创建两个名为 ~/dosprograms~/dosgames 的目录,第一个用于存储程序,后者用于存储游戏。

$ mkdir ~/dosprograms ~/dosgames

出于本指南的目的,我将向你展示如何安装 Turbo C++ 程序和 Mario 游戏。我们首先将看到如何安装 Turbo。

下载最后版本的 Turbo C++ 编译器并将其解压到 ~/dosprograms 目录中。 我已经将 Turbo C++ 保存在在我的 ~/dosprograms/TC/ 目录中了。

$ ls dosprograms/tc/

BGI BIN CLASSLIB DOC EXAMPLES FILELIST.DOC INCLUDE LIB README README.COM

运行 DOSBox:

$ dosbox

~/dosprograms 目录挂载为 DOSBox 中的虚拟驱动器 C:\

Z:\>mount c ~/dosprograms

你会看到类似下面的输出:

Drive C is mounted as local directory /home/sk/dosprograms.

现在,使用命令切换到 C 盘:

Z:\>c:

然后切换到 tc/bin 目录:

Z:\>cd tc/bin

最后,运行 Turbo C++ 可执行文件:

Z:\>tc.exe

备注:只需输入前几个字母,然后按回车键可以自动填充文件名。

你现在将进入 Turbo C++ 控制台。

创建新文件(ATL + F)并开始编程:

你可以同样安装和运行其他经典 DOS 程序。

故障排除:

运行 Turbo C++ 或其他任何 DOS 程序时,你可能会遇到以下错误:

DOSBox switched to max cycles, because of the setting: cycles=auto. If the game runs too fast try a fixed cycles amount in DOSBox's options. Exit to error: DRC64:Unhandled memory reference

要解决此问题,编辑 ~/.dosbox/dosbox-x.xx.conf 文件:

$ nano ~/.dosbox/dosbox-0.74.conf

找到以下变量:

core=auto

并更改其值为:

core=normal

现在,让我们看看如何运行基于DOS的游戏,例如 Mario Bros VGA

这里 下载 Mario 游戏,并将其解压到 Linux 中的 ~/dosgames 目录。

运行 DOSBox:

$ dosbox

我们刚才使用了虚拟驱动器 C: 来运行 DOS 程序。现在让我们使用 D: 作为虚拟驱动器来运行游戏。

在 DOSBox 提示符下,运行以下命令将 ~/dosgames 目录挂载为虚拟驱动器 D

Z:\>mount d ~/dosgames

进入驱动器 D:

Z:\>d:

然后进入 mario 游戏目录并运行 mario.exe 文件来启动游戏。

D:\>cd mario
D:\>mario.exe

开始玩游戏:

你可以同样像上面所说的那样运行任何基于 DOS 的游戏。 点击这里查看可以使用 DOSBox 运行的游戏的完整列表。

总结

尽管 DOSBox 并不能作为 MS-DOS 的完全替代品,并且还缺少 MS-DOS 中的许多功能,但它足以安装和运行大多数的 DOS 游戏和程序。

有关更多详细信息,请参阅官方 DOSBox手册

这就是全部内容。希望这对你有用。更多优秀指南即将到来。 敬请关注!

干杯!


via: https://www.ostechnix.com/how-to-run-ms-dos-games-and-programs-in-linux/

作者:SK 选题:lujun9972 译者:way-ww 校对:wxy

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

这篇文章将会教你如何在 10 分钟中内借助 WordPress 搭建一个支持 ERC20 通证的在线 B2C 商城。

在区块链及通证经济备受瞩目的今天,很多开源社区纷纷在探讨如何将开源社区与区块链技术和通证经济相结合,从而为开源社区和开源生态提供自主、自洽、发展的动力和支持。我们 “Linux 中国”就是这诸多探索的开源社区之一。可喜的是,我们已经迈出了第一步:发布社区通证,也迈出了第二步,使通证流通起来。这里,我们愿意分享我们的经验给各个社区伙伴,使更多的开源社区也可以投身于新的生态探索,避开一些我们遇到的陷阱,从而共同营造一个更繁荣的开源世界。

我们的通证商城是基于 WordPress 的 WooCommerce 商城构建的。

安装 WordPress

在开始配置商城前,你需要先安装 WordPress 。你需要购买一个支持 PHP + MySQL 的虚拟主机,或自行配置 VPS、云服务器的环境,以支持 WordPress 的运行。

当你安装好 WordPress 后,你可以看到一个这样的后台。

安装 WooCommerce

安装完 WordPress 后,接下来安装 WordPress 的商城插件 WooCommerce ,点击菜单栏中的“插件”-“安装插件”,访问到安装插件的界面,在界面右上角的搜索框内容输入“WooCommerce”,并按下回车,可以搜索到 WooCommerce 。

点击现在安装,来安装 WooCommerce。安装完成后,点击“启用”,启用插件。

启用插件后, WooCommerce 会引导你进行初始化配置,根据提示对插件进行配置。

必要时,可以允许线下支付,但是针对加密货币而言,目前看起来不需要线下支付场景:

并设置邮费:

插件安装时,取消 MailChimp 的安装,仅启用 StoreFront:

并视需要觉得是否安装还是跳过 JetPack :

当你看到如图所示的界面时,就说明完成了初始化的配置了。

点击访问控制面板,回到 WordPress 界面。

添加 ERC20 通证作为支付货币

为了原生支持 ERC20 通证来实现支付,从而免去汇率换算,我们需要添加一款自定义的货币。

打开“插件”-“安装插件”,在关键词中输入 “Woocommerce Customize ERC20 Currency”并回车。这是我们联合硬核区块链公司开发的一款用于给 WooCommerce 增加 ERC20 货币的插件,该插件已经开源于 GitHub

找到 “Woocommerce Customize ERC20 Currency” 插件,并安装。

安装,并启用 “Woocommerce Customize ERC20 Currency”。

启用插件后,点击左侧菜单中的“设置”-“WooCommerce ERC20 货币自定义”,进入到插件的设置界面。

在插件的设置界面,你可以设置需要添加的货币的名称和对应的符号。比如这里我设置为 “LCCN” 和 “Ⓛ”,并点击“保存”。

保存后,点击左侧菜单栏中的“WooCommerce”-“设置”,进入到 WooCommerce 设置界面,在常规选项中,拖动到最底部,可以看到币种选项。点击货币,找到你自己设置的货币后,点击“设置”,并“保存”设置。

此时,站点的商品便以你自己设定的 ERC20 通证作为支付货币进行交易了。

安装 ERC20 通证支付网关

接下来,我们来安装“Woocommerce ERC20 Payment Gateway” 来开启站点的 ERC20 Token 的支付支持。这也是我们联合硬核区块链公司开发的一款用于给 WooCommerce 提供 ERC20 货币支付支持的插件,该插件已经开源于 GitHub

点击左侧菜单栏中的“插件”-“安装插件”,在关键词中输入 “Woocommerce ERC20 Payment Gateway”,并回车,找到 “Woocommerce ERC20 Payment Gateway”并安装、启用。

安装,并启用完成后,点击插件后的“设置”,进入到设置页面。

在设置页面,启用 “使用 ERC 20 Token 支付”这一支付方式,并保存。

然后点击支付方式后面的“设置”,进入到插件的设置界面。

首先,设置一些支付方式的基础信息。

标题是支付方式的标题,将会展示在结账的页面,因此,你可以将其设置为诸如“使用 LCCN 支付费用”或其他内容,让顾客明白此支付方式为使用通证支付。

描述会展示在支付方式的下方,同样的,你可以设置为 “使用 LCCN 支付费用”,此外,还建议你在此引导顾客安装、并打开 Metask 插件,切换到主网络,确保后续支付。

支付方式图标则会展示在支付方式标题后,将其设置为你的通证的图标,以获得更明显的提醒效果。

三者具体的示意图如下

支付方式设置完成后,接下来设置与 ERC20 通证有关的内容。

钱包地址为顾客支付时转账的对象,将其设置为你自己的钱包地址即可。

合约 ABI 则可以在 etherscan 中找到,比如,LCCN 的合约地址为:https://etherscan.io/address/0x8f4f3b3c3a900d10e9cf74c30e16f5958d8fd339#code,由于 LCCN 公开了其合约源代码,其 ABI 可以在合约的界面找到(如未公开,请向你的 ERC20 合约开发人员索要 ABI),点击右侧 “Copy”,复制 ABI,并将其填入设置项目中去。

合约地址为你的合约在对应网络中的地址。切记,如果你是测试环境,就需要将其设置为对应测试网络下的合约地址,如果是生产环境,就设置为主网的合约地址。

Gas 提醒这里是用来提醒用户支付时选择较高的 Gas ,从而加快确认的速度。你可以根据自己的需要设置具体的内容,也可以使用默认的语句。

至此,插件就已经设置完成了。

测试支付

插件设置完成后,我们来新建一个产品,用于测试。点击顶栏中的“新建”-“产品”,进入到创建产品的界面。

在产品界面输入产品名称、描述、售价等信息:

然后点击发布,创建新的产品。并点击“查看产品”,进入到产品的主页。

将其加入购物车:

在购物车界面点击“结算”,进行结算。

输入账单地址(账单地址将作为收货地址显示在界面中),点击“使用 Token 完成支付”。

在结算页面,拖动到底部,可以看到支付按钮,点击支付按钮,会自动唤起浏览器的 Metamask 插件。

在弹出的窗口中确认支付:

支付完成后,页面会自动刷新,并看到支付完成的字样。

处理订单

用户支付完成后,如何确定订单已经支付完成了呢?进入后台“仪表盘”-“WooCommerce”-“订单”,可以看到用户所有的订单。

正在处理状态的订单为用户已经支付完成,还没有处理的订单。点击该订单,进入到订单详情,在右侧的“订单备注”中可以看到交易的 Tx 值 。你可以点击对应链接,查看交易是否完成。

至此,整个使用 ERC20 通证的交易流程就走通了,接下来你就可以创建商品,使用 ERC20 通证 来完成你的 ERC20 在线交易流程啦!

关于硬核区块链

硬核区块链是一个区块链技术服务提供商,我们为顾客提供全面的 ERC20 通证发行、安全审计、解决方案构建、流通流程设计、 空投解决方案等服务,为顾客提供咨询与支付服务。

相关链接