【Eureka】Eureka 介绍与实战
1. Eureka 简介
Eureka 是 Netflix 开发的一个服务注册和发现组件,主要用于微服务架构中。它的核心功能是帮助微服务之间进行通讯和管理,使得服务能够动态地发现彼此,实现灵活的服务调用和负载均衡。
1.1 核心概念
- 服务注册中心(Eureka Server):这是一个中央注册中心,所有微服务实例都会将自己的信息注册到这个中心,并定期发送心跳来维持其租约。
- 服务提供者(Service Provider):提供服务的应用,在启动时向 Eureka Server 注册自己,并定期续租。可以是 SpringBoot 应用或其他技术实现,只要对外提供的是Rest风格服务即可。
- 服务消费者(Service Consumer):使用服务的应用,通过 Eureka Server 查找可用的服务实例。消费应用从注册中心获取服务列表,从而得知每个服务方的信息,知道去哪里调用服务方。
1.2 工作流程
- 服务注册:服务实例启动时,会向 Eureka Server 注册自己的信息,包括服务名、IP地址、端口号等。
- 服务续租:服务实例定期(默认30秒)向 Eureka Server 发送心跳,以续租其租约。
- 服务注销:服务实例关闭时,会向 Eureka Server 发送注销请求。Eureka Server将此实例从注册列表中移除。
- 获取服务列表:服务消费者会从 Eureka Server 获取服务列表,并根据负载均衡策略选择一个服务实例进行调用。
1.3 高可用
Eureka Server 支持集群部署,多个 Eureka Server 实例相互注册,形成高可用的服务注册中心。
1.4 主要特点
- 开源:Eureka 是开源的,可以免费使用和修改。
- 可靠性:具有内置的容错机制,能够在服务器崩溃时保持可用。
- 动态性:服务实例可以动态地注册和注销,适应服务的动态变化。
- 易于集成:可以轻松地与 Spring Cloud 等框架集成。
- 基于 RESTful:使用 RESTful API,可以与其他基于 HTTP 的服务轻松集成。
通过使用 Eureka,可以实现以下功能: - 服务注册:每个微服务实例在启动时会自动将自己的信息注册到 Eureka Server。
- 服务发现:服务可以通过 Eureka Client 查询 Eureka Server 来获取可用服务的列表。
- 负载均衡:Eureka Client 提供了简单的轮询负载均衡策略。
- 故障转移:如果某个服务实例出现故障,Eureka Client 会自动检测并从服务列表中移除这个实例。
Eureka 是一个强大而可靠的服务注册与发现工具,适用于云原生应用和微服务架构,能够提高系统的可用性和可伸缩性。
2. Eureka 故障处理
处理服务实例故障通常涉及以下几个步骤:
- 健康检查:
- 服务端检查:服务实例应定期向服务注册中心(如Eureka Server)发送心跳,表明自己处于健康状态。如果服务实例无法在预定时间内发送心跳,注册中心可能会将其标记为不健康或已下线。
- 客户端检查:客户端在调用服务之前,可以执行健康检查,以确认服务实例是否可用。
- 故障检测:
- 超时检测:客户端在尝试与服务实例通信时,如果发生超时,可以认为服务实例可能出现了故障。
- 异常检测:服务实例在处理请求时,如果抛出异常,可以根据异常类型和频率来判断服务是否出现故障。
- 服务下线:
- 当服务实例被检测到故障时,应该从服务注册中心下线,以避免其他客户端继续尝试调用这个故障实例。
- 重试机制:
- 客户端在调用服务时,如果遇到故障,可以实施重试机制,尝试其他服务实例。
- 负载均衡:
- 当某个服务实例故障时,负载均衡器应该能够检测到这一点,并停止向这个实例发送请求,而是将请求分发到其他健康的实例。
- 熔断机制:
- 当服务实例持续故障,可以启用熔断机制,暂时停止对故障服务的调用,防止系统雪崩。
- 故障通知:
- 系统应具备故障通知机制,当服务实例出现故障时,及时通知运维人员。
- 自动恢复:
- 对于可以自动恢复的故障(如临时网络问题),系统应能在问题解决后自动重新注册服务实例。
- 日志记录和监控:
- 记录详细的日志信息,以便分析故障原因。
- 通过监控系统实时监控服务状态,一旦发现异常立即采取措施。
- 人工干预:
- 对于无法自动恢复的故障,需要人工介入进行问题排查和修复。
在微服务架构中,服务注册与发现组件(如Eureka)通常会提供上述大部分功能,以帮助自动处理服务实例的故障。通过这些机制,可以大大提高系统的稳定性和可用性。
3. Eureka 三种负载均衡策略
3.1 默认负载均衡策略
Eureka 与 Ribbon 结合使用时,Ribbon作为客户端负载均衡器,确实有一个默认的负载均衡策略。默认情况下,Ribbon 使用的是RoundRobinRule策略,这是一种简单的轮询策略,它会按照顺序逐一将请求分配到各个服务实例上。
这意味着如果你没有在配置文件中显式指定负载均衡策略,Ribbon 将默认使用RoundRobinRule。这种策略在大多数情况下都能提供基本的负载均衡功能,确保请求在各个服务实例之间均匀分布。
如果你想要查看或修改默认的负载均衡策略,可以在 Spring Cloud 应用的配置文件(application.properties或application.yml)中进行设置。例如,下面是如何在application.yml中显式设置默认轮询策略的示例:
ribbon:eureka:enabled: trueNFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
尽管这里显式设置了默认策略,实际上即使不设置,Ribbon 也会默认使用RoundRobinRule。如果你想要使用其他策略,只需要将NFLoadBalancerRuleClassName的值改为其他策略的实现类即可。
3.2 随机负载均衡策略
要设置 Ribbon 的随机负载均衡策略,你需要修改 Spring Cloud 应用的配置文件,指定使用RandomRule类作为负载均衡规则。以下是具体的步骤和示例:
-
添加Ribbon依赖:
确保你的 Spring Boot 项目已经包含了 Spring Cloud Ribbon 的依赖。在pom.xml或build.gradle文件中,你应该看到如下依赖:Maven示例:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> -
配置Ribbon:
在你的应用配置文件(通常是application.properties或application.yml)中,设置NFLoadBalancerRuleClassName属性为com.netflix.loadbalancer.RandomRule。application.yml配置示例:ribbon:eureka:enabled: true # 确保Eureka用于服务发现NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 设置随机负载均衡策略如果你使用的是
application.properties格式,配置将如下所示:ribbon.eureka.enabled=true ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule -
重启应用:
修改配置后,你需要重启你的Spring Boot应用,以便新的配置生效。
使用RandomRule后,Ribbon 将随机选择服务实例来处理请求,而不是按照轮询或其他规则。这适用于当你想要在服务实例之间实现真正的随机分布请求时。
Warning: 如果你在使用 Spring Cloud Finchley 或更高版本,Ribbon 已经被重新设计为通过 Spring Cloud Commons 中的LoadBalancerClient接口工作,此时配置方式可能会有所不同。在这种情况下,你可能需要使用@LoadBalanced注解来创建一个RestTemplate或WebClient,并使用相应的负载均衡策略。
3.3 自定义负载均衡策略
在 Spring Cloud 中,Eureka 通常与 Ribbon 结合使用来实现客户端的负载均衡。Ribbon 是一个客户端负载均衡器,它可以与 Eureka 配合工作,根据 Eureka 中注册的服务列表来选择调用的服务实例。以下是如何配置 Eureka 的负载均衡策略的基本步骤:
-
添加依赖:
在你的Spring Boot应用的pom.xml或build.gradle文件中,确保你已经添加了Spring Cloud Eureka和Spring Cloud Ribbon的依赖。Maven示例:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> -
配置Ribbon:
在你的应用配置文件(如application.properties或application.yml)中,你可以设置Ribbon的负载均衡策略。示例配置:
# application.yml ribbon:eureka:enabled: true # 启用Eureka来获取服务列表NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule # 负载均衡策略这里
NFLoadBalancerRuleClassName是配置负载均衡规则的关键。以下是一些常用的负载均衡规则:com.netflix.loadbalancer.RoundRobinRule:轮询策略,默认策略。com.netflix.loadbalancer.RandomRule:随机策略。com.netflix.loadbalancer.AvailabilityFilteringRule:会过滤掉故障实例和那些高并发连接的实例。com.netflix.loadbalancer.WeightResponseTimeRule:根据响应时间加权选择服务器。com.netflix.loadbalancer.BestAvailableRule:选择并发请求最小的服务器。
-
自定义负载均衡策略:
如果你需要自定义负载均衡策略,可以创建一个类实现IRule接口,然后配置你的应用使用这个类。示例代码:
public class MyCustomRule extends AbstractLoadBalancerRule {@Overridepublic Server choose(Object key) {// 自定义选择逻辑return null;}@Overridepublic void initWithNiwsConfig(IClientConfig clientConfig) {// 初始化配置} }然后在配置文件中指定你的自定义规则:
ribbon:NFLoadBalancerRuleClassName: com.example.MyCustomRule
通过以上步骤,你可以配置和自定义 Eureka 客户端的负载均衡策略,以适应特定需求。
4. Eureka 实践
下面将展示如何使用Eureka搭建一个简单的服务注册与发现环境。
1. 创建 Eureka Server
使用 Spring Initializr 创建一个 Spring Boot 项目,并添加 Eureka Server 依赖。
<!-- pom.xml -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
在主类上添加@EnableEurekaServer注解。
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication.class, args);}
}
配置文件中设置 Eureka Server 的端口和其他属性。
# application.yml
server:port: 8761
eureka:instance:hostname: localhostclient:registerWithEureka: falsefetchRegistry: falseserviceUrl:defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
2. 创建服务提供者
创建另一个 Spring Boot 项目,并添加 Eureka Client 依赖。
<!-- pom.xml -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
在主类上添加@EnableDiscoveryClient注解。
@SpringBootApplication
@EnableDiscoveryClient
public class ServiceProviderApplication {public static void main(String[] args) {SpringApplication.run(ServiceProviderApplication.class, args);}
}
配置文件中指定 Eureka Server 的地址。
# application.yml
spring:application:name: service-provider
server:port: 8080
eureka:client:serviceUrl:defaultZone: http://localhost:8761/eureka/
3. 创建服务消费者
创建另一个 Spring Boot 项目,添加 Eureka Client 和 Web依赖。
<!-- pom.xml -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
在主类上添加@EnableDiscoveryClient注解,并创建一个 REST 控制器。
@SpringBootApplication
@EnableDiscoveryClient
public class ServiceConsumerApplication {public static void main(String[] args) {SpringApplication.run(ServiceConsumerApplication.class, args);}
}
@RestController
public class ConsumerController {@Autowiredprivate RestTemplate restTemplate;@GetMapping("/greeting")public String getGreeting() {// 假设服务提供者有一个/greeting的端点return restTemplate.getForObject("http://service-provider/greeting", String.class);}
}
配置文件中指定 Eureka Server 的地址。
# application.yml
spring:application:name: service-consumer
server:port: 8081
eureka:client:serviceUrl:defaultZone: http://localhost:8761/eureka/
确保在ConsumerController中注入了RestTemplate,并在其上添加了@LoadBalanced注解,以启用负载均衡功能。
@Bean
@LoadBalanced
public RestTemplate restTemplate() {return new RestTemplate();
}
4. 启动服务
按照以下顺序启动服务:
- 启动Eureka Server:运行
EurekaServerApplication的主类。 - 启动服务提供者:运行
ServiceProviderApplication的主类,并确保它成功注册到 Eureka Server。 - 启动服务消费者:运行
ServiceConsumerApplication的主类。
5. 测试服务发现和调用
一旦所有服务都启动并运行,你可以测试服务消费者是否能够发现服务提供者并调用其 API。
- 打开浏览器,访问 Eureka Server 的仪表板:
http://localhost:8761/。你应该能看到注册的服务列表,包括SERVICE-PROVIDER和SERVICE-CONSUMER。 - 访问服务消费者的端点:
http://localhost:8081/greeting。如果一切配置正确,你应该会看到服务提供者返回的响应。
6. 注意事项
- 心跳续租:服务提供者必须定期发送心跳来续租其在 Eureka Server 上的租约。如果 Eureka Server 在
90秒内没有接收到服务提供者的心跳,它会将该实例从其注册列表中移除。 - 自我保护模式:在特定情况下,Eureka Server 可能会进入自我保护模式,这会阻止它注销那些没有发送心跳的服务实例。这是为了在网络分区或服务中断期间保持系统的稳定性。
- 实例元数据:服务实例可以在注册时提供额外的元数据,这些元数据可以在服务发现时被消费者使用。
通过上述步骤,我们进行了 Eureka 的基本使用,并了解了它在微服务架构中的作用。Eureka 使得服务之间的发现和调用变得更加灵活和可靠,是构建分布式系统的重要组件之一。
相关文章:
【Eureka】Eureka 介绍与实战
1. Eureka 简介 Eureka 是 Netflix 开发的一个服务注册和发现组件,主要用于微服务架构中。它的核心功能是帮助微服务之间进行通讯和管理,使得服务能够动态地发现彼此,实现灵活的服务调用和负载均衡。 1.1 核心概念 服务注册中心࿰…...
密码管理系统的自动化与集成:重塑安全与效率的双重飞跃
在数字化时代,密码作为保护个人信息、企业资产及敏感数据的第一道防线,其重要性不言而喻。然而,随着网络应用的激增和复杂性的提升,传统的密码管理方式——如使用简单密码、重复密码或依赖记忆——已难以满足现代安全需求…...
Outlook如何精确搜索邮件?
Outlook如何精确搜索邮件? 参考链接:https://jingyan.baidu.com/article/e75aca853148ba552edac6b6.html 我们在使用Outlook搜索功能时,直接输入关键词的话,会出来很多不相关的内容,那么有没有办法让搜索时更加精确呢…...
MambaCSR: 使用SSM的双交错扫描压缩图像超分辨率
MambaCSR: Dual-Interleaved Scanning for Compressed Image Super-Resolution With SSMs 2408.11758 (arxiv.org) GitHub - renyulin-f/MambaCSR: The code source of MambaCSR 摘要 本文提出了MambaCSR,这是一个基于Mamba的简单但有效的框架,用于解决…...
【C++】深入解析C/C++内存管理:new与delete的使用及原理
C语法相关知识点可以通过点击以下链接进行学习一起加油!命名空间缺省参数与函数重载C相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类 本章将分享C为何放弃malloc/free系列,选择新系列new/delete去管理内存。深度探索new/delete的使用及其原理,m…...
递归--数据结构--黑马
递归 总结一句话,上手直接多刷Leetcode,比看这个更有用。 定义 递归是一种解决计算问题的方法,其中解决方案取决于同一类问题的更小子集。 例如,单链表递归遍历的例子: void f(Node node) {if (node null) {retu…...
【3.1】贪心算法-解分发饼干
一、题目 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是, 每个孩子最多只能给一块饼干 。 对每个孩子i,都有一个 胃口值 g[i] ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干j,都有一个…...
解决 Error running ‘Application‘: Command line is too long.
一、项目场景: 运行刚拉取下来的项目代码,出现下面问题描述的错误提示。 二、问题描述 Error running Application: Command line is too long. Shorten command line for Application or also for Spring Boot default configuration? 翻译翻译&…...
衡量与归因将是Netflix程序化广告业务的首要任务
作者:刀客doc 8月20日,Netflix宣布今年上半年,品牌的招商收入同比增长了150%,广告主来自旅游、汽车、零售商、快餐和大众快消等行业。这一消息提振了资本市场对Netflix广告业务的信心,8月20日收盘创下每股 698.54 美元…...
关于如何在已有qt项目中添加该项目的单元测试工程
关于如何在已有qt项目中添加该项目的单元测试工程 新建一个子目录工程,把已有项目作为子工程添加进去,然后新建单元测试工程也作为子工程添加进去。单元测试项目要独立于实际项目工程,确保去掉测试项目后,实际项目仍可以正常运行…...
深度剖析数字媒体产业链的无限潜力与创新生态
在当今信息爆炸的时代,数字媒体产业链正以势不可挡的姿态展现出其令人瞩目的无限潜力与创新生态。 数字媒体的发展潜力简直无可限量。从在线视频的爆发式增长,到虚拟现实和增强现实技术带来的沉浸式体验,再到社交媒体平台上丰富多彩的内容创…...
集团数字化转型方案(十二)
集团数字化转型方案致力于通过构建一个集成化的数字平台,全面应用大数据分析、人工智能、云计算和物联网等前沿技术,推动业务流程、管理模式和决策机制的全面升级。该方案将从业务流程的数字化改造开始,优化资源配置,提升运营效率…...
Andrid异步更新UI:Handler(二)深入了解:Message你真的会创建?它是如何子线程和主线程通知?
目录 为什么会有HandlerHandler的原理,以及对象讲解主线程的loop在哪里,为什么主线程loop没有阻塞呢?Looper如何保证唯一Handler为什么会引发内存泄漏呢?Message应该如何创建它? 一、为什么会有Handler 线程分为主线…...
2025计算机毕设50条小众好做的Java题目【计算机毕设选题推荐】
随着2025年的到来,计算机专业的学生们又迎来了毕业设计的关键时刻。对于大多数学生来说,选择一个合适的毕业设计题目往往是一项艰巨的任务。本文旨在为那些正在为毕业设计题目烦恼的同学们提供一些灵感和建议,特别是针对使用Java技术栈的同学…...
day06_算法训练
一. Stream流 1.1 Stream流概述 概念: jdk1.8以后提供的新的API, 主要用于批量操作数据(集合的另外一种操作方式),代码非常简洁 流式处理思想: 2.2 Stream对象获取 1.单列集合的Stream流对象获取 2.双列集合的Stream流对象获取 3.数组的Stream流对象获取 4.散装数据的St…...
@SpringBootTest单元测试中报错:无法自动装配,找不到 ‘XXX‘ 类型的 Bean
一开始照着网上教程讲Springboot原理中的代码来copy写的↓ import com.google.gson.Gson; import com.itheima.pojo.Result; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.cont…...
nodemon学习(一)简介、安装、配置、使用
nodemon用来监视node.js应用程序中的任何更改并自动重启服务,非常适合用在开发环境中。以前,我们开发一个node后端服务时,每次更改文件,均需重启一下,服务才能生效。这使我们的开发效率降低了很多。nodemon的出现,可以…...
【Qt从摄像头视频中获取数据】
有时候需要在视频上画图,所以需要能获取到每一帧视频数据。 以前从视频文件或视频流中得到帧,一般都是使用qt ffmpeg或qt vlc。 qt对显示处理视频大体有以下方法: QMediaPlayer QVideoWidget 这种方法只适合简单的显示视频功能ÿ…...
视频截取中的UI小组件
引言 视频截取在社交类 APP 中十分常见。有了上传视频的功能,就不可避免地需要提供截取和编辑的选项。如果我们过度依赖第三方库,项目的代码可能会变得异常臃肿,因为这些库往往包含许多我们用不到的功能,而且它们的 UI 样式和功能…...
java设计模式--结构型模式
结构性模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式 适配器模式 适配器模式(Adapter Pattern) 充当两个不兼容接口之间的桥梁,属于结构型设计模式。目的是将一个类的接口转换为另一个接口&am…...
开源大模型Phi-4-mini-reasoning横向评测:性能、成本与易用性深度分析
开源大模型Phi-4-mini-reasoning横向评测:性能、成本与易用性深度分析 1. 评测背景与模型概览 在开源大模型生态快速发展的当下,Phi-4-mini-reasoning作为一款轻量级推理模型引起了开发者社区的广泛关注。这款由微软研究院开源的模型,定位在…...
Qwen3-0.6B-FP8功能测评:思维模式切换,让对话更智能
Qwen3-0.6B-FP8功能测评:思维模式切换,让对话更智能 你是否遇到过这样的场景:想让AI帮你解决一个复杂的数学题,它却用闲聊的语气跟你兜圈子;或者只是想简单聊聊天,它却开始长篇大论地推理分析?…...
别再只会画零件了!用SolidWorks装配体做设计,这5个实战技巧让你效率翻倍
别再只会画零件了!用SolidWorks装配体做设计,这5个实战技巧让你效率翻倍 刚接触SolidWorks时,我们总把精力放在如何把单个零件画得又快又好。但随着项目复杂度提升,你会发现真正的挑战在于如何让几十甚至上百个零件完美配合。我曾…...
RobotDuLAB:面向K-12教育的Arduino机器人教学库设计
1. RobotDuLAB Arduino库:面向教育场景的嵌入式机器人控制抽象层设计与工程实践1.1 教育型开源机器人的系统定位与硬件架构RobotDuLAB并非通用工业机器人平台,而是一个专为K-12阶段编程教学深度定制的开源教育机器人系统。其核心设计理念是“可理解性优先…...
穿戴式设备:生理信号采集与健康状态分析
**穿戴式设备:生理信号采集与健康状态分析** 在科技飞速发展的今天,穿戴式设备已成为健康管理的重要工具。它们通过实时采集心率、血氧、体温等生理信号,结合智能算法分析用户的健康状态,为疾病预防和健康干预提供科学依据。无论…...
IotNetESP32:面向i-ot.net平台的嵌入式物联网连接抽象库
1. 项目概述IotNetESP32 是一款专为 ESP32 平台设计的嵌入式物联网通信中间件库,其核心定位并非替代底层协议栈,而是构建在 ESP-IDF 或 Arduino-ESP32 框架之上、面向应用层的“连接抽象层”。该库通过封装 WiFi 管理、MQTT 客户端、HTTP 客户端三大基础…...
pytest.ini 中 addopts 详解 多插件配置方法
addopts = --html=report.html --self-contained-html 一、addopts 到底是什么? addopts 是 pytest.ini 配置文件中 [pytest] 节下的核心配置项,全称是 additional options(附加选项)。它的作用是:把你每次执行 pytest 命令时都要手动加的命令行参数,永久写在配置文件里…...
Leaflet结合天地图实现动态主题切换与个性化地图定制
1. 理解Leaflet与天地图的角色定位 Leaflet作为轻量级开源地图库,就像一张可以自由绘画的透明画布。我在实际项目中发现,它最强大的能力在于提供地图交互骨架——缩放、拖拽、标记等基础功能全部开箱即用。而天地图则像是专门为中国地区优化的彩色颜料&a…...
JBoltAI框架4.2发布!八大核心升级重塑AI开发全场景
深耕AI开发领域,聚焦开发者实际需求,JBoltAI框架持续迭代优化。今日,我们正式宣布JBoltAI框架升级至V4.2版本,带来9大核心功能升级,覆盖语音交互、文件处理、文档生成、知识库优化等全场景,进一步降低AI应用…...
模型不是壁垒,Harness 也不是
文章目录前言一、先从那个" accidents "说起吧二、Harness 到底是个啥?别被唬住了三、OpenAI 和 Google 早就跟上了四、源码泄漏后我发现了啥秘密五、真正的壁垒到底在哪儿?六、我实际用起来是啥感受七、给开发者的一些大实话八、这事儿还没完…...
