为什么停运问题如此重要?


149

我不明白为什么经常使用“ 暂停问题”来消除确定程序是否暂停的可能性。维基百科[article] [1]正确地解释了具有有限内存的确定性机器将停止或重复先前的状态。您可以使用算法来检测链表是否循环以实现具有O(1)空间复杂度的停止功能。

在我看来,“停顿问题”证明无非就是所谓的“悖论”,它是自欺欺人的自相矛盾(至少是周期性的),与说谎者的悖论一样。它得出的唯一结论是,停止功能容易受到此类格式错误的问题的影响。

因此,除矛盾的程序外,停止功能是可以确定的。那么,为什么我们认为它是相反的证据呢?

4年后:当我写这篇文章时,我只是看了这段视频。程序员得到了一些程序,必须确定哪些程序终止,然后视频继续解释为什么这是不可能的。我很沮丧,因为我知道给定一些任意程序,主角可能会证明它们是否终止。普遍性的概念以某种方式丢失了。说“无法证明某些程序终止”与“不能证明程序终止”之间是有区别的。正式证明了许多算法可以做到这一点。根据我在网上找到的每一个参考文献,未能做出这种区分是我如何找到该问题的标题。因此,我非常感谢您的回答 将停止功能重新定义为三元而不是布尔值。


16
“具有有限内存的确定性机器”之所以“无聊”,是因为它仅是有限自动机。通常,这些对于建模计算没有用。至于停顿问题:这是不可(图灵)可计算函数的特定示例。如果您对非构造性证明感到满意,则无需“使用”它。但是,它仍然具有历史意义。
拉斐尔

16
就是说,您的问题消息灵通。您可能希望重读可计算性理论的基础知识(这挑战您的直觉,而直觉是由现实提供的,而不是那里讨论的模型)。请参阅我们的参考问题作为开始。如果您需要进一步“证明”您的直觉(就理论而言)是致命的错误,请阅读此问题
拉斐尔

12
“您可以使用算法来检测链表是否循环执行以实现O(1)空间复杂度的停止功能”-但是,如果要解决具有2 GB存储空间的计算机的问题,则需要2 ^ 2000000000步和一台更大的计算机。
user2357112 2014年

11
很久以前,我和一个朋友聊天时遇到了暂停问题,一个坐在附近的人问“暂停问题是什么,重要吗?” 我的朋友转向他说:“如果我们能够解决停顿的问题,我们就可以在云上建造城市”。这是真的。
弗朗西斯·戴维2014年

8
@emory该声明完全是虚假的:P => Q如果我们知道这P是错误的(并且确实知道停止问题是不可解决的),那么对于任何Q都是正确的。弗朗西斯也可以说“如果我们能够解决停顿问题,我们就能找到治愈死亡的方法”。这就是定义逻辑含义的方式。
2014年

Answers:


217

因为许多真正的实际问题是变相的停顿问题。解决这些问题的方法可以解决暂停问题。

您是否希望编译器为给定程序找到最快的机器代码?实际上是暂停问题。

您拥有JavaScript,其中一些变量处于较高的安全级别,而某些变量处于较低的安全级别。您想确保攻击者无法获得高安全性信息。这也是停顿的问题。

您有用于您的编程语言的解析器。您进行了更改,但是您想确保它仍然解析它以前使用的所有程序。实际上是暂停问题。

您有一个防病毒程序,并且想查看它是否执行了恶意指令。实际上只是停止问题。

对于Wikipedia示例,是的,您可以将现代计算机建模为有限状态机。但这有两个问题。

  1. 每台计算机将是不同的自动机,具体取决于RAM的确切位数。因此,这对于检查特定的代码段没有用,因为自动机取决于运行它的机器。

  2. 如果您有n位RAM,则需要个状态。因此,对于您的现代8GB计算机,这是2 32000000000。这个数字太大了,以至于Wolfram alpha甚至都不知道如何解释它。当我执行2 10 9时,它说它具有300000000个十进制数字。显然,将其存储在普通计算机中很大。2ñ23200000000021093亿

停止问题使我们可以推理算法的相对难度。它告诉我们,有些算法不存在,有时候,我们只能猜测一个问题,而永远不知道我们是否已经解决了问题。

如果没有停顿的问题,我们仍将寻找希尔伯特的神奇算法,该算法输入定理并输出定理是否成立。现在我们知道我们可以停止寻找,可以将我们的精力放在寻找启发式方法和解决这些问题的第二好的方法上。

更新:只是为了解决评论中提出的几个问题。

@Tyler Fleming Cloutier:“荒谬”的问题源于以下方面的证明:停顿问题是不可确定的,但不可确定性的核心实际上是拥有无限的搜索空间。您正在搜索具有给定属性的对象,如果不存在该对象,则无法知道何时完成。

问题的难度可能与问题的数量有关。为了显示存在()具有任意属性的对象,您必须进行搜索直到找到一个对象。如果不存在,则通常没有办法知道。很难证明所有对象()都具有属性,但是您可以搜索没有该属性的对象来证明它。永久和存在之间的交替越多,问题就越困难。

有关更多信息,请参见算术层次结构。任何高于是不可判定,虽然电平1是半可判定的。Σ00=Π00

如果不使用诸如停顿问题或骗子悖论之类的荒谬悖论,也有可能表明存在无法确定的问题。图灵机可以使用一串位(即整数)进行编码。但是问题可以编码为一种语言,即整数的子集。众所周知,在整数集和所有整数子集之间没有双射。因此,必须存在一些没有关联的图灵机(算法)的问题(语言)。

@布伦特:是的,这承认这对于现代计算机是可以决定的。但这对于特定的机器是可决定的。如果添加了具有磁盘空间的USB驱动器,或者具有存储在网络中的能力,或其他任何功能,则表明机器已更改,结果仍然不成立。

还必须说,在很多情况下,算法会说“此代码将停止”,因为它会失败并耗尽内存,而增加一点额外的内存会导致代码成功并给出不同的结果。

问题是,图灵机没有无限的内存量。从来没有机会将无数个符号写入磁带。相反,图灵机具有“无限”内存,这意味着您可以在需要时不断获得更多的内存资源。电脑就是这样。您可以添加RAM或USB记忆棒,硬盘驱动器或网络存储。是的,当宇宙中的原子用完时,内存用完了。但是拥有无限的内存是一个更有用的模型。


4
@Mehrdad对于“给定程序的最快机器代码”的任何合理定义,这个问题是有道理的,答案是“不可能有这样的编译器”。
David Richerby 2014年

13
它还可用于查找可能要输出的最短机器代码,具有最少内存访问量的机器代码等。对于一般程序,找到任何最佳转换都是不确定的。这基本上是赖斯定理。
jmite 2014年

4
作为一个推论,就是在没有紧密相关的图灵等效概念的情况下仍在寻找希尔伯特的神奇算法,我们仍然会争论是否getos或自修改代码允许更强大的计算,寻找更强大的计算形式的硬件,关于哪种语言是最好的编程语言的争论将比现在更加主观。
sdenham 2014年

3
它甚至出现在您意想不到的地方。是否想编写一个在编译所有有效程序时拒绝所有无效程序的C ++编译器?首先解决暂停问题-C ++模板元编程是图灵完备的,因此,通常情况下,要判断您的模板是否有效,就必须解决。
2014年

7
@Merhrdad:您的“模拟整个计算机程序”的示例是一个很好的示例,说明停机问题如此重要。对于某些程序,模拟程序并不像看起来那样简单(例如,请参阅有关停止的Wikipedia页面)。如果问题可以这种形式欺骗,您可以想象向某人解释更隐蔽的形式(例如反病毒问题)有多么困难
Cort Ammon 2014年

49

实际上,这一点很重要,因为它可以让您告诉无知的老板“您要问的东西在数学上是不可能的”。

停机问题和各种NP完全问题(如旅行商问题)来了很多在“为什么你不能只是做一个程序,做X?”的形式,你需要能够给个说法在宇宙剩余生命中为何不可能或不可行的原因。

请注意,可以通过禁止无限制的递归和迭代来设计图灵完备的语言,以便对其进行分析。



16
好吧,@ bishop,除了Flickr几乎没有做到
Francisco Presencia 2014年

8
可以设计一种非图灵完备的语言:有用的非图灵完备语言的示例:SQL(实际上是精简的SQL)。图灵完整性会自动为该语言添加非终止符,这是您在运行数据库查询时可能不想要的。(尽管如此,恐怕所有现代SQL实现都会提供图灵完整性)
Bakuriu 2014年

8
@FranciscoPresencia:他们使用了一个研究团队,因此总体观点仍然成立。
RemcoGerlich 2014年

4
@MooingDuck:Flickr不会在公园和鸟类之间进行选择,而是(试图)确认其中一个或两个。或者,不是异或。
rickster 2014年

45

您可以使用算法来检测链表是否循环以实现具有O(1)空间复杂度的停止功能。

为此,您至少需要在内存中存储该程序的部分状态的两个副本,再加上检查程序的开销。因此,在给定的计算机上,您不能测试可以在该计算机上执行的所有程序,而只能测试在内存小于一半的小型计算机上执行的程序。

给定的有限大小计算机的暂停问题无法在有限大小计算机上解决。它只能在更大的计算机上解决。(这对任何方法都是正确的,不仅限于您建议的方法。我将不提供正式证明,而是要点。如果计算机C可以运行N个不同的程序,其中至少一个P不会终止,那么可以测试这N个程序是否暂停的计算机V也必须能够运行N个不同的验证程序。如果C和V是同一台计算机,则P并不是V运行的N个不同程序之一,因此计算机必须至少运行N + 1个不同程序,这与C运行N个不同程序的假设相矛盾。)

另外,您不能使用算法来检测链表中的循环。您需要知道何时停止。一旦执行了与计算机中状态一样多的步骤,就可以停止。如果程序使用多达位的内存,则它可以具有2 M个不同的状态。这很快变得不可能。例如,一台典型的计算机每秒执行十亿条指令。10亿秒是30年多一点的时间。因此,如果您使用一台计算机运行了8年,就可以测试一个具有大约2500亿潜在状态的程序是否停止。但这仅是2 56个状态,即,您只能测试在7个字节的内存中运行的程序。中号2中号256

那里的数字表明,将计算机视为有限状态机几乎是不实际的。状态的数量可能是有限的,但令人难以置信的是,这是不切实际的。推理非玩具程序的唯一方法是抽象方式,不是通过枚举状态而是通过逻辑推理。

因此,除了矛盾的程序之外,停止问题是可以确定的

矛盾不是来自问题,而是来自解决方案的尝试。对于任何给定的程序,都有一种算法,如果程序终止则说“是”,如果程序没有终止则说“否”。这是微不足道的:要么print "yes"还是print "no"会做。问题在于确定要呼叫哪一个。解决暂停问题的可能性意味着没有算法可以进行此确定。证明使用对角化参数的原因是它需要证明没有解决方案;为此,它从一个任意声称的解决方案开始,并且表明它必须通过构造丢失的程序来丢失某些程序。对角化(您不恰当地称其为“悖论”)在构造中,而不在结果程序中。生成的程序不是自引用的。

有一个更普遍的结果称为赖斯定理,它指出任何非平凡性质程序的不确定性-任何仅取决于程序行为且不依赖于其编写方式的属性(例如,“源代码是否由少于42个字符组成?”显然可以确定,而“是否存在源代码由少于42个字符组成并且对于所有输入均返回相同结果的程序?”也不是,“该程序是否输出了任何内容?”)。停止只是一个例子。这很重要,因为它经常在实践中出现(通常,由于运行的计算机资源有限,我们想知道某个程序是否会在合理的时间内返回结果,但是由于这实际上几乎不负责任,愿意解决一个简单的问题,即在足够的时间和内存下该程序最终是否将终止。


2
我认为问题是“是否有一个程序可以产生与给定的自包含程序相同的输出(除了程序本身,没有输入,但在更短的时间内,包括加载程序的时间?”)这是可以决定的,尽管很棘手,因为候选程序的最大长度是有限制的,就像测试每个程序的时间一样。
2014年

@supercat是的,此属性是可确定的。对于需要输入的程序的一般情况,这是不确定的。
吉尔斯2014年

1
我给人的印象是,“暂停问题”通常假定程序在执行过程中将收到的所有输入都与程序捆绑在一起。如果有人拥有一台可以神奇地解决喂入任何特定输入序列的任何程序的暂停问题的机器,那么这种机器能否确定某个程序是否将针对所有有界长度输入而暂停?
2014年

3
@supercat不,“停止所有输入的预言”比“停止给定输入的预言”高出一步。这对于该站点将是一个很好的问题……事实上,我们已经有了它。顺便说一下,我的默认思维模型是递归函数,其中“输入”表示“参数”,运行程序意味着将其应用于参数。您说得对,在关于Turing机器的上下文中我的陈述是错误的,我将对其进行更新。
吉尔斯2014年

28

在我看来,“停顿问题”无非就是所谓的“悖论”,它是一种自欺欺人的自相矛盾(至少是周期性的),与说谎者的悖论一样。它得出的唯一结论是,停止功能易受此类格式错误的问题的影响

不,这不是停顿问题。诸如骗子悖论之类的悖论不是真假,它们根本没有道理。另一方面,确定性算法将要么停止给定输入,要么将永远运行。halts(program, input)对于每个程序,每个输入,该函数都有一个定义明确的确定性值。我们只是无法为任何程序决定它。或者,更准确地说:我们不能编写一个可以为每个程序/输入对决定程序的程序。

Σñ:=ññññΣñ


2
值得注意的是,骗子悖论以常见的形式对其自身进行了明确的引用,但是即使没有,也会出现相同的问题。陈述的答案是否是通过采用文本形成的:“陈述的答案是否是通过采用文本并在第一个逗号后插入引号引起来的副本形成的,不是吗?” 并在第一个逗号后插入一个用单引号引起来的副本,不是吗?这样的陈述不是明确的自我参照,而是指逐字相同的陈述的真实性。
2014年

2
@supercat:恩,我想我以前没看过英文的
奎因

@SamB:我看过一些书,但是决定尝试使用原始的表述,虽然比某些表述更冗长,但阅读起来可能更自然。
2014年

24

我不明白为什么经常使用“暂停问题”来消除确定程序是否暂停的可能性。维基百科文章正确地解释了具有有限内存的确定性计算机将停止或重复先前的状态。您可以使用算法来检测链表是否循环以实现具有O(1)空间复杂度的停止功能。

首先,是的,从理论上讲,将具有有限内存的真实计算机视为有限状态机是有意义的。但是实际上,真实计算机的状态数量如此之多,以至于用图灵机或其他无限状态计算模型可以更好地对真实计算机进行建模。

其次,即使从理论上讲,也可以将现代计算机视为无限状态机。图灵机没有无限的磁带,它有一条磁带,当机器的内存不足时,可以随时对其进行扩展。难道这不是我们真正的计算机所能做的吗?(如果CPU的地址空间用完了,我们可以使用云等)

在我看来,“停顿问题”无非就是所谓的“悖论”,它是一种自欺欺人的自相矛盾(至少是周期性的),与说谎者的悖论一样。它得出的唯一结论是,停止功能容易受到此类格式错误的问题的影响。因此,排除矛盾的程序,停止问题是可以确定的。那么,为什么我们认为它是相反的证据呢?

HPXHPX

图灵关于停止问题的不确定性证明使用的技巧与骗子悖论类似,是的。悖论通常被定义为明显的矛盾,并且一些人由此推断出悖论并不是真正的矛盾。但是,罗素悖论(说谎者悖论的形式集合理论的形式对应物)在数学上显示出真正的矛盾,并且关于停顿问题的不可判定性的证明使用了真实的矛盾来证明其矛盾。


1
+1用于解释真实计算机,有限状态机和图灵机之间的关系,这是问题设置的重要组成部分。
David Richerby 2014年

1
你激起了我的兴趣。明显的矛盾和真实的矛盾有什么区别?
布伦特2014年

换一种说法:一般来说,程序设计并不假定资源有限,除非我们专门设计用于以下目的的算法或编写的程序,否则大多数情况下都不是使用有限甚至固定数量的计算资源编写的。方式(例如,为嵌入式系统编程时通常需要这样做)。
reinierpost 2014年

3
@布伦特 许多悖论根本不是矛盾的,而只是乍一看。当我们仔细观察时,可能会发现推理中有错误,或者某些单词的含义在不同的上下文中使用时略有变化,或者类似。然而,有时候,一个悖论揭示了一个真正的矛盾。
Hoopje

自从我的OP以来,我一直在研究这个问题。哥德尔的不完备性定理是否意味着无论使用什么逻辑系统,总是有可能提出一些悖论?
布伦特2015年

17

jmite很好地回答了这个问题。让我在与“说谎者悖论”的相似性上加一个小小的注解,我认为这是由于他们使用了自指机制。

自我指称不是矛盾的!

自我引用是计算(算法可以引用其代码,反射)和人类语言(我们可以引用自己,自我意识)中非常有用的工具。)中。

导致骗子悖论的问题不是自我参照,而是试图将真谓词用于语言内部的(正式)语言。即使没有自我参照也会引起问题,我们不需要使用自我参照就可能产生矛盾:可以消除自我参照!。这只会使句子不太美观和简洁,但并不难。实质上就是证明Kleene不动点定理的方法。说谎者悖论所暗示的是,(一种正式)语言中陈述的真实性是该语言的先验,而不是自我参照存在问题。


在我看来,您的不适不是由于无法确定暂停问题(对于图灵机),而是因为接受了图灵机作为计算机的理论模型。通常(尽管并非总是)图灵机(以及等效的计算模型,例如随机存取机))在有限的自动机上对实际计算机上的计算讨论非常有用,并且有充分的理由(请记住,图灵机没有无限量的内存,它具有无限量的内存,这是不同的东西:“无限量”意味着我们可以在需要时为计算机提供更多的内存,而不是它使用无限量的内存。

当然,如果您想将计算机视为有限自动机,并且对您的目的有意义,那么有限自动机的停止问题是可以确定的(通过可确定性,我们指的是由图灵机而不是有限自动机确定)。但是,这并不是人们使用停机问题时通常所说的,而是图灵机的停机问题。

s2s


14

停顿问题引入了数学中以前不存在的“不确定性”这一新的数学概念。这是(看似矛盾的)证明,有些问题没有“证明”。它与哥德尔式的不可证明性概念有关。戈德尔斯定理在图灵提出停顿问题之前已有数年之久。Godels的结果在当时被认为是相当抽象的,只有研究人员和专家才知道。Turings的表述表明,不可决定性的原理与计算机科学中高度实际/务实/ 应用的问题有关,例如确定任意程序是否停止,并且它被认为远没有理论意义,它出现在诸如 (挑战计算机是否可以发现定理)并证明程序终止。

另一个有趣的角度是,(Diophantine)数论中存在一些非常古老的问题,这些问题起源于希腊人,但尚未得到千年的证明。有一个相关的结果是,关于Diophantine方程的一般问题无法确定,称为Hilberts第十个问题/定理。希尔伯特(Hilbert)活在20世纪初,被提出作为研究计划,使数学可以找到解决数学问题的系统方法。几十年后发现不确定性,这一挑战/计划遭到了严重打击。不确定性仍然是一个非常先进的研究领域,不确定性和可决定性问题之间的界限可能将一直处于进一步的研究和分析之中。


14

您似乎对基于“自我参照”的经典证明感到困惑,即不能通过停止问题(又名“停止”)本身来解决“停止”问题。

该自引用程序(即仅在不停止时才停止的程序)的构造是为了易于证明您无法解决暂停问题。我们通过技术Y证明X是不可能的事实并不意味着Y是我们无法求解X的唯一原因。

换句话说,我们不仅无法解决暂停问题,而且无法检测出无法确定程序是否停止的程序类型,除了诸如“如果运行时间超过一分钟,假装”这样的粗略措施之外,它不会停止”。

如果您从停止问题着手,并减少其他问题,最终您将减少关于程序的几乎所有问题。我们得出莱斯定理:

令S为图灵机接受的非平凡属性1。这意味着至少有一台图灵机接受具有属性S的输入,而另一台不接受。

然后,不确定给定的图灵机T是否接受具有属性S的输入。

您想知道图灵机是否接受偶数整数吗?不可思议。

您想知道图灵机是否接受算术序列吗?不可思议。

您通常可以推断出Turing Machine的胆量。您可以推理特定的图灵机,并证明它是否会停止/接受某些顺序/等。但是您不知道您的技术是否可以在您喂入的下一台图灵机上使用。


1property of不包括它是如何被接受的机制-只是什么被接受。“它以100或更少的步数接受”是它如何接受而不是接受什么的属性。


您可能想解释什么是“财产”,因为一个人可能天真的解释可能是不正确的。
里克·德克

@rick我认为脚注现在涵盖了它?
Yakk 2014年

7

没错,通常引入和说明的停止问题仅仅是一个陷阱。并不能证明不能有三值(“停顿”,“循环”,“不知道”)的停顿函数,在实践中总是返回“停顿”或“循环”,而仅返回“唐”例如,“不知道”用于特殊构造的转角箱。

暂停问题很重要的两个原因:

1)这是第一个无法确定的问题之一。即使假设只有一个“不知道”,它仍然具有巨大的数学意义。

2)一些问题减少到中止问题,恶意攻击者可以提供待分析的案件。这迫使我们接受可能仍然需要拒绝的有效案例。

到第二点,软件分析是一个难题,尽管在分析和语言设计上都取得了很大进步,以使分析更加容易。如果您可以证明某项任务类似于软件分析,是的,用大写字母H很难。“这不可能,因为这等于解决了暂停问题”,尽管在很多情况下在技术上是错误的或无关紧要的,此观察的简写。


5

埃里克·海纳(Eric Hehner)在一系列论文中提出了一个相反的论点,该论据认为,“停顿问题”的不可解决性通常被误解。可以在此处找到论文“ Epimenides,Gödel,Turing:永恒的金色纠结”,“有关停止问题的问题”,“重建停止问题”和“停止问题” 。为了使这个答案不是“仅链接”,我将尝试总结他的结论之一,而不是论点。

结论是:暂停问题无法解决的原因不是因为旨在解决该问题的程序可以用来产生矛盾,而是因为该问题本身无法实现,在某种意义上,函数的规范必须同时返回1和2是无法实现的。我们发现没有程序满足规格并不引人注目F0=1个F0=2HH中号中号HHH


3
我不懂 停止功能是一个定义明确且有效的谓词-对于任何给定的Turing机器和任何给定的输入,机器都会停止或循环。(您缺乏适当的参考;您要总结哪种papar?)
Raphael

@Raphael函数定义良好通常被认为是事实。赫纳的观点有所不同,他的论文对此进行了解释。我将编辑答案以提供论文的名称。
Theodore Norvell

远的不说,无论Hehner的说法是[我还没有看报纸]他们至少在有争议的一读/近似横空出世:“ cs.toronto.edu/~hehner/Shallitaffair.pdfrecursed.blogspot.com/ 2013/10 / eric-hehner-replies.html
Fizz

鉴于被引用的性质和次数,海纳的论文(对此)是否具有任何其他读物(值得一提)是否值得,尚不清楚。
嘶嘶声

他的证明似乎很扎实,并指出这只是哲学上可以做的愚蠢的事情的重做,例如试图分析以下自我指称的陈述的真实性:“这句话是错误的。” 如果为true表示它是假的,则表示它实际上为true,没有,这又使它再次假了……所以这看起来像是一个不太重要的哲学注视问题。en.wikipedia.org/wiki/Liar_paradox停止悖论可能是科学家不与哲学家交谈的情况。
詹姆斯·韦克菲尔德

3

我想对涉及人而不是机器的停机问题的重要性提供不同的解释。

这是麻省理工学院1986年结构与解释课程的最后一讲。教授问:“有什么问题吗?” 当其中一个学生问:“这是最后一个问题吗?”并准备结束演讲

考虑一下。老师怎么回答呢?如果学生决定与老师矛盾,那么老师将无法给出有效答案-就像停顿问题一样。

我们习惯于使用功能和机器来抽象地考虑停止问题,但是比这要深得多。从根本上讲,这意味着存在无法回答的完全有效的问题。

PS:如果您不知道我在说什么课程,那就去看吧,那太棒了。


但是,如果我执行doesHalt(programCode, input);,程序将无法知道doesHalt函数返回的内容。doesHalt函数评估后,程序将无法停止。
Tvde1

0

我可以很容易地编写一个给定输入n的程序,或者输出最小素数p> n使得p + 2也是素数,或者如果不存在这样的p则永远运行。如果您可以解决该问题以预测我的程序是否针对每个输入都暂停,那么您就解决了Twin Prime猜想。

这种推测很有可能被证明是无法确定的,在这种情况下,我们将有一个简单的程序,其中暂停程序会失败。


我认为您正在将“难以置信的变幻莫测”与一个截然不同的概念混为一谈。实际上,您可能偶然地陷入了“同样古老”的谬论。另请参阅此处此处
拉斐尔
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.