如何将Maven项目版本获​​取到bash命令行


201

上一期,我提出了一个有关如何从命令行更改Maven项目版本的问题,这导致我遇到了新问题。

以前,我能够获得版本号,因为版本存储为易于通过命令行(bash)进行grep和解析的属性。现在已经使用了pom.xml元素,它不再是唯一的,因为所有依赖项(可能还有其他依赖项)也都使用了此元素。我认为,没有外部工具来解析xml或一些非常了解上下文的sed命令,就无法通过bash脚本获取当前版本号。

在我看来,最干净的解决方案是让Maven分发此版本信息。我当时正在考虑编写一个自定义的Maven插件来检索不同的属性,但是我想先在这里问一下。

那么,是否有任何简单的方法来获取${project.version}命令行的值?提前致谢。

感谢您的帮助。我不得不cd手动访问目录,但是可以轻松完成。在我的bash脚本中,我有

version=`cd $project_loc && mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | sed -n -e '/^\[.*\]/ !{ /^[0-9]/ { p; q } }'`

这给了我当前的版本,然后可以进行升级。暂存可能会更简单,但是我想我想尽可能地强大,所以我对以数字开头的第一行感到满意,并尝试将其作为版本号来处理。

# Advances the last number of the given version string by one.
function advance_version () {
    local v=$1
    # Get the last number. First remove any suffixes (such as '-SNAPSHOT').
    local cleaned=`echo $v | sed -e 's/[^0-9][^0-9]*$//'`
    local last_num=`echo $cleaned | sed -e 's/[0-9]*\.//g'`
    local next_num=$(($last_num+1))
    # Finally replace the last number in version string with the new one.
    echo $v | sed -e "s/[0-9][0-9]*\([^0-9]*\)$/$next_num/"
}

我通过简单地调用

new_version=$(advance_version $version)

希望这对某人有帮助。


1
解决方案似乎错过了'以完成sed表达式。
nawroth 2011年

哪个sed exp?我似乎没注意到。
mkko 2011年

1
使之成为MVN -o以加快执行速度
弥敦道Bubna

2
您可以用一个简单的grep -e '^[[:digit:]]'
bedman

2
如果您按照@NathanBubna的建议使用-o,那么这会将maven置于“离线”模式。如果您尚未下载maven帮助插件和相关的jar,则构建将失败。被这件事烧掉了一点,希望对别人有帮助。
phillipuniverse

Answers:


217

Maven的帮助插件以某种方式已经提出的东西这样的:

  • help:evaluate 以交互方式评估用户给出的Maven表达式。

这是您在命令行上调用它以获取的方式${project.version}

mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate \
    -Dexpression=project.version

8
好的谢谢。我认为这是最接近清洁解决方案的方法。有什么想法可以抑制maven输出并过滤掉这些[INFO]消息吗?我没有找到Maven的开关。否则,我将只添加一些命令行脚本来解析版本号。
mkko 2010年

80
我正在使用mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version|grep -Ev '(^\[|Download\w+:)'
Chadwick

13
别指望行家这么冗长
安迪(Andy)

24
这是我支持的方法:printf 'VERSION=${project.version}\n0\n' | mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate | grep '^VERSION'
ash

40
@montoyaed发布了最佳答案,就是mvn help:evaluate -Dexpression=project.version -q -DforceStdout。要捕获它在猛砸使用一个变量version=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
塞巴斯蒂安Thomschke

200

Tom使用Exec Maven插件的解决方案要好得多,但仍然比需要的复杂。对我来说,这很简单:

MVN_VERSION=$(mvn -q \
    -Dexec.executable=echo \
    -Dexec.args='${project.version}' \
    --non-recursive \
    exec:exec)

30
我认为这是最简单的方法,因为它并不意味着使用grep或类似的东西。快速说明:您可以将其缩短一些:mvn -q -Dexec.executable="echo" -Dexec.args='${project.version}' --non-recursive exec:exec
scrutari

1
该解决方案对我来说效果很好,因为我想打印groupId,artifactId和版本-Dexec.args='${project.groupId}:${project.artifactId}:${project.version}'
James H.

1
[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.3.2:exec (default-cli) on project audit-events-processor-parent: Command execution failed. Cannot run program "maven" (in directory "/tmp"): error=2, No such file or directory 耸耸肩另一个对我不起作用的答案,哦,很好
cbmanica

谢谢你,这是到目前为止我所见过的最好的解决方案,因为它不需要应用易碎的grep / sed命令或类似命令
Mike76 '17

什么是set -o errexit
theonlygusti

79

我一直在做一些研究,发现以下几点:

  1. Maven被指责是因为与DevOps工具集成并不容易,因为它没有遵循有关CLI工具的一些良好实践。(参考:https : //youtu.be/1ILEw6Qca3U? t =372

  2. 受前一个断言的启发,我决定看一下maven的源代码以及maven-help-plugin。看来他们已经修复了Maven的-q开关(我正在使用3.5.3版),所以现在如果您通过它,您将不会得到所有讨厌的无意义的日志记录内容,这些东西会阻止Maven被使用在自动脚本中。因此,您应该可以使用如下所示的内容:

    mvn help:evaluate -Dexpression=project.version -q

    问题在于该命令不打印任何内容,因为默认情况下,帮助插件通过记录器输出,而记录器已被-q开关静音。(该插件的最新可用版本是2018年6月3日发布的3.1.0)

  3. Karl Heinz Marbaise(https://github.com/khmarbaise)通过添加可选参数来修复它,该参数允许您通过以下方式调用它:

    mvn help:evaluate -Dexpression=project.version -q -DforceStdout

    提交说明位于:(https://github.com/apache/maven-help-plugin/commit/316656983d780c04031bbadd97d4ab245c84d014


2
这将是我的首选解决方案,并且在官方帮助页面上也提到了该解决方案。但是,它对我不起作用。我在使用Maven v3.5.3的MacOS上。当我不使用-q开关时,它将正确打印出版本(在日志行之间)。有任何想法吗?
gucce

3
这应该是公认的答案。它可以在Windows和Linux(我没有尝试过Max OSX)中工作,而且很简单。谢谢。
垃圾桶

1
@montoyaedu对不起,您没有回复。在此期间,我已更新到maven 3.5.4,该版本可以在该-q开关上正常工作。
gucce

1
@gucce我可以确认使用的Maven版本会影响此效果:对于3.5.2(debian 9上的软件包版本)-q -DforceStdout,即使确保插件的3.1.0版本与pluginManagement一起使用,输出也为空。我用3.5.4版的Maven配置了Maven包装器,并且它正常工作
Gorkk

3
最后,2019年没有grep的实用解决方案-(这应该成为公认的答案)。作品与CI-友好的版本太-在3.3.9测试,3.5.3,3.5.4,3.6.0
埃德·兰德尔

47
mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\['

2
作出这样的MVN -o以加快执行速度
弥敦道Bubna

1
请参阅我的答案(quickshiftin),该答案也在下面过滤“已下载:”行。
quickshiftin 13-10-8

10
如果您按照@NathanBubna的建议使用-o,那么这会将maven置于“离线”模式。如果您尚未下载maven帮助插件和相关的jar,则构建将失败。被这件事烧掉了一点,希望对别人有帮助。
phillipuniverse

您可能还想添加2> /dev/null,否则您将获得Picked up _JAVA_OPTIONS:
Jakub Bochenski 2015年

2
在Windows上,将命令末尾替换为| findstr /v "["
Tunaki

39

在我看来,最佳答案是非常垃圾,您必须使用一堆grep来破解Maven控制台输出。为什么不使用正确的工具进行工作?使用xpath语法是检索版本号的最佳方法,因为它是访问XML数据结构的预期方法。下面的表达式使用元素的“本地名称”遍历pom,换句话说,就是忽略xml中可能存在或可能不存在的名称空间声明。

xmllint --xpath "//*[local-name()='project']/*[local-name()='version']/text()" pom.xml

@bobmarksie我赞成 使用Maven并使用regexp的输出擦洗是很痛苦的。
mhvelplund

3
从父pom继承的项目呢?
Wes

2
“为什么不使用正确的工具来完成这项工作?” IE浏览器!
jeremyjjbrown

我知道使用mvn是正确的方法,并且exec插件实际上可以很好地工作,但是所有的mvn解决方案都必须解决,并且我正在尝试引导无法解决依赖关系解析的构建管道,因此,我将exec用此解决方案替换该方法。幸运的是,我不必担心从父母那里继承来的版本。
haridsv

此功能不适用于ci友好的版本控制,例如,版本是诸如此类的属性${revision}。参考 maven.apache.org/maven-ci-friendly.html
Ed Randall

30

这将避免需要从输出中删除日志条目:

mvn -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive exec:exec -q

尽管此代码可以回答问题,但提供有关其为什么和/或如何回答问题的其他上下文将大大提高其长期价值。请编辑您的答案以添加一些说明。
Toby Speight

1
我认为对于这种方法,有必要在mvn之后加上“ -q”。
拉奇

这比公认的解决方案要好。无需过滤掉Maven嘈杂的输出。
Willian Mitsuda

19

这是我发现的最干净的解决方案

mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -q -DforceStdout

优点:

  • 所有操作系统和所有外壳上可以正常工作。
  • 无需任何外部工具!

注意:

  • maven-help-plugin版本3.2.0(及更高版本)具有forceStdout选项。您可以使用来自工件的mvn-help-plugin3.2.0可用版本列表(如果可用)中的较新版本替换上述命令。
  • 选项-q禁止显示详细消息([INFO][WARN]等等)

如果你想获取groupIdartifactId为好,检查这个答案


13
python -c "import xml.etree.ElementTree as ET; \
  print(ET.parse(open('pom.xml')).getroot().find( \
  '{http://maven.apache.org/POM/4.0.0}version').text)"

只要您拥有python 2.5或更高版本,它就可以工作。如果您的版本低于此版本,请安装python-lxml并将导入更改为lxml.etree。这种方法快速,不需要下载任何额外的插件。它也适用于格式不正确的pom.xml文件,这些文件无法通过xmllint进行验证,例如我需要解析的文件。在Mac和Linux上测试。


12

在这里使用其他一些答案时,我经常遇到其他情况,因此这是另一种选择。

version=$(printf 'VER\t${project.version}' | mvn help:evaluate | grep '^VER' | cut -f2)

1
printf 'VER\t${project.version}' | mvn help:evaluate 2> /dev/null | grep '^VER' | cut -f2
yegeniy

7

如果您不介意将版本写入临时文件,那么还有另一种解决方案(不带grep / sed)对我来说很好。(编辑:请参见rjrjr的答案,以获得更简单的解决方案,而无需任何临时文件麻烦)

我将Exec Maven插件echo二进制文件一起使用。与Maven帮助插件相反,Exec插件允许将输出重定向到文件中,该文件可用于绕过grep / sed,甚至可以解析诸如多行版本字符串(在version标签中带有CDATA块)之类的奇怪内容,至少在一定程度上。

#!/usr/bin/env sh

MVN_VERSION=""
VERSION_FILE=$( mktemp mvn_project_version_XXXXX )
trap "rm -f -- \"$VERSION_FILE\"" INT EXIT

mvn -Dexec.executable="echo" \
    -Dexec.args='${project.version}' \
    -Dexec.outputFile="$VERSION_FILE" \
    --non-recursive \
    --batch-mode \
    org.codehaus.mojo:exec-maven-plugin:1.3.1:exec > /dev/null 2>&1 ||
    { echo "Maven invocation failed!" 1>&2; exit 1; }

# if you just care about the first line of the version, which will be
# sufficent for pretty much every use case I can imagine, you can use
# the read builtin
[ -s "$VERSION_FILE" ] && read -r MVN_VERSION < "$VERSION_FILE"

# Otherwise, you could use cat.
# Note that this still has issues when there are leading whitespaces
# in the multiline version string
#MVN_VERSION=$( cat "$VERSION_FILE" )

printf "Maven project version: %s\n" "$MVN_VERSION"

6
这是比帮助程序插件更好的解决方案,并且您不需要所有的I / O。只需添加-q标志,唯一的输出就是版本。因此:mvn -q -Dexec.executable =“ echo” -Dexec.args ='$ {project.version}'--non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec
rjrjr

rjrjr:太好了!我唯一需要在这里提及的是错误处理:如果mvn失败,您将获得无效的版本字符串。因此,需要进行一些验证,例如检查mvn返回码或字符串本身。
汤姆

6

仅作记录,可以通过以下命令直接在命令行中配置Maven的Simple SLF4J日志记录,以仅输出我们需要的内容:

  • org.slf4j.simpleLogger.defaultLogLevel=WARN
  • org.slf4j.simpleLogger.log.org.apache.maven.plugins.help=INFO

http://www.slf4j.org/api/org/slf4j/impl/SimpleLogger.html所述

MAVEN_OPTS="\
-Dorg.slf4j.simpleLogger.defaultLogLevel=WARN \
-Dorg.slf4j.simpleLogger.log.org.apache.maven.plugins.help=INFO" \
mvn help:evaluate -o -Dexpression=project.version

结果,一个人可以简单地运行tail -1并获得:

$ MAVEN_OPTS="\
-Dorg.slf4j.simpleLogger.defaultLogLevel=WARN \
-Dorg.slf4j.simpleLogger.log.org.apache.maven.plugins.help=INFO" \
mvn help:evaluate -o -Dexpression=project.version | tail -1

1.0.0-SNAPSHOT

请注意,这是单线的。MAVEN_OPTS仅针对此特定mvn执行而被重写。


5

我注意到Downloaded:输出中出现一些虚假行,这些行打破了我的原始任务。这是我确定的过滤条件;希望能帮助到你!

version=$(mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | egrep -v '^\[|Downloading:' | tr -d ' \n')

编辑

不是100%知道为什么,但是在Jenkins中通过后构建脚本运行此脚本时,输出结果为[INFO]version,例如[INFO]0.3.2

我将输出转储到文件中,并直接从BASH通过我的第一个过滤器运行它,它工作正常。

为了在詹金斯获得100%的收益,我添加了一个后续sed过滤器;这是我的最新消息

version=$(mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | egrep -v '^\[|Downloading:' | tr -d ' \n' | sed -E 's/\[.*\]//g')

编辑

最后一点在这里..我发现tr仍在造成之类的东西/r/n0.3.2(又只能通过詹金斯运行时)。切换至awk该问题已消失!我的最终工作结果

mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version \
| egrep -v '^\[|Downloading:' | sed 's/[^0-9\.]//g' | awk 1 ORS=''

5

一个仅适用于Maven的简单解决方案

mvn -q -N org.codehaus.mojo:exec-maven-plugin:1.3.1:exec \
    -Dexec.executable='echo' \
    -Dexec.args='${project.version}'

并为奖励积分解析了一部分版本

mvn -q -N org.codehaus.mojo:build-helper-maven-plugin:3.0.0:parse-version \
    org.codehaus.mojo:exec-maven-plugin:1.3.1:exec \
    -Dexec.executable='echo' \
    -Dexec.args='${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}'

5

我最近开发了Release Candidate Maven插件,它解决了这个确切的问题,因此您不必求助于任何骇人听闻的Shell脚本并解析maven-help-plugin

例如,要将Maven项目的版本打印到终端,请运行:

mvn com.smartcodeltd:release-candidate-maven-plugin:LATEST:version

其输出类似于maven-help-plugin

[INFO] Detected version: '1.0.0-SNAPSHOT'
1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

但是,您也可以指定任意的输出格式(以便CI服务器(例如TeamCity)可以从日志中获取版本:

mvn com.smartcodeltd:release-candidate-maven-plugin:LATEST:version \
   -DoutputTemplate="##teamcity[setParameter name='env.PROJECT_VERSION' value='{{ version }}']"

结果是:

[INFO] Detected version: '1.0.0-SNAPSHOT'
##teamcity[setParameter name='env.PROJECT_VERSION' value='1.0.0-SNAPSHOT']
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

要将输出保存到文件(以便诸如Jenkins的CI服务器可以使用它):

mvn com.smartcodeltd:release-candidate-maven-plugin:LATEST:version \
   -DoutputTemplate="PROJECT_VERSION={{ version }}" \
   -DoutputUri="file://\${project.basedir}/version.properties"

生成的version.properties文件如下所示:

PROJECT_VERSION=1.0.0-SNAPSHOT

除此之外,Release Candidate还允许您基于在POM中定义的API版本来设置项目的版本(这可能是您在CI服务器上所做的事情)。

如果您希望看到一个示例Release Release用作Maven生命周期的一部分,请查看pom.xml我的另一个开源项目-Build Monitor for Jenkins的示例。


5

还有一种不需要Maven的选项:

grep -oPm1 "(?<=<version>)[^<]+" "pom.xml"

这个仅显示pom中的第一次出现。在我的情况下,第一次出现会给出父pom版本。但是说实话,这是我一直在寻找的答案。它比前面提到的解决方案要快得多,并且很容易对其进行修改以使其正确出现。为了获得第二次出现,使用:grep -oPm2 "(?<=<version>)[^<]+" pom.xml | sed -n 2p为了获得第三次出现,使用:grep -oPm3 "(?<=<version>)[^<]+" pom.xml | sed -n 3p依此类推
KrzysztofCieśliński

您假设版本元素是第一个出现,并且当该假设无效时它不起作用。
devildelta

3

易于理解的多合一解决方案,可输出maven项目版本,并抑制来自[INFO]Download消息的多余输出:

mvn -o org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\['

同样,但分为两行:

mvn -o org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate \
      -Dexpression=project.version | grep -v '\['

输出: 4.3-SNAPSHOT

因此,project.version在简单的bash脚本中使用:

projectVersion=`mvn -o org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\['`
cd "target/"$projectVersion"-build"

此页面上的其他解决方案似乎并未将所有技巧结合在一起。



3

到目前为止,这是最简单的bash剪切和粘贴解决方案:

VERSION=$(mvn -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive exec:exec -q)
echo $VERSION

它回声

1.4

2

我找到了合适的平衡点。在mvn packagemaven-archiver插件创建后target/maven-archiver/pom.properties,内容如下

version=0.0.1-SNAPSHOT
groupId=somegroup
artifactId=someArtifact

我正在使用bash只是为了执行它

. ./target/maven-archiver/pom.properties

然后

echo $version
0.0.1-SNAPSHOT

当然,执行此文件根本不安全,但是可以轻松地将执行转换为perl或bash脚本以从该文件读取和设置环境变量。


1

这对我有用,离线并且不依赖于mvn:

VERSION=$(grep --max-count=1 '<version>' <your_path>/pom.xml | awk -F '>' '{ print $2 }' | awk -F '<' '{ print $1 }')
echo $VERSION


1

基于这个问题,我在下面使用此脚本自动增加所有maven父级/子模块中的版本号:

#!/usr/bin/env bash  

# Advances the last number of the given version string by one.  
function advance\_version () {  
    local v=$1  
    \# Get the last number. First remove any suffixes (such as '-SNAPSHOT').  
  local cleaned=\`echo $v | sed \-e 's/\[^0-9\]\[^0-9\]\*$//'\`  
 local last\_num=\`echo $cleaned | sed \-e 's/\[0-9\]\*\\.//g'\`  
 local next\_num=$(($last\_num+1))  
  \# Finally replace the last number in version string with the new one.  
  echo $v | sed \-e "s/\[0-9\]\[0-9\]\*\\(\[^0-9\]\*\\)$/$next\_num/"  
}  

version=$(mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -q -DforceStdout)  

new\_version=$(advance\_version $version)  

mvn versions:set -DnewVersion=${new\_version} -DprocessAllModules -DgenerateBackupPoms=false

0

您可以mvn给答案(如大多数答案所建议),也可以从中提取答案pom.xml。第二种方法的唯一缺点是,您可以非常轻松地提取<version/>标记的值,但是仅当它是文字时才有意义,即不是Maven属性。我之所以选择这种方法,是因为:

  • mvn 是冗长的方式,我只是不喜欢过滤其输出。
  • 开始mvn时相比很慢阅读pom.xml
  • 我总是在中使用文字值<version/>

mvn-version是一个zshshell脚本,用于xmlstarlet读取pom.xml和打印项目的版本(如果存在)或父项目的版本(如果存在):

$ mvn-version .
1.0.0-SNAPSHOT

其优点是,它是这样的速度比运行mvn

$ time mvn-version .
1.1.0-SNAPSHOT
mvn-version .  0.01s user 0.01s system 75% cpu 0.019 total

$ time mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate \
> -Dexpression=project.version
mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate   4.17s user 0.21s system 240% cpu 1.823 total

我的机器上的差异大于两个数量级。


0

在Travis工作期间,我确实需要此要求,但需要多个值。我从此解决方案开始,但是在多次调用时这很慢(我需要5个表达式)。

我编写了一个简单的maven插件,将pom.xml的值提取到.sh文件中。

https://github.com/famaridon/ci-tools-maven-plugin

mvn com.famaridon:ci-tools-maven-plugin:0.0.1-SNAPSHOT:environment -Dexpressions=project.artifactId,project.version,project.groupId,project.build.sourceEncoding

将产生:

#!/usr/bin/env bash
CI_TOOLS_PROJECT_ARTIFACTID='ci-tools-maven-plugin';
CI_TOOLS_PROJECT_VERSION='0.0.1-SNAPSHOT';
CI_TOOLS_PROJECT_GROUPID='com.famaridon';
CI_TOOLS_PROJECT_BUILD_SOURCEENCODING='UTF-8';

现在您可以简单地获取文件

source .target/ci-tools-env.sh

玩得开心。


-1

我在unix shell中使用单线...

猫pom.xml | grep“” | 头-n 1 | sed -e“ s / version // g” | sed -e“ s / \ s * [<> /] * // g”

您可以将此行隐藏在Shell脚本中或作为别名。


-1

这是上面的编辑

猫pom.xml | grep“” | 头-n 1 | sed -e“ s / version // g” | sed -e“ s / \ s * [<> /] * // g”

我在cmdline上进行了测试,效果很好

grep“” pom.xml | 头-n 1 | sed -e“ s / version // g” | sed -e“ s / \ s * [<> /] * // g”

是同一版本的另一个版本。我需要在未安装mvn的k8s中获取Jenkins CI中的版本号,因此这是最有用的

谢谢大家


-2
mvn help:evaluate -Dexpression=project.version | sed -e 1h -e '2,3{H;g}' -e '/\[INFO\] BUILD SUCCESS/ q' -e '1,2d' -e '{N;D}' | sed -e '1q'

我只是添加了sed我最近实现的project.version从Maven输出中提取的小型过滤器改进。


-2
VERSION=$(head -50 pom.xml | awk -F'>' '/SNAPSHOT/ {print $2}' | awk -F'<' '{print $1}')

这是我用来获取版本号的方式,以为会有更好的行家方式

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.