计算流体力学(Computational Fluid Dynamics,CFD)技术发展的一个重要标志是各种CFD通用商业软件的陆续出现。而我国CFD软件在历史上发展严重滞后。一大批国外商业CFD软件涌入我国市场,如ANSYS Fluent、ANSYS CFX、CFD++、STAR-CD、NUMECA等,这些软件功能全、求解速度快,同时以客户需求作为开发的导向,很快获得了一大批用户的青睐,占领了大部分市场。
近年来,受益于计算机水平的不断提高、成本的不断下降,以及国家在科研领域的持续投入,航空航天领域的各个大学、研究院所纷纷发展推出各类In-House CFD Codes,一些CFD软件公司也推出自主商用CFD软件,我国自主CFD软件发展形势喜人。
然而,国产CFD软件大部分属于研究性软件,少数属于专业软件,特点是软件精巧、专业性强、求解问题有限,对于软件开发人员或对算法熟悉的技术人员,可以计算得到精度较高的结果。尽管我国的CFD软件在长期的发展过程中,取得了长足的进步,但是受限于CFD软件开发的历史局限,在开发模式方面和国外软件还存在一定差距,主要体现在:(1)开发模式落后。大部分软件实际上是具备某种专业功能的计算代码,没有结合现代软件工程思想,程序基本上是面向过程式开发。随着软件规模的扩大、软件功能的增加,代码量急剧增长,面向过程式开发软件的可扩展性、易维护性都大大降低。(2)软件开发目标不明确。很多国内早期的计算软件往往是出于某个工程任务或学术研究的需要而开发,软件研制的主要目的之一是解决某类特定问题,在开发过程中为了快速达到目的,只侧重某类功能的实现,导致软件的体系结构、数据结构考虑不周全,可扩展性差。(3)软件测试不够系统。CFD软件除了要进行验证与确认外,在开发过程中还需要大量单元测试、集成测试,以保证软件质量。
相比较而言,国外大型CFD软件项目在开发过程中非常重视与现代软件工程思想和方法的结合。
从2008年开始至2020年结束,美国国防部在研项目“计算研究与工程采购工具与平台”[1-4] (Computational Research and Engineering Acquisition Tools and Environments,CREATE)是为了工程设计与分析而发展的多学科的软件工具平台,共计投入3.6亿美元。该项目十分重视测试,其中四大模块之一的Kestrel[5]就包含4个层次的自动化测试:单元测试、融合测试、系统测试和可信度测试。目前,Kestrel拥有3485个单元测试、239个融合测试、21个系统测试,每天都必须运行这些测试,大致产生17 189个功能正确性判定。同时,可信度自动化测试系统(Automated Testing System,ATS)在美国国防部的超级计算机上每两周运行一次,ATS包含124个独立的计算任务,大概需要43 000个CPU机时才能完成测试。
Flucs[6-8](Flexible Unstructured CFD Software),是德宇航(DLR)正在研发的一款面向下一代的CFD软件。与DLR的传统CFD软件开发过程相比,Flucs最大的变化体现在软件开发模式、编程框架和并行计算等方面。在软件开发模式方面,大量采用现代软件开发思想及方法,如采用分布式版本控制工具GIT、基于WEB的版本Review系统、不间断的持续集成、自动化测试方法等。
除了开发模式外,软件测试也是制约大型CFD软件研制成功与否的关键因素。随着人们对软件测试重要性的认识越来越深刻,软件测试阶段在整个软件开发周期中所占的比重日益增大。无论是从软件开发方法学还是软件测试自身的效益看,软件测试在今后很长时间内仍将是保证软件质量和可靠性的重要手段。CFD软件的开发测试是一项系统工程。国外CFD软件开发过程中引入了严格的质量管控体系,从开发到发布的全生命周期要经过非常严格的系列测试,很好地保证了软件质量。
现代软件开发过程中,软件测试人员往往占到开发人员40%以上,对于某些性命攸关的软件,其测试费用甚至高达所有其他软件工程阶段费用总和的3到5倍[9]。许多世界级的公司(如Google公司)可以打造出世界级的软件,这与其对待质量的方法是离不开的[10]。他们把软件开发过程和测试融合在一起,二者同时开展。开发过程中,并不是将软件测试当作独立隔离的活动,而是把它作为开发过程的一部分。当开发和测试融合在一起,就像在搅拌机里混合搅拌那样,直到不能区分彼此的时候,就得到了质量,这也是“测试驱动开发”软件开发模式的基本思想。
与传统软件测试不同的是,由于以CFD为代表的科学计算过程包括逻辑运算和浮点运算,因此CFD软件测试除了要开展常规的静态扫描、单元测试以及逻辑正确性测试外,还要开展针对不同科学算例的集成测试和回归测试。CFD软件的集成测试是保证CFD软件质量的最后一道屏障,而目前大多数从业者依靠开发者人工发送计算作业、手动收集计算结果进行对比分析,占去了CFD软件开发者的大量时间,严重影响了CFD软件的开发效率。并且往往是在开发后、发布前进行集成测试,存在软件开发与软件测试严重脱离的问题。随着软件版本的更新,不但不能保证CFD软件开发的稳步前进,质量问题也得不到明确的保障。所以,在CFD软件开发中引进自动化测试系统显得尤为重要。
为了满足我国在航空航天、交通运输、能源动力、桥梁建筑等产业创新以及武器装备研制过程中对大规模CFD软件的需求,中国空气动力研究与发展中心开发了一款通用CFD软件——“风雷”软件[11-14](NNW-PHengLEI,源于作者团队开发的结构/非结构混合求解器HyperFLOW[15-17])。该软件研制目标是开发一款面向下一代的、结构解算器/非结构解算器耦合求解的、具备多学科计算扩展能力的大型通用CFD软件。该软件已于2016年面向全国发布并免费使用。
此前,在“风雷”软件开发过程中,为了提高开发效率、保证软件质量,并减少测试工作对于人力资源的过多占用,开发了与CFD软件平台匹配的自动化测试平台(Automated Test Platform,ATP)[18]。该平台基于数据库,通过前台界面和远程集群后台管理程序的网络进行信息交互。自动化测试的主要工作原理是:在已建立的基本CFD算例数据库基础上,“风雷”软件每次版本提交后自动编译并运行数据库中的所有算例,将计算结果和标准结果进行对比以检测代码是否正确,与此同时,对计算结果进行统计分析、误差分析等初步的验证与确认。ATP平台具备友好的人机交互界面,开发了算例管理、算例测试监控和算例结果分析等功能,大幅提高了“风雷”软件的开发效率,减少了代码错误率,CFD代码质量得到有效保证。
然而,随着“风雷”开发团队的扩大、软件功能的增加,软件开发过程中的一些开发模式问题逐渐显现出来。大型软件一般需要数十个乃至上百个程序员一起进行并行开发,他们会分为多个开发组,完成不同的模块任务,也必然会在同一套代码下面工作。目前,风雷软件代码量已经达到数十万行,开发团队人员达到数十人,每天都有数十个版本更新。随着开发规模的逐渐扩大,在实际开发中陆续出现以下新问题:
(1) 代码管理难度及学习成本增加。只有几个人的开发团队可以用单一的SVN等工具管理代码,当团队增加后,在代码分支、代码权限等方面出现不可调和的矛盾。而且,新人学习需要花费大量时间,极易因为错误的操作导致混乱,严重阻滞软件的开发进程。
(2) 模块化开发难度剧增。对于大型通用CFD软件,功能复杂,模块数量多,往往需要根据不同的开发小组将软件分解为不同的模块,各模块以静态库或动态库的形式在其他团队中得到体现,而单一版本的软件代码难以胜任。
(3) 人工成本增加。大型通用CFD软件被分解为若干个模块后,在每次测试前,需要人工部署、人工集成,既增加人工成本又容易出错。而且,在开发过程中,软件代码的变动很大,往往以前验证确认的算例在经过一些版本的升级之后又需要重新进行验证确认,人工成本太大,基本属于重复性工作,效率低下。
(4) 缺陷率增加。由于代码的更新迭代的速度很快,错误的累积和纠缠将导致错误更加隐蔽,由此产生的代码停滞将直接阻碍软件开发的进度,造成软件开发周期的失控。多人并行开发导致多样性的错误源,每个人引入的错误会直接或间接地导致其他人开发出现问题,并且很难找到问题所在。
大型软件的开发不同于小作坊式个体劳动,是有组织有计划的群体活动。针对上述问题,“风雷”软件开发过程中不仅需要ATP,还需要一个持续集成平台(Automated Continuous Integration,ACI)从事代码集成管理工作,并且将二者相结合起来,形成一个完善可靠的风雷软件开发管理环境,提升软件开发的质量与效率。
在文献[18]中已经对“风雷”软件自动化测试平台ATP进行了详细介绍,本文主要介绍持续集成平台ACI的设计开发以及和ATP一起形成的CFD软件开发环境。
1 开发环境设计 1.1 总体设计开发环境是开发团队与软件之间的纽带,基于该环境,开发团队实施编码、版本管理、集成、测试, 通过建立规范统一的CFD软件代码开发流程,不断地将开发成员的工作集成到软件主体,经过严格的代码审核后提交进入代码库,然后经过自动构建、自动部署、自动测试等过程,形成可供直接使用的CFD软件产品,并将整个过程中出现的问题及时地反馈给开发人员,开发人员及时解决此次集成中出现的错误后重新进行提交集成,从而形成一个不断修正、不断完善的良性开发流程。该环境由自动化持续集成平台(ACI)、自动化测试平台(ATP)组成(如图 1)。
自动化持续集成平台(ACI),基于开源代码管理工具Gitlab,负责软件模块(团队)管理、代码版本管理(提交、审核、合并、集成)。CFD软件往往由多个模块组成,PHengLEI软件由前处理、解算器、后处理三大模块构成,各模块具有其独立性,但模块之间又存在一定依赖性。每个模块在开发的过程中都有相应的开发团队。由于每个模块所需要开发的功能复杂,且需要开发人员具备较高专业水平的CFD理论基础,因此团队中的开发人员只能专注于某一个功能模块的开发,而无多余的时间精力关注其他功能模块,由此,团队中的密切协作至关重要。由于复杂的CFD功能模块开发周期较长而且模块之间存在相互依赖性,所以采用的自动化持续集成方案既要考虑到集成的长期性和稳定性,也要关注模块的依赖性,尽早发现问题尽早解决,保证软件的整体开发进度。为此,ACI中构建了“团队—模块—库”的对应关系,即,将开发团队分成不同的组,开发对应的功能模块。例如,图 1中列出了2组,分别对应开发API模块和CFD模块。
自动化测试平台(ATP),负责对ACI集成之后的软件进行测试。团队开发过程中会频繁提交代码,通过ATP控制每次提交代码的质量,减小错误率。
1.2 自动化持续集成平台ACI持续集成被认为是一种基于某些变化,对软件系统进行的经常性的构建活动。从人与人的交互性方面,持续集成又被认为是软件开发团队所采用的整个开发流程及活动,它强调开发团队与软件系统之间的互动性,其典型特征在于“持续”与“自动化”。自动化持续集成平台(ACI)的功能是协同管理开发团队提交的分支或主干代码,将其编译、集成、部署,得到满足需求的软件产品。在一个持续集成周期内,主要包括:
(1) 部件管理。基于“团队—模块—库”模式,将PHengLEI软件分解为多个模块,主要包含CFD解算器和应用程序编程接口(API)两个部分,API自底而上又分为Common、DataStruct、Math层,Data、MPI、Toolkit层,和Geometry、IO层,每个层次分属不同的开发团队,一个模块对应一到两个开发人员。开发人员提交代码后,能编译所属的代码库,并通过“钩子”,将归属其他团队的模块类库,拉取到环境并链接,生成可执行程序。
(2) 分支管理。考虑到集成的长期性和稳定性,代码由分支和主干组成,开发人员在分支上从事开发工作。只有通过自动化测试平台ATP测试的分支,才能被合并到主干,作为发布版本。多人团队开发软件过程中,分支与主干的管理尤为重要,直接关系到成员间的工作是否能协同开发,模块间的依赖性问题是否能够及时解决。图 3是风雷软件持续集成方案中的分支管理情况,分为主分支(即主干)、功能分支和Bug分支。开发者在功能分支上进行开发,向所对应的模块库中提交代码,一周内要合并一次他人代码,及时获得其他成员的贡献,并及时发现模块的依赖性问题,尽早解决,当完成给定的功能时,可向主干合并。在代码合并过程中,采用令牌独占机制,只有当令牌为可用状态时,才能执行合并操作,以避免合并产生冲突。Bug分支主要用于解决开发过程中发现的缺陷,分支的生命周期由Bug的发现和解决决定。为保证代码质量,在分支提交、代码合并前,都需经ATP执行测试,以保证集成的稳定性。
软件开发过程主要包含4个层次的测试:处于开发阶段的开发测试与Alpha测试、质量确认阶段的确认测试、针对用户的Beta测试(图 4)。本文的自动化测试平台(ATP)指的是开发测试。
自动化测试平台(ATP)的功能是,对由自动化持续集成平台ACI集成的可执行程序,开展CFD算例测试。新加代码功能的同时,要添加对应的可覆盖的算例,而每次新提交的代码,不应对已有算例结果造成影响。对ATP算例库中的每个CFD算例,设定标准“答案”后,每次提交代码编译的可执行程序的计算结果,应与标准“答案”一致。根据测试对象的粒度粗细,可将CFD软件测试分为单元测试、集成测试与系统测试,其测试内容与一般软件测试存在一定差异。
(1) 单元测试,是为了验证一个代码单元的功能,一般与运行环境隔离,例如针对一个独立的类或一组相关函数的测试。其外部依赖一般集中在函数级别的独立操作与调用上,可以提供更加全面的底层代码覆盖率和测试时间段,测试频繁,几乎每次代码进行了更改都会进行单元测试。CFD软件中的单元测试可以是限制器、通量格式、数据结构、文件I/O等独立的模块、函数和类。在CFD软件开发中,代码单元的功能实现需要具备CFD基础理论知识才能完成,所以单元测试算例一般由CFD软件开发人员来编写;每个单元测试算例评价内容不一,需要视情况而定,评价参考量包含但不限于单个变量、向量、矩阵等不同数据, 例如网格点线面的连接关系、壁面距离的计算结果、通量的计算结果等;参考量与标准“答案”要保持完全一致,才能视为单元测试通过。
(2) 集成测试,用于测试各个模块之间的集成,验证两个或多个模块之间的交互,与单元测试相比,有着更大的范畴且运行所需时间也更久。单元测试会尝试达到更大的代码覆盖率,而集成测试主要目标是验证指定模块间的交互。其执行频率需要加以控制。CFD软件中,集成测试主要是指一些简单的CFD算例,以测试软件的独立功能模块是否正常运行,能否运行一些CFD基本功能,如前置处理、只有数十步迭代的简单CFD算例、重启续算等。主要定性地考察代码的更改是否对基本功能产生影响,评价标准是残差和气动力的变化范围,通常通过计算其与标准“答案”的相对误差的平均值和方差来反映影响大小。
(3) 系统测试,针对大型标模的计算算例进行验证确认。系统测试在一个完全真实的层次运行,验证系统作为一个整体是如何工作的。通常一个系统测试的完成需要几天甚至更长的时间,要根据算例大小、网格大小来确定。在计算完成后,将计算结果和实验值或者其他计算结果进行对比,并采用了Oberkampf提出的一种不确定度尺度进行初步的验证工作[18-19],该不确定度的表达式为:
$ V = 1 - \frac{1}{I}\sum\limits_{i = 1}^{i = I} {{\rm{tanh}}\left| {\frac{{y({x_i}) - Y({x_i})}}{{Y({x_i})}}} \right|} $ |
式中,I是需进行确认的位置点的总数,y(xi)与Y(xi)分别是位置xi处的计算与实验值,后者实际以平均值代替。V越接近1,实验值与计算值的一致性越好。
表 1对比了三类测试的区别,主要表现为测试对象不同、持续时间不同、所关注的对象不同、测试频率与时间不同。目前,风雷软件开发环境有115个集成测试,93个系统测试。单元测试还在不断丰富中。集成测试每天运行10余次,每次测试控制在5 min以内。系统测试算例包含了从低速到高超声速流动、二维到三维、结构/非结构网格的标模算例,在集群上每周五晚上运行一次,需要约25万CPU机时。
自动化测试平台基于QT开发,图 5是目前开发完成的界面,主要包含:算例管理模块、测试管理模块、结果分析和查询模块。
国家数值风洞工程“风雷”软件开发过程中,通过持续集成与测试平台构建完善的软件开发环境,在加快软件敏捷迭代开发效率的过程中发挥重要的作用。图 6~图 9是平台自动生成的统计数据图,对“风雷”软件开发过程完成的各类信息进行了统计,以分析开发环境对软件开发的促进作用。
从每月提交代码统计看(图 6),2019年度共提交了3557次代码,其中3月份次数最多达到524次,平均每月提交约250次;测试总出错为1700次,达到总提交次数的47.79%。通过开发环境,可清晰地展示开发团队在不同时间段的代码开发效率,及时发现、纠正代码缺陷问题,保证软件质量的同时能进一步促进软件开发效率。
图 7进一步对导致错误的原因进行了细化,将错误类型分为链接错误、编译错误和测试错误三种。可以看到,代码错误主要是来源于3级测试,其次是编译错误,链接错误最少。通过自动识别并对错误进行分类,有利于开发人员尽早发现并解决问题。软件开发过程中,测试是不可缺少的一环。将测试和开发融合在一起,开展自动化测试有利于进一步提高软件开发效率和软件质量。
为了分析代码错误来源,提高团队开发水平,从单个开发人员角度出发,分析了给定时间段内,不同开发人员的代码错误率(图 8)。通过提交代码次数和错误率的统计,可清晰统计开发团队中每个开发人员的提交次数、错误率。
开发环境除了要保证代码的正确性,还要分析CFD计算效率。对给定的算例,统计了不同版本软件的CPU墙上计算时间变化情况(图 9)。图中横坐标是解算器版本信息,纵坐标是CPU墙上时间。可以看到,绝大部分版本的计算时间都差异不大,仅有少数版本因错误引入导致计算时间跳跃。同时,从第1300版本开始,由于算法改进,计算时间减少。通过记录不同版本解算器的计算效率,严格控制不同开发人员提交的代码对于主干的影响,保证解算器的计算效率。
通过ACI & ATP平台,不仅有利于开发人员进行代码的提交和集成,完成代码的统一管理,还能对代码质量起到“监督”作用。通过及时监控,统计研发过程中的各类数据,可掌控软件研发的细节和进度,保证软件质量,提高软件开发效率。
3 总结与展望针对国家数值风洞“风雷”软件团队开发的需要,设计研发了自动化持续集成平台(ACI)与测试平台(ATP)。通过建立规范统一的CFD软件代码开发流程,持续地将CFD软件开发成员的工作集成到软件,经过自动构建、自动测试、自动部署等过程,形成可供直接使用的CFD软件产品,并将整个过程中出现的问题及时地反馈给开发人员,开发人员及时解决此次集成中出现的错误后重新进行提交集成,从而形成一个不断修正不断完善的良性的软件开发流程。结合ACI & ATP平台,构建了一个完善可靠的CFD软件开发环境,对软件开发的质量与效率提升给予保证。
[1] |
POST D, SUNDT S. CREATE:acceptance and adoption of virtual prototyping across the defense R & D and acquisition communities[J]. Computing in Science & Engineering, 2017, 19(6): 6-8. DOI:10.1109/mcse.2017.3971165 |
[2] |
POST D, ATWOOD C, NEWMEYER K, et al. The computational research and engineering acquisition tools and environments (CREATE) program[J]. Computing in Science & Engineering, 2016, 18(1): 10-13. DOI:10.1109/mcse.2016.2 |
[3] |
ATWOOD CA M, ADAMEC S, POST D, et al. Collaborative software development of scalable DoD computational engineering[C]//HPCMP-UGC'10: Proceedings of the 2010 DoD High Performance Computing Modernization Program Users Group Conference. 2010: 414-420. DOI: 10.1109/HPCMP-UGC.2010.25[LinkOut]
|
[4] |
AREVALO S, ATWOOD C, BELL P, et al. A new DoD initiative:the Computational Research and Engineering Acquisition Tools and Environments (CREATE) program[J]. Journal of Physics:Conference Series, 2008, 125: 012090. DOI:10.1088/1742-6596/125/1/012090[LinkOut |
[5] |
MORTON S A, MEAKIN RE. HPCMP CREATETM-AV kestrel architecture, capabilities, and long term plan for fixed-wing aircraft simulations[C]//Proc of the 54th AIAA Aerospace Sciences Meeting, San Diego, California, USA. Reston, Virginia: AIAA, 2016. AIAA-2016-0565. DOI: 10.2514/6.2016-0565
|
[6] |
LEICHT T, VOLLMER D, JÄGERSKVPPER J, et al. DLR-project Digital-X next generation CFD solver 'Flucs'[C]//Proc of Deutscher Luft und Raumfahrtkongress, 2016. Document ID: 420027.
|
[7] |
KROLL N, ABU-ZURAYK M, DIMITROV D, et al. DLR project Digital-X:towards virtual aircraft design and flight testing based on high-fidelity methods[J]. CEAS Aeronautical Journal, 2016, 7(1): 3-27. DOI:10.1007/s13272-015-0179-7 |
[8] |
SCHWAMBORN D, GERHOLD T, HEINRICH R. The DLR TAU code: recent applications in research and industry[C]//Proc of European Conference on Computational Fluid Dynamics, 2006: 1-25.
|
[9] |
齐治昌, 谭庆平, 宁洪. 软件工程[M]. 北京: 高等教育出版社, 2001. QI Z C, TAN Q P, NING H. Software Engineering[M]. Beijing: Higher Education Press, 2001. (in Chinese) |
[10] |
WHITTAKER J, ARBON Jason, CAROLLO J. Google软件测试之道[M].李师贤, 蒋爱军, 梅晓勇, 林瑛, 译.北京: 人民邮电出版社, 2013.
|
[11] |
赵钟, 何磊, 何先耀. 风雷(PHengLEI)通用CFD软件设计[J]. 计算机工程与科学, 2020, 42(2): 210-219. ZHAO Z, HE L, HE X Y. Design of general CFD software PHengLEI[J]. Computer Engineeringand Science, 2020, 42(2): 210-219. DOI:10.3969/j.issn.1007-130X.2020.02.004 (in Chinese) |
[12] |
赵钟.超大规模并行CFD方法研究及软件研发[D].绵阳: 中国空气动力研究与发展中心, 2018.
|
[13] |
陈坚强.国家数值风洞(NNW)工程关键技术研究进展[J].中国科学: 技术科学, 2020(在线发表). CHEN J Q. Advances in the key technologies of Chinese National Numerical Windtunnel project[J]. Scientia Sinica Technologica, 2020(online). (in Chinese) DOI: 10.1360/SST-2020-0334 |
[14] |
赵钟, 张来平, 何磊, 等. 适用于任意网格的大规模并行CFD计算框架PHengLEI[J]. 计算机学报, 2019, 42(11): 2368-2383. ZHAO Z, ZHANG L P, HE L, et al. PHengLEI:a large scale parallelCFD framework for arbitrary grids[J]. Chinese Journal of Computers, 2019, 42(11): 2368-2383. DOI:10.11897/SP.J.1016.2019.02368 (in Chinese) |
[15] |
赫新, 赵钟, 张来平.结构非结构耦合计算CFD软件HyperFlow初步验证[C]//第15届全国计算流体力学会议论文集.烟台, 2012. HE X, ZHAO Z, ZHANG L P. The research and development of structured/unstructured hybrid CFD software 'HyperFlow'[C]//The Proceedings of the 15th Chinese CFD Conference, Yantai, 2012. |
[16] |
赫新, 张来平, 赵钟, 等. 大型通用CFD软件体系结构与数据结构研究[J]. 空气动力学学报, 2012, 30(5): 557-565. HE X, ZHANG L P, ZHAO Z, et al. Research of general large scale CFD software architecture and data structure[J]. Acta Aerodynamica Sinica, 2012, 30(5): 557-565. (in Chinese) |
[17] |
HE X, ZHAO Z, ZHANG L P. The research and development of structured-unstructured hybrid CFD softwar[J]. Transactions of Nanjing University of Aeronautics & Astronautics, 2013, 30(sup): 116-126. |
[18] |
何磊, 赫新, 马戎, 等. 大型CFD软件自动化测试平台的初步设计与实现[J]. 空气动力学学报, 2016, 34(4): 418-425. HE L, HE X, MA R, et al. Preliminary design and application of CFD software automatic testing platform[J]. Acta Aerodynamica Sinica, 2016, 34(4): 418-425. DOI:10.7638/kqdlxxb-2014.0102 (in Chinese) |
[19] |
OBERKAMPF W L, TRUCANO T G. Validation methodology in computational fluid dynamics[R]. AIAA 2002-2549, 2002.
|