当前位置: 首页 > article >正文

28-模块四-AI代码审核实战 第28讲-代码质量评分体系 - 可维护性 可读性 可测试性的量化指标

本讲目标:理解「量化指标」如何把主观感受变成可治理信号;掌握从 Python AST 计算圈复杂度与认知复杂度的基本方法;实现可配置权重的QualityScorer、历史趋势与团队基准对比接口;输出 JSON 与 Markdown 双语报告,嵌入 CodeSentinel 审核结论。本讲强调可解释:每个分数都能追溯到具体函数与规则。建议你把quality_report.md当作 PR 评论附件的生成原型,在团队评审会上走一遍阅读路径。开场:没有度量,就没有改进;但只有度量,也没有意义很多团队在引入自动代码审核后,会迅速遇到一个尴尬局面:评论越来越多,研发越来越烦,但质量是否变好却说不清楚。根因通常是两类缺失。第一类缺失是指标缺失:你只告诉对方「这里不好」,却没有说明「不好到什么程度、相对团队基线如何、修复后能改善多少」。第二类缺失是语境缺失:复杂度在核心领域服务里可能值得付出,在一次性脚本里却不值得同等对待;没有语境的分数会变成无意义的惩罚。本讲要做的不是堆叠学术指标,而是搭建一套可落地、可配置、可复盘的评分体系,让它服务三个决策场景。场景一是 PR 级别的快速反馈:贡献者在十分钟内看到本次变更对质量分数的影响。场景二是团队级别的趋势管理:负责人能看到过去四周平均复杂度、覆盖率与债务比的变化。场景三是平台级别的规则迭代:当某条规则与缺陷率相关性弱,你可以用数据把它降级或删除。我们会重点处理三类指标家族。第一类是结构复杂性(圈复杂度、认知复杂度):它们与缺陷密度、评审耗时、合并冲突率有广泛实证相关性。第二类是可维护性综合指标(Maintainability Index,MI):它把体量、复杂度、注释等压缩为一个可比较分数,但要注意不同语言实现差异。第三类是过程性指标(测试覆盖率、代码搅动、技术债务比):它们来自测试产物与版本历史,更能解释「为什么这次 PR 风险更高」。下面先给出 CodeSentinel 质量评分在平台中的流水线位置,再展开计算公式与完整实现。完成本讲后,你应能把「感觉难维护」翻译成「哪一个函数把分数拉低」,并能把分数映射为 A/B/C/D/F 等等级用于门禁与看板。全局视角:质量评分流水线(Mermaid)输出评分层计算层数据源Python 源码(单文件/快照)coverage.json(可选)git log(可选 churn)issues 估算(可选债务字段)AST 解析Cyclomatic圈复杂度Cognitive认知复杂度(简化)MaintainabilityIndex 近似多维加权聚合QualityScorer权重+阈值等级映射A-F趋势序列(时间桶)团队基准分位数)quality.jsonquality.mdHTTP 报告接口(可选)核心原理:为什么这些指标值得进入 CodeSentinel1. 圈复杂度(Cyclomatic Complexity)衡量「决策密度」圈复杂度来源于控制流图:每个决策点(if、for、while、except、布尔短路、case 分支等)都会增加独立路径数量。经验法则是:函数 CC 超过 10~15,单元测试组合爆炸、缺陷概率上升。对 Python AST,可用经典算法:从函数节点子树开始,统计特定语句与表达式节点类型并加总。注意and/or短路在 AST 里是BoolOp,是否计入取决于你们团队标准;本讲实现采用「计入 BoolOp」的较严格版本,可在配置里关闭。2. 认知复杂度(Cognitive Complexity)衡量「人类阅读负担」认知复杂度在圈复杂度基础上惩罚嵌套:深层 if 比平铺的并列 if 更难读。Sonar 的规则体系是行业参考。教学实现可以做简化版:每个嵌套层级对新增决策加权重;break/continue、多分支match、以及lambda内嵌套按增量规则处理。目标是让分数与工程师直觉更一致,而不是与编译器优化一致。3. 可维护性指数(Maintainability Index)是「压缩摘要」经典 MI 形式类似:[\text{MI} = 171 - 5.2 \ln V - 0.23 G - 16.2 \ln L]其中 (V) 为 Halstead Volume(教学实现可用行数与运算符数量的近似),(G) 为圈复杂度,(L) 为有效代码行数。不同工具常做 0~100 归一与钳制。MI 的价值是:在仪表盘上给非技术干系人一个「趋势向好/向坏」的信号。缺点是:对短函数或小文件波动大,因此 PR 级别应看增量影响而不是绝对值。4. 测试覆盖率:线覆盖与分支覆盖覆盖率不是质量本身,而是未验证变更范围的代理指标。CodeSentinel 应读取coverage.py输出的 JSON(coverage json -o coverage.json),提取totals.percent_covered与文件级明细。分支覆盖更能抓if的另一半,但工具链更重。建议门禁策略:对核心包目录要求分支覆盖阈值,对工具脚本目录放宽。5. 代码搅动(Code Churn)与缺陷相关性搅动可以定义为:某文件在最近窗口期内被修改的次数或行数。实证研究常见结论是:高搅动文件缺陷率更高。实现上可用git log --since=... -- path统计。把 churn 作为「风险乘子」比作为绝对分数更稳:同一复杂度下,搅动高则降级。6. 技术债务比(Technical Debt Ratio)简化定义:[\text{TDR} = \frac{\text{estimated_fix_minutes}}{\text{development_minutes}}]在自动平台里,estimated_fix_minutes可由规则引擎汇总(每条规则带修复成本估计),development_minutes可由提交时间差或工单记录估计。教学实现允许外部传入,避免绑定特定项目管理工具。7. 评分体系:A/B/C/D/F 与阈值建议把综合分映射为百分制,再映射等级:A:≥ 90B:80~89C:70~79D:60~69F: 60阈值必须团队化:数据科学团队可能接受更高复杂度,基础设施团队可能对覆盖率更苛刻。QualityScorer必须把权重与阈值做成配置,而不是写死在代码里。8. 历史趋势与基准对比的工程含义趋势不是画图好看,而是为了回答:「我们上周的治理是否有效」。实现上可用时间序列桶(按天/周)存储聚合均值与中位数。团队基准对比建议使用分位数:你的 PR 在团队当月分布的 P75 之上,才触发 warning,避免内卷式「永远不满意」。9. 与 AI 生成代码相关的特殊点生成代码往往「结构正确但过度防御」:大量 try/except、深层嵌套、以及重复分支,导致 CC/COG 同时飙升。评分体系应配合「允许的解释字段」:当模型引入额外分支是为满足规范(例如安全审计要求),应在 PR 描述里标注,平台支持标签降权。10. 误用指标的典型反模式把 MI 当唯一真理、把覆盖率当 KPI 强行 100%、把 churn 当个人绩效,这些都会扭曲行为。平台方要明确:指标服务于风险沟通,不服务于人事评判(除非你刻意设计且经过治理委员会批准)。11. AST 计算的边界AST 无法知道运行期分支频率;复杂度相同但业务关键度不同的函数需要人工标注权重。可以在文件级 docstring 约定# codesentinel: criticality=high之类扩展点(本讲不实现完整解析器,仅提示方向)。12. 性能与缓存对大仓库,AST 解析可并行;指标结果应按(commit, path, hash)缓存。Quality 报告生成应是增量式的:仅对变更文件重算,再与父提交聚合。13. 多语言扩展本讲聚焦 Python。其他语言应接入对应分析器(Sonar、CodeQL、原生工具),再映射到统一 schema:metric_pack+value+evidence。14. 报告可读性Markdown 报告要包含:总览表、Top 风险函数列表、与上一版本的差分。JSON 报告要稳定版本化:schema_version字段必须有。15. 与 findings 的耦合方式质量分数不应替代安全 finding;建议并行输出:findings[]+quality_summary。合入门禁可以要求「无 high finding 且 grade = C」。16. 统计学谨慎小样本团队的分位数不稳定;至少积累 N 个 PR 后再启用强门禁。可以先用「仅提示」模式。17. 伦理与隐私churn 统计可能暴露个人加班节奏;聚合到团队级更安全。18. 与模块二审核聚合对齐codesentinel-clean-lab的 review 模型可追加quality_score字段或作为评论附件上传,避免破坏既有 API。19. 版本升级策略指标算法变更会改变历史可比性;记录algorithm_version并在变更时重建趋势。20. 落地路径第一周只计算 CC 与行数;第二周加入覆盖率;第三周加入 churn;第四周再引入 MI 与债务比,避免一次性信息过载。21. 指标相关性与因果陷阱即使圈复杂度与缺陷率统计相关,也不意味着「降低圈复杂度必然降低缺陷」。更合理的表述是:高复杂度函数更难测试、更难评审,从而提高缺陷存活概率。平台文案要避免暗示因果,否则会被资深工程师质疑并抵制。你可以把相关性研究作为内部培训材料,但不要把论文结论写进门禁错误信息里。22. 组织行为:分数会如何改变协作方式当 PR 显示综合分下降,评审者可能把讨论焦点从业务正确性转向风格争论。为避免失焦,建议规则是:先判定功能与安全,再讨论质量分数;质量分数只作为合并前的最后一道「卫生检查」。另外,给维护者提供「override」能力并强制写理由,可以避免平台成为瓶颈。23. 代码生成器的偏差:模板化重复生成代码常常复制粘贴相似结构,导致多个函数同时处于「中等复杂度」区间,分数看起来平庸但系统整体难以推理。对此可以引入重复度指标(与本讲不同,但可并行):当 AST 子树相似度高于阈值,提示抽象不足。该指标要小心误报常见 boilerplate。24. 与 Code Review 评论模板结合Markdown 报告建议固定结构:摘要一行、子分数表、Top 风险函数、与父版本 diff(若可获取)、以及「建议下一步」。评论模板越稳定,研发越能快速扫描。不要在评论里贴完整 JSON,除非调试。25. 与静态类型检查的关系类型完善会降低某些缺陷类型,但对复杂度不一定有效。Mypy 通过与否与 CC 无必然联系。平台应并行展示:类型错误属于「正确性」通道,复杂度属于「可维护性」通道,避免混为一谈。26. 注释与文档字符串对 MI 的影响不同工具对注释处理不同。若 MI 把注释当「提高可维护性」的正向因素,可能鼓励无意义注释。更健康的做法是:MI 主要反映结构与复杂度,文档质量用独立规则(例如公共 API 必须有 docstring)评估。27. 分支覆盖的实现成本分支覆盖需要覆盖率工具支持。若团队暂不具备,可先用行覆盖并在报告里明确标注「风险未完全暴露」。当业务关键模块稳定后,再引入分支覆盖门槛。28. 搅动指标的窗口选择窗口太短会噪声大,太长会迟钝。常见选择是 30 天与 90 天并行:30 天用于风险提示,90 天用于架构健康度。对发布频繁的服务,7 天窗口也有意义,但要标注季节性因素(例如大促)。29. 债务比的估计误差estimated_fix_minutes若来自人工填写,容易乐观或悲观。更稳妥的是用历史修复耗时分布校准:同样 rule_id 的历史 PR 实际耗时中位数作为估计。平台需要工单系统或时间追踪数据支撑。30. 与「可读性」的主观维度可读性无法完全量化。认知复杂度是近似。团队可以做抽样:每月随机抽取十个 PR,让两名工程师独立打分可读性,与 COG 做对照,逐步调参。这个过程是「把组织偏好编码进工具」的关键。31. 指标歧视风险若把复杂度与绩效绑定,可能导致工程师规避必要分支(例如安全校验)。治理委员会应明确禁止不当使用场景,并在员工手册或研发规范里写明。32. 开源合规若你复用 Sonar 规则思想,注意许可证与版权声明;自研算法也要记录来源论文与参考实现,避免知识产权争议。33. 与 Feature Flag 的交互被 flag 保护的代码常有额外分支,复杂度上升但业务需要。建议 PR label:ff-heavy触发权重调整或跳过某些提示。34. 与数据科学的协作若团队有数据科学角色,可以帮你做分位数基线、异常检测与因果推断(需谨慎)。质量平台的数据是长期资产,应进入数据仓库而不是散落在 CI 日志里。35. 失败案例:门禁过严导致绕过平台当平台比组织协作节奏更慢时,研发会绕过平台直接在分支合并。要保持门禁「快」:计算增量、并行、缓存。否则指标再科学也落不了地。36. 与模块四整体叙事对齐本讲分数应与性能 finding、安全 finding 并列展示,而不是互相覆盖。最终 PR 评论是一个拼盘:风险、性能、质量、规范合规四类信息分区展示,阅读体验最好。37. 未来:LLM 作为解释器而非评分者让模型解释「为什么该函数 COG 高」很有价值;让模型直接给 0~100 分则不稳定。平台应坚持确定性指标为主,模型为辅。38. 与 IDE 集成在 IDE 显示当前函数的实时复杂度,可以把问题前移到编码阶段。CodeSentinel 服务端评分与 IDE 插件评分可能略有差异,需要统一算法版本。39. 跨仓库复制与搅动失真同名工具类在不同仓库复制粘贴会导致搅动指标异常低(因为每份看起来稳定)。单仓 monorepo 更利于真实反映修改频率;多仓需要服务级聚合。40. 本讲代码的演进路线下一步可以把FunctionMetrics输出为 SARIFmetrics扩展字段;可以把TrendStore换成 PostgreSQL;可以把fake_churn_score替换

相关文章:

28-模块四-AI代码审核实战 第28讲-代码质量评分体系 - 可维护性 可读性 可测试性的量化指标

本讲目标:理解「量化指标」如何把主观感受变成可治理信号;掌握从 Python AST 计算圈复杂度与认知复杂度的基本方法;实现可配置权重的 QualityScorer、历史趋势与团队基准对比接口;输出 JSON 与 Markdown 双语报告,嵌入 CodeSentinel 审核结论。本讲强调可解释:每个分数都…...

新手福音:用快马平台生成wsl安装ubuntu图文教程,轻松入门linux开发

最近在学Linux开发,发现Windows Subsystem for Linux(WSL)真是个神器,特别是搭配Ubuntu使用,既保留了Windows的便利性,又能体验原汁原味的Linux环境。不过刚开始安装配置时踩了不少坑,后来用Ins…...

一篇大模型Agents工作流优化最新综述

过去,人们总希望一个LLM直接把任务做完;现在,一个更现实的方向正在浮现——针对不同任务设计不同工作流,并让系统在执行前、执行中乃至执行后持续优化这条链路。 近日,Rensselaer Polytechnic Institute(RP…...

指挥OpenClaw抓取数据折腾了一夜,我终于想到了邪修玩法

这段时间玩小龙虾玩得真上头,突然想起之前一直想要统计公众号的数据。 这工作交给小龙虾妥妥能胜任啊!但是吧……实际上执行出来的结果却不是这样的。 因为小白本地使用的是OpenClawAtomgit的方案,Atomgit主打一个不费一分钱,免…...

DeepSeek-Coder-V2终极指南:如何免费打造你的专属AI编程助手

DeepSeek-Coder-V2终极指南:如何免费打造你的专属AI编程助手 【免费下载链接】DeepSeek-Coder-V2 DeepSeek-Coder-V2: Breaking the Barrier of Closed-Source Models in Code Intelligence 项目地址: https://gitcode.com/GitHub_Trending/de/DeepSeek-Coder-V2 …...

从“动态规划”到“强化学习”:贝尔曼方程的前世今生与核心思想

从“动态规划”到“强化学习”:贝尔曼方程的前世今生与核心思想 1953年,美国数学家理查德贝尔曼在兰德公司研究导弹防御系统时,面对复杂的多阶段决策问题,提出了一个革命性的数学工具——动态规划。这个诞生于冷战背景下的理论&am…...

Windows ISO制作与补丁集成自动化工具实战指南:从手动操作到批量部署的效率革命

Windows ISO制作与补丁集成自动化工具实战指南:从手动操作到批量部署的效率革命 【免费下载链接】Win_ISO_Patching_Scripts Win_ISO_Patching_Scripts 项目地址: https://gitcode.com/gh_mirrors/wi/Win_ISO_Patching_Scripts 在数字化时代,系统…...

掌握PingFangSC字体配置优化:面向全平台开发者的专业指南

掌握PingFangSC字体配置优化:面向全平台开发者的专业指南 【免费下载链接】PingFangSC PingFangSC字体包文件、苹果平方字体文件,包含ttf和woff2格式 项目地址: https://gitcode.com/gh_mirrors/pi/PingFangSC 比传统方案提升30%效率的跨平台适配…...

导入MotorCAD API(需先安装MotorCAD的Python接口)

基于Motorcad的4极6槽 内转子采用内插式磁钢 3000rpm 输出转矩 2.6Nm 效率93%外径 94mm 轴向长度70mm 功率800w 直流母线380V 永磁同步电机(永磁直流无刷)模型(PMSM或者是BLDC) 最近捣鼓了个小功率PMSM模型,用MotorCAD搭了个4极6槽内插式的&a…...

3张表搞定财务BP工作!财务BP必须会的3张表

做了这么多年财务数据分析,我发现国内很多公司的财务BP,还停留在自己造表的阶段。每人一套表,格式五花八门,数据口径对不上。结果就是BP花大量时间在拉表、对数的琐事上,真正花在业务分析和决策支持上的时间少之又少。…...

C语言基础:LiuJuan20260223Zimage嵌入式开发入门

C语言基础:LiuJuan20260223Zimage嵌入式开发入门 1. 学习目标与前置知识 如果你是刚开始接触嵌入式开发的C语言初学者,这篇文章就是为你准备的。我们将从最基础的C语言语法开始,一步步带你了解如何在嵌入式环境中使用C语言进行开发。不需要…...

大厂高薪抢手!文科生如何抓住AI时代机遇,实现职业逆袭?

大厂纷纷高薪招聘文科生,引发社会关注。文科生凭借沟通、叙事、逻辑等优势,在大模型理解人类价值观、企业品牌宣传等方面发挥作用。高校也调整专业设置,培养跨学科人才。文章建议文科生根据自身专业,向文案策划、品牌宣传、法务、…...

智慧树自动化学习工具终极指南:解放双手,高效完成课程学习

智慧树自动化学习工具终极指南:解放双手,高效完成课程学习 【免费下载链接】fuckZHS 自动刷智慧树课程的脚本 项目地址: https://gitcode.com/gh_mirrors/fu/fuckZHS 智慧树自动化学习工具是一款专为智慧树平台设计的Python脚本,能够帮…...

突破Wallpaper Engine资源壁垒:RePKG工具全方位应用指南

突破Wallpaper Engine资源壁垒:RePKG工具全方位应用指南 【免费下载链接】repkg Wallpaper engine PKG extractor/TEX to image converter 项目地址: https://gitcode.com/gh_mirrors/re/repkg 一、RePKG:解锁创意资源的技术钥匙 在数字创意领域…...

2.2.2.3 Spark实战:词频统计

本次实战涵盖了Spark词频统计(WordCount)的两种主流实现方式。首先,利用Scala在spark-shell中完成从读取文件、flatMap分词、map映射到reduceByKey聚合的完整流程,并实现结果的降序排序。其次,针对Spark 3.3.2版本的需…...

Infinity Pro书签迁移终极指南:从JSON文件到本地缓存的完整操作流程

Infinity Pro书签迁移终极指南:从JSON文件到本地缓存的完整操作流程 作为一名长期使用Infinity Pro的开发者,我深知书签迁移的痛点。每次换设备或重装系统,那些精心整理的技术资源库都要重新配置。本文将分享一套经过实战验证的迁移方案&…...

告别卡顿!用SwiftFormer在iPhone上5分钟部署实时图像识别App(附完整代码)

在iPhone上5分钟部署SwiftFormer图像识别App的实战指南 从理论到实践:为什么选择SwiftFormer 去年夏天,我在为一个时尚电商客户开发AR试衣功能时,第一次被移动端视觉模型的性能问题难住。当时使用的模型在iPhone 12上每帧处理需要近200ms&…...

从rdt1.0到rdt3.0:可靠数据传输协议的演进与发送接收端FSM解析

1. 可靠数据传输协议的前世今生 第一次接触可靠数据传输协议(Reliable Data Transfer,简称rdt)是在十多年前的一个网络编程项目里。当时为了确保数据能准确无误地传输,我翻遍了各种资料,最终在《计算机网络&#xff1a…...

BiliTools:B站资源高效管理与下载完全指南

BiliTools:B站资源高效管理与下载完全指南 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools BiliTools是一…...

新手零基础入门:通过快马生成burpsuite超详细安装图解教程

作为一名网络安全新手,第一次接触BurpSuite时确实容易被各种专业术语和复杂的安装步骤吓到。今天我就用最直白的方式,手把手带你完成BurpSuite的安装,让你轻松迈出Web安全测试的第一步。 什么是BurpSuite?为什么需要它&#xff1…...

3 月 21 日G-Star Gathering Day 武汉站活动精彩回顾

3 月 21 日,G-Star Gathering Day 武汉站在鄂港澳青创园顺利举办。来自 AI 与开源领域的开发者、创业者齐聚一堂,围绕 AI Agent、代码智能体、个人创业形态与真实落地场景展开分享与交流。这不仅是一场技术沙龙,更是一场关于 “AI 如何真正改…...

Real-ESRGAN-GUI:如何用AI双引擎将模糊图片一键变高清

Real-ESRGAN-GUI:如何用AI双引擎将模糊图片一键变高清 【免费下载链接】Real-ESRGAN-GUI Lovely Real-ESRGAN / Real-CUGAN GUI Wrapper 项目地址: https://gitcode.com/gh_mirrors/re/Real-ESRGAN-GUI 还在为模糊的老照片、低分辨率的动漫图片而烦恼吗&…...

效率提升:基于快马平台为dc=y103pc=类参数快速打造调试工具

效率提升:基于快马平台为dcy103&pc类参数快速打造调试工具 在日常开发中,我们经常需要处理各种URL参数,尤其是类似"dcy103&pctest"这样的查询字符串。手动解析和修改这些参数不仅效率低下,还容易出错。最近我在…...

光流法在气象雷达中的应用:从原理到外推实践

光流法在气象雷达中的应用:从原理到外推实践 气象雷达作为现代气象监测的核心工具,其回波数据蕴含着丰富的天气系统动态信息。如何从这些看似静态的图像序列中提取运动规律,进而预测未来短时内的天气变化,一直是气象学界和工程界关…...

零基础入门Python爬虫:借助快马AI生成你的第一个可运行爬虫脚本

今天想和大家分享一下我作为Python爬虫新手的学习经历。刚开始接触爬虫时,面对各种库和概念真的有点懵,直到发现了InsCode(快马)平台,它让我用自然语言描述需求就能生成可运行的代码,大大降低了入门门槛。 爬虫的基本原理 爬虫就像…...

新手入门指南:基于快马生成的代码理解设备配对功能实现

今天想和大家分享一个特别适合新手学习的设备配对功能实现案例。这个例子用最基础的HTML、CSS和原生JavaScript就能完成,特别适合刚接触前端开发的朋友理解交互逻辑。 项目结构设计 整个项目分为三个部分:两个模拟设备(用不同图标表示&#x…...

量子计算入门捷径:在快马平台用qorder实现第一个纠缠态实验

量子计算听起来很高深,但有了合适的工具和平台,入门其实比想象中简单。最近我在InsCode(快马)平台上尝试用qorder框架做了第一个量子纠缠实验,发现整个过程就像搭积木一样直观。下面分享我的学习笔记,希望能帮到同样想入门的朋友。…...

零基础入门AI开发:在快马平台亲手制作你的第一个口播智能体

最近在尝试入门AI开发,发现用InsCode(快马)平台做"旗博士口播智能体"特别适合零基础选手。这个项目不需要自己从头写代码,但能完整走通AI应用开发全流程,分享下我的学习笔记: 项目整体结构 整个项目分三部分&#xff1a…...

AI开发AI:借助快马多模型能力,迭代式构建你的智能健康管理Agent

最近在尝试开发一个健康管理AI助手,发现用传统方式写代码调试特别耗时。后来尝试了InsCode(快马)平台,发现用AI对话的方式迭代开发简直打开了新世界。记录下这个"用AI开发AI"的完整过程: 基础框架搭建 最开始只需要一个能交互的对话…...

计算机毕业设计springboot基于web的好文阅读网站的设计与实现 SpringBoot在线文学阅读与创作平台的设计与实现 基于Web的数字化阅读社区系统构建

计算机毕业设计springboot基于web的好文阅读网站的设计与实现xl6429gd (配套有源码 程序 mysql数据库 论文) 本套源码可以在文本联xi,先看具体系统功能演示视频领取,可分享源码参考。随着互联网技术的飞速发展和数字阅读习惯的普及&#xff0…...