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

乙巳马年春联生成终端生产环境部署:日志监控与异常捕获机制

乙巳马年春联生成终端生产环境部署日志监控与异常捕获机制1. 引言从创意演示到稳定服务想象一下你精心打造的“皇城大门春联生成终端”在年会上大放异彩用户们争相输入愿望词看着金色笔墨在朱红大门上瞬间凝结现场气氛热烈。然而当你想把它部署到公司官网作为新年期间的常驻互动服务时问题来了万一用户量激增系统卡顿了怎么办万一AI模型突然“罢工”生成一堆乱码对联谁来发现并修复又或者深夜两点系统崩溃而你对此一无所知直到第二天上班才发现服务挂了整整一晚。这就是从“演示项目”到“生产环境服务”的关键一跃。一个炫酷的交互界面背后必须有一套坚实的运维体系来支撑确保它7x24小时稳定、可靠地运行。本文将手把手带你为“乙巳马年春联生成终端”构建生产级的日志监控与异常捕获机制让你不仅能“开门见喜”更能“高枕无忧”。你将学到什么为什么需要监控理解在生产环境中看不见的系统内部发生了什么至关重要。搭建日志系统使用Python的logging模块为你的Streamlit应用装上“黑匣子”记录每一次用户交互和系统状态。捕获与处理异常构建坚固的异常处理围墙确保单个用户的错误输入或内部bug不会导致整个服务崩溃。实现应用健康监控创建一个简单的健康检查端点让外部系统能随时“ping”一下你的应用确认它还活着。部署与验证将这套机制整合到你的Docker容器中并进行实际测试。无论你是独立开发者还是团队中的运维新手这套方案都将帮助你以最小的成本为你的AI应用披上可靠性的铠甲。2. 核心挑战生产环境面临什么在本地开发时我们通常直接在终端查看print语句。但在生产环境比如云服务器上的Docker容器这套方法完全失效。我们面临几个核心挑战日志去哪了容器内的print输出默认不会持久化容器重启日志就消失了。我们需要一个地方集中存储和查看日志。错误如何感知用户遇到一个生成失败如果只是前端弹个窗作为开发者我们可能完全不知情无法及时修复潜在的bug。系统健康状态应用是否在运行响应速度是否正常模型加载是否成功我们需要一个快速检查的方法。性能瓶颈在哪当大量用户同时“开门见喜”时是Streamlit服务慢了还是PALM模型推理慢了我们需要数据来定位问题。为了解决这些问题我们将引入三个核心组件结构化日志记录、全局异常捕获和健康检查端点。3. 实战部署构建监控体系接下来我们直接修改“皇城大门春联生成终端”的源代码为其注入生产级的能力。请确保你已备份原始代码文件通常是app.py。3.1 第一步配置结构化日志系统我们将用Python内置的logging模块替代所有print语句。它可以将日志按级别DEBUG, INFO, WARNING, ERROR分类并输出到文件和控制台。在你的app.py文件顶部添加以下日志配置代码import logging import sys from datetime import datetime import os # 创建logs目录如果不存在 log_dir ./logs os.makedirs(log_dir, exist_okTrue) # 生成带日期的日志文件名例如 app_2025-02-10.log log_filename datetime.now().strftime(f{log_dir}/app_%Y-%m-%d.log) # 配置logging logging.basicConfig( levellogging.INFO, # 设置记录级别为INFO及以上INFO, WARNING, ERROR, CRITICAL format%(asctime)s - %(name)s - %(levelname)s - %(message)s, # 日志格式 handlers[ logging.FileHandler(log_filename, encodingutf-8), # 输出到文件 logging.StreamHandler(sys.stdout) # 同时输出到控制台方便Docker查看 ] ) # 创建一个logger实例供整个应用使用 logger logging.getLogger(SpringCoupletApp) logger.info( 乙巳马年春联生成终端启动 ) logger.info(f日志文件将保存在: {os.path.abspath(log_filename)})这段代码做了什么在项目根目录创建了一个logs文件夹。每天生成一个新的日志文件方便按天归档。定义了清晰的日志格式时间 - 日志器名 - 级别 - 消息。同时将日志写入文件用于追溯和打印到控制台用于实时查看。3.2 第二步用日志记录关键事件现在我们替换掉原来可能存在的print语句并在关键操作点添加日志记录。找到你处理用户生成春联请求的核心函数可能叫generate_couplet或类似名称进行改造import time def generate_couplet_with_logging(keyword): 带日志记录的春联生成函数 logger.info(f收到生成请求关键词: {keyword}) start_time time.time() try: # 1. 记录模型调用开始 logger.debug(开始调用PALM模型进行推理...) # 这里是你原有的调用ModelScope模型的代码 # 假设结果保存在 result 变量中 # result pipeline(keyword, ...) # 2. 模拟一个结果请替换为你的实际代码 result { 上联: 龙马精神开锦绣, 下联: 春风得意展宏图, 横批: 马到成功 } inference_time time.time() - start_time logger.info(f春联生成成功关键词 {keyword} - 上联: {result[上联]} 推理耗时: {inference_time:.2f}秒) return result except Exception as e: # 错误日志将在下一步的全局异常处理中记录这里可以记录为警告 logger.warning(f春联生成函数内部捕获到异常已传递至全局处理: {e}) raise # 重新抛出异常让全局处理器接管关键点logger.info: 记录正常的业务流程如收到请求、生成成功。logger.debug: 记录更详细的调试信息在生产环境可以关闭此级别以减少日志量。记录了推理耗时这是监控性能的关键指标。3.3 第三步实现全局异常捕获与优雅降级这是保证应用不会崩溃的关键。我们将使用Streamlit的st.exception和自定义装饰器或try-catch来捕获所有未处理的异常并给用户友好的提示。在app.py中Streamlit主逻辑部分通常是if __name__ __main__:之前添加一个全局异常处理函数import streamlit as st import traceback def handle_global_exceptions(): 全局异常处理装饰器/上下文管理器。 在实际部署中更推荐使用装饰器包装主函数。 这里提供一个简化版的思路。 # 这个函数需要在你的主UI渲染逻辑中被调用 pass # 更实用的方法在调用核心业务函数的地方进行try-catch def safe_generate_couplet(keyword): 一个包装函数用于安全地调用生成逻辑并处理异常 try: return generate_couplet_with_logging(keyword) except Exception as e: # 记录详细的错误日志这是最重要的 logger.error(f生成春联时发生未捕获的异常关键词: {keyword}, exc_infoTrue) # exc_infoTrue 会记录完整的错误堆栈跟踪 # 给用户返回一个友好的错误信息和一套备用的、静态的春联 st.error( 哎呀门神打了个盹笔墨暂未就位请稍后再试或换个词试试。) # 优雅降级返回一个预定义的备用春联确保用户体验不中断 fallback_couplet { 上联: 福星高照全家福, 下联: 春光耀辉满堂春, 横批: 吉祥如意 } logger.info(f已为用户 {keyword} 返回备用春联。) return fallback_couplet然后在你的Streamlit界面按钮点击事件中调用safe_generate_couplet而不是原来的函数# 在你的Streamlit UI代码中 if st.button( 开门见喜): user_keyword st.text_input(写下您的马年愿望词) if user_keyword: with st.spinner(门神研磨金毫挥洒中...): # 使用安全的生成函数 couplet_result safe_generate_couplet(user_keyword) # 显示结果 st.success(生成成功) col1, col2, col3 st.columns(3) with col1: st.markdown(fh2 styletext-align: center;{couplet_result[上联]}/h2, unsafe_allow_htmlTrue) with col2: st.markdown(fh2 styletext-align: center;{couplet_result[下联]}/h2, unsafe_allow_htmlTrue) with col3: st.markdown(fh1 styletext-align: center;{couplet_result[横批]}/h1, unsafe_allow_htmlTrue)3.4 第四步添加健康检查端点健康检查端点允许运维系统如Kubernetes、Docker Healthcheck、负载均衡器快速判断你的应用是否处于正常工作状态。由于Streamlit原生不提供HTTP端点我们需要一个小技巧。可以在启动Streamlit服务的同时利用一个轻量级的线程来运行一个简单的HTTP健康检查服务。在app.py文件末尾启动Streamlit之前添加以下代码import threading from http.server import HTTPServer, BaseHTTPRequestHandler class HealthCheckHandler(BaseHTTPRequestHandler): def do_GET(self): if self.path /health: # 这里可以添加更复杂的健康检查逻辑例如检查模型是否加载 self.send_response(200) self.send_header(Content-type, text/plain) self.end_headers() self.wfile.write(bOK) # 返回OK表示健康 logger.debug(健康检查端点被访问返回200 OK) else: self.send_response(404) self.end_headers() def log_message(self, format, *args): # 静默健康检查端点的访问日志避免干扰 pass def run_health_check_server(): 在一个单独的线程中运行健康检查服务器 server HTTPServer((0.0.0.0, 8080), HealthCheckHandler) # 在8080端口监听 logger.info(健康检查服务已启动端口: 8080) server.serve_forever() # 在主程序启动前开启健康检查线程 if __name__ __main__: # 启动健康检查服务器线程 health_thread threading.Thread(targetrun_health_check_server, daemonTrue) health_thread.start() # 原有的启动Streamlit的代码 # 假设你原来用 streamlit run app.py现在需要调整 # 因为streamlit会接管主线程我们通常把健康检查放在Docker的启动脚本里更合适。 # 更生产化的做法将健康检查服务写在一个独立的check.py文件中在Dockerfile里同时启动它和streamlit。 logger.info(启动Streamlit应用...) # 这里省略实际启动Streamlit的代码保持你原有的方式生产环境建议更常见的做法是编写一个独立的health_check.py脚本然后在Dockerfile中使用CMD指令同时启动Streamlit和健康检查服务或者使用supervisord这类进程管理工具。4. 部署与验证让监控跑起来现在我们已经完成了代码改造。接下来需要将其部署到生产环境并验证监控是否生效。4.1 更新Dockerfile假设你原有的Dockerfile是直接运行streamlit run现在需要确保日志目录被持久化并且可以考虑加入健康检查指令。# 基于你原有的Dockerfile FROM python:3.9-slim WORKDIR /app COPY . . RUN pip install -r requirements.txt # 创建日志目录 RUN mkdir -p /app/logs # 暴露Streamlit端口和健康检查端口 EXPOSE 8501 8080 # 设置健康检查Docker原生健康检查每30秒检查一次超时3秒 HEALTHCHECK --interval30s --timeout3s --start-period5s --retries3 \ CMD curl -f http://localhost:8080/health || exit 1 # 启动命令可以写一个启动脚本同时启动健康检查服务和Streamlit # 或者使用进程管理工具如supervisord # 这里示例一个简单的shell脚本启动 CMD sh -c python health_check.py streamlit run app.py --server.port8501 --server.address0.0.0.0你需要创建一个health_check.py文件内容就是上面run_health_check_server函数的实现。4.2 验证步骤构建并运行新镜像docker build -t spring-couplet-prod . docker run -p 8501:8501 -p 8080:8080 -v $(pwd)/logs:/app/logs spring-couplet-prod-v参数将宿主机的./logs目录挂载到容器内的/app/logs这样日志就持久化保存在本地了。测试健康检查 打开浏览器或使用curl访问curl http://localhost:8080/health应该返回OK。测试正常流程 访问http://localhost:8501输入关键词生成春联。然后检查宿主机上的./logs目录应该能看到以日期命名的日志文件打开它可以看到类似这样的记录2025-02-10 14:30:25,123 - SpringCoupletApp - INFO - 乙巳马年春联生成终端启动 2025-02-10 14:30:45,456 - SpringCoupletApp - INFO - 收到生成请求关键词: 如意 2025-02-10 14:30:46,789 - SpringCoupletApp - INFO - 春联生成成功关键词 如意 - 上联: 龙马精神开锦绣 推理耗时: 1.33秒测试异常流程 尝试模拟一个错误例如在你的模型调用代码前加一句raise ValueError(模拟模型错误)然后再次生成。观察前端是否显示了友好的错误提示和备用春联日志文件中是否记录了ERROR级别的日志并包含了完整的错误堆栈信息5. 总结从“能用”到“可靠”通过以上步骤我们为“乙巳马年春联生成终端”完成了一次重要的生产化升级。我们来回顾一下核心成果有了“黑匣子”结构化的日志系统记录了应用的每一次“呼吸”和“心跳”无论是正常的用户请求还是突发的错误都有迹可循。./logs目录下的文件是你排查问题的第一手资料。穿上了“防弹衣”全局异常捕获机制确保了应用不会因为单个未处理的错误而彻底崩溃。即使AI模型暂时不可用用户也能收到一个体面的回应和一份备用的“祝福”体验不会戛然而止。装上了“健康仪表盘”/health端点就像是一个简单的生命体征监测仪让外部的运维系统能够快速判断服务是否存活为后续的自动重启、负载均衡提供了基础。这套监控机制的价值在于它让你从被动的“救火队员”用户投诉了才知道有问题转变为主动的“系统医生”通过日志提前发现潜在风险通过健康检查感知实时状态。当你的春联应用在春节高峰期迎接成千上万的用户时这份“可靠性”所带来的安心感与那扇“皇城大门”所带来的视觉震撼同样重要。现在你的“门神”不仅镇守在前端界面更在系统的深处默默守护着每一次“开门见喜”的仪式。你可以自信地将应用部署出去迎接属于它的马年鸿运了。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。

相关文章:

乙巳马年春联生成终端生产环境部署:日志监控与异常捕获机制

乙巳马年春联生成终端生产环境部署:日志监控与异常捕获机制 1. 引言:从创意演示到稳定服务 想象一下,你精心打造的“皇城大门春联生成终端”在年会上大放异彩,用户们争相输入愿望词,看着金色笔墨在朱红大门上瞬间凝结…...

Java Web 扶贫助农系统系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】

摘要 随着乡村振兴战略的深入推进,数字化技术在扶贫助农领域的应用日益广泛。传统的扶贫模式存在信息不对称、资源分配不均等问题,亟需通过信息化手段提升帮扶效率。基于此背景,设计并实现了一套基于Java Web的扶贫助农系统,旨在整…...

基于Magma的智能编程助手:代码生成与错误检测

基于Magma的智能编程助手:代码生成与错误检测 1. 引言 想象一下这样的场景:深夜加班时,你面对一个复杂的算法问题,手指在键盘上徘徊却不知从何下手。或者当你调试代码时,那个诡异的bug就像捉迷藏一样,明明…...

开源CAD处理新选择:LibreDWG深度技术解析与实践指南

开源CAD处理新选择:LibreDWG深度技术解析与实践指南 【免费下载链接】libredwg Official mirror of libredwg. With CI hooks and nightly releases. PRs ok 项目地址: https://gitcode.com/gh_mirrors/li/libredwg LibreDWG作为一款开源CAD文件处理库&#…...

ResNet101人脸检测实操手册:cv_resnet101_face-detection_cvpr22papermogface图像预处理参数调优

ResNet101人脸检测实操手册:cv_resnet101_face-detection_cvpr22papermogface图像预处理参数调优 1. 引言 你有没有遇到过这样的场景?从手机相册里翻出一张几年前的老照片,想做个电子相册,结果发现照片里人脸太小、角度太偏&…...

Wan2.2-T2V-A5B优化技巧:提升视频生成质量的几个小方法

Wan2.2-T2V-A5B优化技巧:提升视频生成质量的几个小方法 1. 模型简介与核心优势 Wan2.2-T2V-A5B是一款轻量级文本到视频生成模型,拥有50亿参数规模,专为快速内容创作而优化。相比同类大型视频生成模型,它的主要优势在于&#xff…...

Qwen3-ASR-0.6B应用实战:批量音频转文字,提升办公效率

Qwen3-ASR-0.6B应用实战:批量音频转文字,提升办公效率 1. 引言:语音识别如何改变办公场景 在日常办公中,会议记录、访谈整理、语音备忘录转文字等场景都需要大量时间进行人工转录。传统方法要么依赖专业速记员,要么使…...

欧姆龙CP系列PLC数据采集实战:Fins TCP协议详解与Python代码实现

欧姆龙CP系列PLC数据采集实战:Fins TCP协议详解与Python代码实现 在工业自动化领域,PLC(可编程逻辑控制器)作为核心控制设备,其数据采集能力直接影响着生产监控与决策效率。欧姆龙CP系列PLC凭借稳定可靠的性能&#xf…...

nlp_seqgpt-560m在软件测试中的应用:自动化测试用例生成

nlp_seqgpt-560m在软件测试中的应用:自动化测试用例生成 1. 引言 软件测试团队每天都要面对这样的困境:新功能上线前需要编写大量测试用例,手动编写既耗时又容易遗漏关键场景。一个中等规模的项目往往需要数百个测试用例,测试工…...

Qwen3-Reranker-0.6B在MobaXterm中的远程开发配置

Qwen3-Reranker-0.6B在MobaXterm中的远程开发配置 1. 引言 如果你正在开发AI应用,特别是文本重排序相关的项目,Qwen3-Reranker-0.6B是个不错的选择。这个模型专门用来优化搜索结果的相关性,让检索到的文档更符合你的查询需求。但问题来了&a…...

nlp_structbert_sentence-similarity_chinese-large 赋能运维智能化:日志信息聚类与根因分析

nlp_structbert_sentence-similarity_chinese-large 赋能运维智能化:日志信息聚类与根因分析 半夜三点,手机突然响起刺耳的报警声。你睡眼惺忪地打开电脑,屏幕上密密麻麻的日志像瀑布一样刷下来,几百条报警信息交织在一起&#x…...

StructBERT快速部署:开箱即用的中文句子相似度计算工具,支持多种场景

StructBERT快速部署:开箱即用的中文句子相似度计算工具,支持多种场景 1. 引言:你的智能文本理解助手,三分钟就能用起来 想象一下这个场景:你是一个电商平台的客服主管,每天要处理成千上万的用户咨询。用户…...

DAMOYOLO-S模型工作流可视化:ComfyUI节点式编程入门

DAMOYOLO-S模型工作流可视化:ComfyUI节点式编程入门 你是不是对目标检测模型感兴趣,但又觉得写代码、调参数太麻烦?或者想快速验证一个视觉AI想法,却被复杂的开发环境劝退?今天,我们就来聊聊一个能让你“拖…...

Linux下QtCreator编译动态库.so的5个常见坑及解决方案(附完整测试流程)

Linux下QtCreator编译动态库.so的5个常见坑及解决方案(附完整测试流程) 在Linux环境下使用QtCreator进行动态库开发时,新手开发者往往会遇到各种棘手的编译问题。这些问题看似简单,却可能耗费数小时甚至数天的调试时间。本文将深入…...

双路DC-DC降压模块:5V/3.3V嵌入式电源设计与实现

1. 项目概述DC-DC降压模块是一个面向嵌入式系统供电需求设计的双路稳压电源单元,核心目标是为微控制器、传感器、通信模块及外围数字电路提供稳定、低噪声、可复用的5V与3.3V直流电源。该模块不依赖单一输入源,支持多类型物理接口接入宽范围直流输入&…...

STC32G/STC8H双平台USB-HID无驱下载硬件设计

1. 项目概述本项目包含两个相互关联但功能定位明确的硬件模块:STC32G12K128转接板与STC8H8K64U最小核心板。二者共同构成面向8051生态演进的技术验证平台,服务于从传统8位学习向现代32位架构过渡的工程实践需求。设计目标并非简单替代旧有开发板&#xf…...

StructBERT 768维特征提取实操手册:批量文本向量化完整步骤

StructBERT 768维特征提取实操手册:批量文本向量化完整步骤 1. 引言:为什么需要专业的文本向量化工具? 如果你处理过中文文本数据,很可能遇到过这样的困扰:用通用的文本模型提取向量,发现“苹果手机”和“…...

基于ESP32-S2的桌面快捷控制中心硬件与协议设计

1. 项目概述“桌面快捷控制中心”是一个面向生产力场景的嵌入式人机交互终端,其核心设计目标是将高频操作从操作系统图形界面中解耦,通过物理按键本地显示的组合方式,实现零延迟、免切屏、单手可达的快捷任务触发。该系统并非传统意义上的遥控…...

Ostrakon-VL-8B入门指南:10分钟完成Python环境配置与首次调用

Ostrakon-VL-8B入门指南:10分钟完成Python环境配置与首次调用 你是不是也对那些能“看懂”图片的AI模型感到好奇?比如,给它一张美食照片,它就能告诉你这是什么菜,甚至还能分析出食材和做法。今天,我们就来…...

DeepChat开源镜像优势:为什么它比手动部署Ollama+Llama3更稳定、更省心、更安全

DeepChat开源镜像优势:为什么它比手动部署OllamaLlama3更稳定、更省心、更安全 你是否曾经尝试过手动部署一个本地大模型,比如Ollama配上Llama3,结果却陷入了一连串的麻烦?从环境配置冲突、模型下载失败,到端口被占用…...

FireRedASR-AED-L与微信小程序集成:语音输入功能实现

FireRedASR-AED-L与微信小程序集成:语音输入功能实现 1. 引言 想象一下这样的场景:用户在你的微信小程序里,不用打字,只需轻轻按住说话按钮,语音瞬间变成文字。这种流畅的语音输入体验,不仅提升了用户满意…...

STM32密码锁实战:Flash存储实现密码持久化与安全机制

1. STM32密码锁的核心需求与Flash存储优势 做密码锁最头疼的就是断电后密码丢失的问题。我之前用外部EEPROM芯片存密码,不仅占用I/O口,成本还高。后来发现STM32内部自带Flash闪存,简直就是为这种场景量身定制的解决方案。 为什么选择内部Flas…...

从C语言基础到AI模型调用:使用NLP-StructBERT的C接口实践

从C语言基础到AI模型调用:使用NLP-StructBERT的C接口实践 如果你是一位C语言开发者,习惯了与内存、指针和结构体打交道,看着现在AI应用遍地开花,是不是偶尔会想:这些用Python、PyTorch写起来很酷的模型,有…...

Zotero-Better-Notes表格编辑全攻略:从基础操作到效率提升

Zotero-Better-Notes表格编辑全攻略:从基础操作到效率提升 【免费下载链接】zotero-better-notes Everything about note management. All in Zotero. 项目地址: https://gitcode.com/gh_mirrors/zo/zotero-better-notes 在学术研究和知识管理过程中&#xf…...

数字IC后端设计中Post-mask ECO的Spare Cell优化策略与实践

1. 数字IC后端设计中的Post-mask ECO核心挑战 在芯片设计流程中,Post-mask ECO(Engineering Change Order)是让很多工程师头疼的关键环节。想象一下,当芯片已经完成tapeout进入制造阶段,突然发现某个逻辑功能需要调整—…...

STM32G474 HRTIM高精度定时器实战:实现互补PWM与死区控制

1. HRTIM高精度定时器为何成为电机控制利器 第一次接触STM32G474的HRTIM模块时,我被它的参数惊到了——184ps的时间分辨率意味着什么概念?这相当于在1秒钟内可以完成54亿次精确计时操作。相比之下,普通定时器的10ns分辨率就像用米尺测量头发丝…...

Wan2.1 VAE实战:Java后端服务集成与高并发调用优化

Wan2.1 VAE实战:Java后端服务集成与高并发调用优化 最近在帮一个电商平台做技术升级,他们想给商品详情页自动生成一些风格化的背景图,提升视觉吸引力。需求很明确:用户上传一张商品白底图,系统能快速生成多种风格的背…...

Alpamayo-R1-10B入门指南:理解Chain-of-Causation推理四阶段输出逻辑

Alpamayo-R1-10B入门指南:理解Chain-of-Causation推理四阶段输出逻辑 1. 项目简介:自动驾驶的“思考型大脑” 想象一下,你正在教一个新手司机开车。你不仅要告诉他“踩油门”、“打方向盘”,更重要的是要解释“为什么”要这么做…...

Log4j2配置实战:如何为SpringBoot项目定制高性能日志方案(附模板下载)

Log4j2配置实战:如何为SpringBoot项目定制高性能日志方案 在分布式系统与微服务架构盛行的当下,日志系统已从简单的调试工具演变为关键的业务监控组件。当QPS突破5000时,传统的同步日志写入可能直接拖慢系统响应速度30%以上。本文将深入剖析如…...

隐私党必备!用群晖NAS部署完全离线的Llama 2聊天机器人(2024最新Docker方案)

隐私守护者的终极方案:群晖NAS离线部署Llama 2聊天机器人全指南 在数据泄露事件频发的今天,越来越多的技术爱好者开始寻求完全掌控个人数据的解决方案。想象一下,一个无需连接任何云端服务器、所有对话内容仅存在于本地设备的AI助手——这正是…...