[译]时间自动机:语义,算法和工具

本文原题是《Timed Automata Semantics, Algorithms and Tools》,本人硕士毕业设计与此相关,研究了好久,现在自行翻译出来。转载请注明版权。

时间自动机:语义,算法和工具

Johan Bengtsson和Wang Yi

 

Uppsala大学

Email:{johanb,yi}@it.uu.se

(译者:祝威http://bitzhuwei.cnblogs.com

摘要:本文是时间自动机的教程,重点介绍了它作为验证工具的语义和算法。本文给出了时间自动机的具体语义、抽象语义、决策问题及其算法(主要是转换规则、区域和带这些概念)。DBM(Difference Bound Matrices)是常用的基于时间自动机理论的验证工具使用的数据结构。本文详细讲解其原理。最后,本文以Uppaal为例,介绍这一款时间自动机验证工具的基本原理和使用方法。

1. 简介

时间自动机是一套对实时系统进行建模和验证的理论。这一理论是Alur和Dill的杰出工作成果。很多验证工具(例如Uppaal)就是基于时间自动机理论制作的。本文就将介绍这些工具所依赖的时间自动机的语义和算法。

时间自动机就是带有时钟集的有限自动机。时钟集是有限个时钟的集合,每个时钟都是一个取值范围为0或正数的变量。时间自动机状态之间的转换要满足时钟约束才可能发生。时间自动机的状态可以附加上“位置不变性”的属性,这也是一个时钟约束,用来保证状态不会保持在原地不动。这种自动机称为“时间安全自动机”,本文默认讨论的都是这种自动机。

后文组织方式如下:下一节讲述时间自动机的语法和语义,以及和自动化验证相关的决策问题。本文中,可判定性和不可判定性被视为计算模型的基本属性。第3节介绍基于区域和带的抽象语义。第4节介绍DBM的数据结构。第5节介绍验证工具UPPAAL。最后,在附录中给出DBM相关算法的伪代码。

2. 时间自动机群

时间自动机是附带了若干实值变量的有限自动机(由有限个结点或位置和有限个边组成的图)。时间自动机是时序系统的抽象模型。变量模拟逻辑时钟,时钟从零开始,同步地增长。边上的时钟约束(例如guard)限制了自动机的跳转行为。只有时钟值满足guard时,guard所在的边才能发生跳转。跳转时可以将时钟重置为零。

下面的Figure 1时间自动机和位置不变性是一个时间自动机的例子。时序性质由两个时钟x和y实现。时钟x用于控制loop结点的自循环。当x为1时,loop就可能发生一次自循环。时钟y控制整个自动机的完整运行。自动机可能在10<=y<=20的任何时间点离开start结点,也可以在40<=y<=50的任何时间点从loop到达end结点。

clip_image002[11]

Figure 1时间自动机和位置不变性

Timed Büchi Automata

Guard只规定了在某些时间范围内可以发生跳转,但不是强制发生跳转。(必要不充分条件)

时间安全自动机(略)

2.1 正规语法

clip_image004[14]表示实值变量或时钟(clock)的有限集合,其元素用clip_image006[8]等表示。

clip_image008[8]表示动作的有限集合,其元素用clip_image010[8]等表示。

原子时钟约束:形如clip_image012[8]clip_image014[8]的式子,其中clip_image016[8]clip_image018[8]

时钟约束(Clock Constraint):原子时钟约束的合式公式。用于充当转换条件。用clip_image020[8]等表示。

clip_image022[14]表示时钟约束的集合。

定义1 (时间自动机Timed Automaton)

一个时间自动机Α是一个四元组clip_image024[8],其中

clip_image026[8]是位置(或称为状态)的有限集合

clip_image028[8]是初始位置

clip_image030[8]是边的集合

clip_image032[8]是从不变性到位置的映射

clip_image034[8],可记作clip_image036[8],即存在从位置clip_image038[8]clip_image040[8]的转换。

在Uppaal里,位置不变性规定为x<=n或x<n的形式。

并发和交互

(略)

2.2 操作语义

时间自动机的语义是一个状态转换系统。状态由当前位置和所有时钟的当前值组成。

状态转换包括两种类型,即延时转换和动作转换。为了表述时间自动机的操作语义,引入时钟映射的概念。时钟映射是从clip_image004[15]到非负实数的映射,用clip_image043[8]表示。用clip_image045[14]代表clip_image047[14]所映射的时钟值满足clip_image049[8],即动作转换是可能发生的。用clip_image051[8]代表clip_image053[8],其中clip_image055[14]。用clip_image057[8]代表clip_image059[14]范围内的时钟值置为零,clip_image059[15]外的时钟值由clip_image047[15]确定(clip_image062[8])。

定义2 (操作语义Operational Semantics)

一个时间自动机的语义被定义为一个转换系统,时间自动机的状态为二元组<l,u>,转换则定义为:

clip_image064[8] if clip_image066[8]clip_image068[8]clip_image055[15]

clip_image071[8] if clip_image073[8]clip_image045[15]clip_image075[8],且clip_image077[8]

2.3 验证问题

操作语义是时间自动机验证的基础。下文基于转换系统来阐述可判定性问题。(略)

定义3 (语句Run)

在操作语义的基础上,我们可以定义一个时间自动机的时间语言clip_image079[14],其中clip_image081[8],若对于clip_image083[8]存在时序序列clip_image085[8]使得如下的序列成立:

clip_image087[8],其中clip_image089[8]

那么我们称clip_image091[8]clip_image079[15]的一条语句。

定义4 (相似Bisimulation)

(略)

可达性分析
定义5 (可达性)

clip_image093[8]

(略)

3. 符号语义和验证

时钟是实值的,所以状态转换系统有无数个情况,这不能用于自动化验证。为解决这个问题,提出下面的区域、带和符号语义的概念。

3.1 区域,带和符号语义

区域等价是时间自动机属性判定的基础。

定义6 (区域等价Region Equivalence)

clip_image095[8]

(略)

clip_image096[8]

Figure 2有两个时钟的系统区域图

(略)

时间自动机的状态空间的更高效的表述方法是用“带图”。“带”表示符号状态。构造带图的方法和算法在第4节有介绍。Figure 3时间自动机和它的带图展示了一个示例。这个带图只有8个状态,而它的区域图却有超过50个状态。

clip_image098[8]

Figure 3时间自动机和它的带图

一个带就是一个时钟约束。严格的说,是这个所有满足这个时钟约束的解的集合。带可以用DBM表示,这方面的研究很成熟。以后D既可以表示时钟约束,也可以表示带,那么clip_image022[15]就可以表示带的集合了。

时间自动机的符号状态是一个二元组<l,D>。<l,D>实际上是时间自动机的某些状态的集合,其中l是位置,D是带。符号转换描述的就是这些状态集之间的所有可能发生的转换。

定义7 (符号转换Symbolic Transition)

clip_image100[8]

第4节会详细讲述这些操作。其中的D写作了up(D),r(D)写作了reset(D,r:=0)。带的运算结果仍然是带(矩阵的运算结果仍然是矩阵)。带可以像代数式那样化简(canonical),而且化简的最终形式是唯一的。这是符号语义缓解状态空间爆炸的关键结构。

符号语义和操作语义有着对应关系。就是说,若<l,D>à<l’,D’>,那么对于所有的u’属于D’,一定存在u∈D,使得<l,u>-><l’,u’>。符号语义可以说是对定义2的本质的描述。

定理1 (符号语义的完整性和存在性)

设时间自动机初始状态为<l0,u0>

clip_image102[8]

完整性的意思是,若初始的符号状态能够到达最终的符号状态,那么最终的符号状态中包含的所有具体状态都应该是可到达的。存在性的意思是,若一个具体状态是可达的,那么就存在一个符号转换关系把这个状态包含进去。

不幸的是,符号状态转换是无限的,所以时间自动机的带图可能是无限的。考虑下面的示例Figure 4产生无限带图的时间自动机,时钟y无限的增长,从而绘出了无限的带图。

clip_image104[8]

Figure 4产生无限带图的时间自动机

解决方式是用类似扩展操作的技术,把含有任意大常量的带转化为一个类型的带。直觉上看,就是一旦时钟值超过某个常量,它具体是多少就无关紧要了。

3.2 不含差约束的带的正规化

差约束是形如x-y<=n的guard。最初的时间自动机理论不允许差约束作为guard,只允许x<=n的形式。这是无斜角的自动机。这类自动机的带用k正规化操作即可。Uppaal就是这么做的。

定义8 (K正规化k-Normalization)

设D为带,k为时钟上限,那么D上的k正规化操作的语义如下:

clip_image106[8]

Normk(D)可以通过对D的最简式执行以下两个操作来实现。

1. 去掉所有m>k(x)的x<=m,x-y<=m的约束;

2. 把所有m>k(x)的x>=m和x-y>=m分别替换为x>=k(x)和x-y>=k(x)。

在Figure 4产生无限带图的时间自动机中的带图的正规化的结果如下Figure 5正规化的带图所示。其中的时钟上限是时间自动机中出现的最大时钟常量。

注意到,对于有限个时钟,给定它们的时钟上限,那么只存在有限个正规化的带。就是说,通过正规化我们可以把无限的带图转化为有限的带图。

clip_image107[8]

Figure 5正规化的带图

定义9 (正规跳转)

clip_image109[8]

无斜角的时间自动机,正规跳转满足完整性、存在性和有限性。

定理2 无斜角的时间自动机

设时间自动机有初始状态<l0,u0>,最大时钟常量上限由函数k决定,且不含差约束。那么:

clip_image111[8]

不幸的是,对于包含差约束的时间自动机,不满足完整性。本文用下面的示例说明。考虑如下Figure 6计数器示例所示的自动机。最后一个节点是不可达的。因为在S2结点,时钟带是(x-y>2且x>2);而S2到S3的guard是(x<z+1且z<y+1),这等价于(x-z<1且z-y<1且x-y<2)。很明显S2永远不能满足guard,最后一个转换就不可能发生。

clip_image112[8]

Figure 6计数器示例

但是,x时钟的最大常量是1,y是2,S2的带(x-y>2且x>2)经过正规化就是(x-y>1且x>1),这样就能够满足S2到S3的guard了。这样一来,基于正规化的符号可达性分析就出错了。

带的最简式在下面的列出。隐含的所有时钟都为非负数没有列出。

clip_image114[8]

Figure 7计数器示例的带

注意到,正规化前后的S0和S1是相同的,问题是S2前后带与guard的交集一个是空的一个是非空的。

3.3 含有差约束的时间自动机的正规化

含有差约束的正规化是很有用的。

定义10 (使用差约束的正规化Normalization Using Difference Constraints)

clip_image116[8]

优化定义的k正规化操作的语义可表示为:

clip_image118[8]

优化的区域等价要符合时钟上限k函数和guard集G。正规化操作也是。

因为k等价运算得到的区域是有限的,G中的guard也是有限的,所以优化的k正规化操作得到的区域也是有限多个。这就是说,给定带D,normk,G(D)操作仅包含有限个等价区域。只不过这个区域不是凸的。这个区域可以由有限个凸的区域的并集组成。下一节将详细介绍算法。

定义11 (优化的k正规化跳转)

clip_image120[8]

设时间自动机有初始状态<l0,u0>,最大时钟常量上限由函数k决定,guards中的差约束集合用G表示。则满足完整性、存在性和有限性:

clip_image122[8]

3.4 符号可达性分析

模型检测关心两种类型的属性:liveness和safety。检测liveness的算法是环路检测,非常耗时。时序系统主要是由safety检测,相关算法是遍历时间自动机的状态空间。

算法1 可达性分析

clip_image124[8]

可达性分析用于检测状态的性质。核心思想分两步,首先计算出时间自动机的状态空间,然后搜索状态空间中符合条件或与之矛盾的状态。第一步可以提前处理,也可以在搜索过程中实时处理。后者更有优势,因为只需要处理那些需要验证的状态就可以了。但是有时候这并不管用,还是要处理所有的状态空间。

我们将讲解Uppaal的核心验证引擎。Uppaal是基于符号语义和带图进行可达性分析的一种工具。

设有时间自动机A,初始状态<l0,D0>和最终状态<lf, φf>,时钟上限k由A和φf中的最大常量定义,G表示A和φf中的差约束的集合。算法1可用于检测初始状态能否到达这样的状态:其位置为lf,其时钟值满足φf。它实时计算A的带图,搜索其中位置为lf且带和φf有交集的符号状态。

算法1工作在有限的状态空间,所以一定会终止;另一方面,它的返回值也一定是正确的,这在之前的定义11中得到了论证。

算法1也提示出了,时间自动机的模型验证器要解决的关键问题,例如状态、带的表示和运算。另外还需要带的判空和相互包含的判定,以及压缩存储、状态空间压缩和近似计算等技术。

4. DBM: 算法和数据结构

前文讲解了符号化的可达性分析中的关键点。回忆一下,zone(带)是用时钟区间(clock assignment)定义的。我们还没有阐述zone是如何计算的。下面将对zone的表达(数据结构)、zone的操作(算法)和验证(检验是否具有某属性)进行讲解。最后附上相关操作的伪代码。

5.1 DBM基础

在时钟集C上的时钟约束是原子约束的合式公式。原子约束是x~m或者x-y~n的形式,其中x,y是时钟集C的元素,~属于{≤,<,=,>,≥},m,n属于自然数。用时钟区间D表示的zone是满足D的时钟值的集合。(符合时钟约束的x,y。。。的值的所有情况)zone最重要的性质(或者说搞出zone这个东西来的理由)是zone可以用矩阵来表示,就是DBM(Difference Bound Matrices)。所以下面就讲述DBM的结构和性质。

为方便数学表达,我们引入“零时钟”。零时钟就是无论何时其值都为0。设C0=C∪{零时钟},那么任意zone都可以写作x-y<=n的形式。(n是整数)

显然,用|C0|2个形如x-y<=n的原子约束就可以表达zone。所以就用|C0|×|C0|的矩阵表示zone,矩阵的一个元素对应一个原子约束,这个原子约束表达了两个时钟的差异,所以叫做差界矩阵。后文中一律用Dij表示DBM的(i,j)处的元素。(DBM表示zone,或者说D)

下面是构造DBM的方法。

首先,将C0的时钟按0,...,n排序,让零时钟的序号为0,。矩阵的一行表示一个时钟。计算规则如下:

对于形如Xi – Xj<=n的约束,让Dij=(n,<=)

对于Xi – Xj未定义的Dij,让Dij=(∞,<=)无穷大在数据结构里用一个特殊值表示。

对特殊情况:0 – Xi <= 0和Xi – Xi <= 0进行设置

示例:例如一个zone,表示为D= x – 0 < 20且y – 0 <= 20且 y – x <= 10且x – y <= -10且0 – z < 5。这个zone转化为矩阵如下:

clip_image125[8]

DBM的元素有两种操作:比较和相加。我们规定如下:

若n1 < n2,则(n,<=1) < (n1,<=) < (n2,<=2)。

(n,<) < (n,<=)

b1 + ∞ = ∞

(m,<=) + (n,<=) = (m+n,<=)

(m,<) + (n,<=) = (m+n,<)

最简(Canonical)DBM

通常,会有无限个zone本质上相同,但他们只有一个最简的形式。

为求出最简化的DBM,我们把用权重图表示zone,其中C0的元素用结点表示,原子约束用边表示。形如x-y<=n被转化为从y结点到x结点的边,用(n,<=)标记,这意思是说从y到x的距离最大是n。

clip_image126[8]

Figure 8示例矩阵的图解和闭包形式

分析一下(过程略),可知界限最紧最强的等价D表示可以通过图解中两个结点的最短路径算法得到!(好厉害的结论,Floyd-Warshall算法就可以)由于这个算法比较耗时,所以我们要求DBM的保存和操作结果的保存都用最简化的形式。

最小约束系统

一个zone可能包含冗余的约束。例如D=x-y<2, y-z<5, x-z<7。其中x-z<7显然可以从前两个推理出来。去掉冗余约束是必要的。最小约束矩阵可以用稀疏矩阵表示,这就缓解了状态空间爆炸的问题。最小约束系统已经被很彻底的研究过了。下面我们总结一下前人的成果就好。

(总结略)在附录的算法4里有伪代码。看代码就行了。

好了,我们能够得到DBM的最简形式了。减轻了包袱,下面开始处理DBM的计算问题。

5.2 DBM基本操作

本节讲述除了zone标准化之外的所有基本操作。这些操作会用在时间自动机的模型验证,前向、后向分析。下一节再讲zone标准化(normalization)。

为描述简单,本节讨论的zone都是相容的(不为空的),最简化的。

DBM的操作分为两类:

属性验证:这类操作包括检验DBM相容性、zone之间的包含关系以及zone师父满足给定的原子约束。

变形:这类操作包括根据guards、延时和时钟重置来计算zone的最强后置条件和最弱前置条件。

1. 属性验证
1) Consistent(D)

最基本的操作。判断DBM是否不为空(为空则表示这个带不包含任何有意义的时钟值)。例如,时钟解的集合是否空集。这在状态空间检测中用来去掉不相容(即空)的状态。(去掉那些不可能存在的状态,减少状态数)

把D00设置为负就行了。

2) Relation(D,D’)

包含关系也是个重要的检测。对所有的i,j属于C0,Dij <= D’ij是D包含于D’的充要条件。详见算法5。

3) Satisfied(D,Xi – Xj <= m)

有时候会需要判断一个zone是否满足某约束。例如,在不修改D的前提下判断D且Xi – Xj <= m是否相容。从consistent的定义我们知道zone是否相容取决于它是否包含负环。所以,Satisfied检测就是把这个guard加到D上,看它是不是产生了负环。对于最简化的DBM,只要检测(m,<=)+Dji是否为负就可以了。

2. 变形

clip_image128[8]

1) Up(D)

把那些由于时延被包括进D的时钟区间的范围都算进来,就是Up(D)。所以Up(D)={u+d|u∈D,d∈R+}。算法上的含义是,Up把所有时钟的上限抹掉(DBM的Di0设置为∞)。由于所有时钟具有同速率地走动的性质,任意两个时钟之间的差值都不会超过界限。(因为都是x – y <= n这种形式,所以x、y同步的增减都不会破坏这个关系)

Up和最强后置条件的关系我还不明白。资料上说Up就是计算最强后置条件的。

clip_image130[8]

2) Down(D)

类似Up,Down(D)={u|u+d∈D,d∈R+}。算法上,把DBM的第一行(零时钟所在行)都设置为(0,<=)。但这可能导致不产生不最简的DBM,需要进一步处理。算法是:计算x时,将所有其他时钟Yi置为0,检查差别约束Yi-X,把其中最强约束最为新的界限。详见算法7。

clip_image132[8]

3) And(D,Xi – Yj <= b)

把一个约束加到zone上是最常见的操作。基本步骤是:若(b,<=) < Dij,则设置Dij为(b,<=),然后调整新zone为最简化的形式。调整方法使用O(n2)的特殊算法。特殊算法利用了只有Dij改变了这一事实和Floyd算法的性质,减少了运算量。详见算法8。

clip_image134[8]

4) Free(D,x)

去掉对给定时钟的所有约束。就是说,x时钟可以取任意正数。Free(D,x)={u[x=d]|u∈D,d∈R+}。用于状态空间的后向检查。详见算法9。

clip_image136[8]

5) Reset(D,x:=m)

在前向检查中用于把时钟置为特定的值。Reset(的,r:=m)={u[x=m]|u∈D}。若不要求最简化的结果,只需设置Dx0=(m,<=),D0x=(-m,<=),并所有x行的边界。但用类似做free的方法,可以得到最简化的结果。详见算法10。

clip_image138[8]

6) Copy(D,x:=y)

用在前向状态空间检查。把y的值复制给x。定义Copy(D,x:=y)={u[x=u(y)]|u∈D}。实现方法很简单,把Dxy和Dyx都置为(0,<=),其他地方的x都换成y的值。详见算法11。

clip_image140[8]

7) Shift(D,x:=x+m)

把时钟x增加或减少一个整数值。Shift(D,x:=x+m)={u[x=u(x)+m]|u∈D}。只需用x-m代替原来的x就行了。详见算法12。

clip_image142[8]

5.3 带(Zone)的正规化

带的正规化的目的是把含有任意大的常量的带转化为只含有不超过上限的常量的带,从而将时间自动机的无限带图转化为有限带图。

若时间自动机不含差约束,用normk(D)正规化即可。实际上只需做两件事,一是把超过上限的<=差约束对应的约束删除;二是把绝对值超过上限的>=差约束改到上限。对最简化的DBM数据结构来说,就是若(m,<=) > (k(x),<=),则去掉x-y<=m这个差约束;若(m,<=) < (-k(y),<),则把x-y<=m改为x-y<-k(y)。

若时间自动机的guard里含有差约束,就比较麻烦。设有时间自动机A,含有差约束的集合G,上限函数k。现在要对A的一个带D进行正规化。根据定义10的正规化的语义,D和正规化的D的时钟值同时满足或不满足G的所有差约束。这启示我们导出如下的正规化核心算法。

1.收集A中满足下列条件之一的所有差约束:

(1)g且D为空:这是g在D外的情况

(2)(非g)且D为空:这是g包含D的情况

设Gunsat=上述g和非g的集合。

2.不考虑差约束的存在,直接计算normk(D)

3.上一步得到的规范化的D逐一减去Gunsat的部分,即normk(D)且(非Gunsat)

第3步的目的在于确保规范化的D中不含那些D不满足的差约束。算法14给出了k核心算法的伪代码。算法中的Gd是时间自动机中出现的差约束的集合。

但normk(D)且(非Gunsat)仍然不是我们要求的正规化的带。K核心算法没有处理那种差约束分割了D的情况。就是说,可能存在一个g,使得g且D不为空同时(非g)且D也不为空。所以,我们要用算法15把D分割成若干部分,对分割出来的部分分别执行k核心算法。任意一个分割的Di都应该满足:对于所有的g∈G,或者Di且g为空,或者Di且g为Di(即g包含Di)。最后把各个Di正规化的结果取并集,就是我们要求的normkG(D)

完整的计算流程就是算法16。

clip_image144[8]

我们用上文中的计数器示例的S2的带D:(x-y>2且x>2)来演示说明正规化过程。示例中的差约束是g1=x-z<1和g2=z-y<1。D既包含满足g1的部分又包含满足(非g1)的部分,所以在正规化之前要分割D,如下图所示。

clip_image146[8]

D(a)与g2交集为空,所以不需再分割。D(b)还要根据g2分割为满足g2和非g2的部分,所以就分成了下面的形式。

clip_image148[8]

这三个带就要执行k核心算法了。

D(a)、D(b)、D(c)不满足的差约束集合分别是Gunsat(a)={非g1,g2},Gunsat(b)={g1,非g2},Gunsat(a)={g1,g2}。分别对其进行kG正规化,得到:

clip_image150[8]

由于正规化的D(A)、D(B)、D(C)与Gunsat都没有交集,我们不需要减去对应的差约束了。最后强调一下,正规化的ABC和g1且g2都没有交集,S2到S3的跳转也没有发生变化。(仍旧不能跳转)

5.4 DBM的内存表示

(略)

5. Uppaal

Uppaal是时间自动机建模、仿真和验证的工具箱。它用到了前文所述的数据结构和算法。它是由Uppsala大学和Aalborg大学共同开发的。

5.1 Uppaal建模

Uppaal建模的核心是时间自动机网络。Uppaal已经扩展了建模和验证能力。重点包括整型变量、立即管道和过期位置。

时间自动机网络

(略)

6. 附录

下面列出DBM常用运算的伪代码。

算法2 Close(D)或Canonical(D):计算D的最简式

clip_image151[8]

Figure 9计算D的最简式

算法3 消去无零环带图的冗余约束

clip_image152[8]

Figure 10 消去无零环带图的冗余约束

算法4 消去一般带图的冗余约束

clip_image153[8]

Figure 11消去一般带图的冗余约束

算法5 判定两个带之间的包含关系

clip_image154[8]

Figure 12判定两个带之间的包含关系

算法6 时间流逝

clip_image155[8]

Figure 13时间流逝

算法7 时间倒流

clip_image156[8]

Figure 14时间倒流

算法8 添加时间约束

clip_image157[8]

Figure 15添加时间约束

算法9 取消整个时钟的约束

clip_image158[8]

Figure 16取消整个时钟的约束

算法10 重置时钟

clip_image159[8]

Figure 17重置时钟

算法11 复制时钟

clip_image160[8]

Figure 18复制时钟

算法12 时钟偏移

clip_image161[8]

Figure 19时钟偏移

算法13 k正规化

clip_image162[8]

Figure 20k正规化

算法14 k核心正规化

clip_image163[8]

Figure 21k核心正规化

算法15 带的分割

clip_image164[8]

Figure 22带的分割

算法16 kG正规化

clip_image165[8]

Figure 23kG正规化

算法17 添加上限

clip_image166[8]

Figure 24添加上限

posted @ 2013-03-26 19:32 BIT祝威 阅读(...) 评论(...) 编辑 收藏

Large Visitor Globe

Flag Counter
Flag Counter