惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

爱范儿
爱范儿
P
Palo Alto Networks Blog
月光博客
月光博客
H
Hackread – Cybersecurity News, Data Breaches, AI and More
I
InfoQ
aimingoo的专栏
aimingoo的专栏
腾讯CDC
T
Threatpost
D
DataBreaches.Net
Vercel News
Vercel News
F
Fortinet All Blogs
Engineering at Meta
Engineering at Meta
C
Cybersecurity and Infrastructure Security Agency CISA
Forbes - Security
Forbes - Security
U
Unit 42
C
Check Point Blog
Blog — PlanetScale
Blog — PlanetScale
O
OpenAI News
量子位
TaoSecurity Blog
TaoSecurity Blog
Microsoft Azure Blog
Microsoft Azure Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
V
Visual Studio Blog
Recorded Future
Recorded Future
云风的 BLOG
云风的 BLOG
Security Archives - TechRepublic
Security Archives - TechRepublic
The Last Watchdog
The Last Watchdog
S
Security Affairs
Attack and Defense Labs
Attack and Defense Labs
罗磊的独立博客
Stack Overflow Blog
Stack Overflow Blog
Microsoft Security Blog
Microsoft Security Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
V
V2EX
小众软件
小众软件
S
SegmentFault 最新的问题
www.infosecurity-magazine.com
www.infosecurity-magazine.com
W
WeLiveSecurity
AI
AI
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园 - 聂微东
I
Intezer
Know Your Adversary
Know Your Adversary
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
P
Proofpoint News Feed
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The Cloudflare Blog
博客园_首页
NISL@THU
NISL@THU
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO

博客园 - ®Geovin Du Dream Park™

go: Functional Options Pattern go:Timing Functions Pattern python: Timing Functions Pattern go: Steady-State Pattern python: Steady-State Pattern go: Handshaking Pattern python: Handshaking Pattern go: Fail-Fast Pattern python: Fail-Fast Pattern I go: Deadline Pattern python: Deadline Pattern go: Circuit-Breaker Pattern python: Circuit-Breaker Pattern go: Bulkheads Pattern python: Bulkheads Pattern go: Push & Pull Pattern python: Push & Pull Pattern python: Publish/Subscribe Pattern II go: Publish/Subscribe Pattern python: Publish/Subscribe Pattern go: Futures & Promises Pattern python: Futures & Promises Pattern go:Pipeline Pattern python: Worker Pool Pattern python: Pipeline Pattern go: Fan-Out Pattern python: Fan-Out Pattern go: Fan-In Pattern python: Fan-In Pattern Fan-In go: Producer Consumer  Pattern python: Producer Consumer Pattern go: Parallelism Pattern python: Parallelism Pattern go: Reactor Pattern python: Reactor Pattern go: Generators Pattern python: speech to text offline python: Generators Pattern go: Coroutines Pattern python:Coroutines Pattern go: Broadcast Pattern python: Broadcast Pattern python: Bounded Parallelism Pattern go: Bounded Parallelism Pattern python: N-Barrier Pattern go: N-Barrier Pattern python: Semaphore Pattern go: Semaphore Pattern python: Read-Write Lock Pattern go: Read-Write Lock Pattern python: Monitor Pattern go: Monitor Pattern python: Mutex Pattern go: Lock/Mutex Pattern Python: Condition Variable Pattern go:Condition Variable Pattern python: Registry Pattern python: Interpreter Pattern go: Interpreter Pattern go: Registry Pattern go: Memento Pattern go: Command Pattern go: State Pattern go:Template Method Pattern go: Strategy Pattern go: Visitor Pattern go: Observer Pattern go: Mediator Pattern go: Iterator Pattern go: Chain of Responsibility Pattern go: Proxy Pattern go:Decorator Pattern go: Facade Pattern go: Flyweight Pattern go: Composite Pattern go: Singleton Pattern go: Prototype Pattern go: Bridge Pattern go: Adapter Pattern go: Builder Pattern 密码进行加盐哈希 using CSharp,Python,Go,Java go: Abstract Factory Pattern go: Model,Interface,DAL ,Factory,BLL using mysql go: Simple Factory Pattern go: Factory Method Pattern go: goLang 在Windows环境搭建Go语言开发环境 CSharp: Parallel Extensions cpp: class python: 蝴蝶跟随鼠标 javascript: 中国历史人物热力分布图using echart javascript: 中国历史人物热力图 python: 初养龙虾微信纯文字自动回复using workBuddy python: object 入门 python: Factory Method Pattern python: Simple Factory Pattern python: Abstract Factory Pattern 区域化 代码 python: Null Object Pattern python: Builder Pattern python: Adapter Pattern
go: Worker Pool Pattern
®Geovin Du Dream Park™ · 2026-06-21 · via 博客园 - ®Geovin Du Dream Park™
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Worker Pool Pattern 工作池模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 17:56
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : logger.go
*/
package utils

import (
	"godesginpattern/workerpool/config"
	"log"
	"os"
)

var Logger *log.Logger

func InitLogger() {
	Logger = log.New(os.Stdout, "", config.LogFlag)
}



/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Worker Pool Pattern 工作池模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 17:58
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : settings.go
*/
package config

import "log"

// 工作池并发
const WorkerCount = 3
const QueueMaxSize = 100

// 任务延迟
const MinTaskDelay = 0.3
const MaxTaskDelay = 0.8

// 日志标记
const LogFlag = log.LstdFlags


/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 18:01
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : task.go
*/
package tasks

import (
	"godesginpattern/workerpool/config"
	"math/rand"
	"time"
)

// RawMaterialCheck 原料质检
func RawMaterialCheck(orderID string) {
	simulateDelay()
}

// JewelryProcess 首饰加工
func JewelryProcess(orderID string) {
	simulateDelay()
}

// FinishedGoodsCheck 成品质检
func FinishedGoodsCheck(orderID string) {
	simulateDelay()
}

// InventoryRecord 库存录入ERP
func InventoryRecord(orderID string) {
	simulateDelay()
}

// OrderDelivery 订单物流发货
func OrderDelivery(orderID string) {
	simulateDelay()
}

// FullProcessTasks 任务链
var FullProcessTasks = []func(string){
	RawMaterialCheck,
	JewelryProcess,
	FinishedGoodsCheck,
	InventoryRecord,
	OrderDelivery,
}

// 模拟延迟
func simulateDelay() {
	rand.Seed(time.Now().UnixNano())
	delay := config.MinTaskDelay + rand.Float64()*(config.MaxTaskDelay-config.MinTaskDelay)
	time.Sleep(time.Duration(delay*1000) * time.Millisecond)
}



/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 18:01
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : worker_pool.go
*/
package core

import (
	"godesginpattern/workerpool/utils"
	"sync"
)

// Task 任务结构体
type Task struct {
	OrderID string
	Func    func(string)
}

// WorkerPool 工作池
type WorkerPool struct {
	workerCount int
	taskChan    chan *Task
	wg          sync.WaitGroup
}

// NewWorkerPool 创建工作池
func NewWorkerPool(workerCnt int, queueSize int) *WorkerPool {
	return &WorkerPool{
		workerCount: workerCnt,
		taskChan:    make(chan *Task, queueSize),
	}
}

// worker 工作协程
func (wp *WorkerPool) worker(id int) {
	utils.Logger.Printf("Worker %d started, waiting task", id)
	for task := range wp.taskChan {
		utils.Logger.Printf("Worker %d start task: %s", id, task.OrderID)
		task.Func(task.OrderID)
		utils.Logger.Printf("Worker %d finish task: %s", id, task.OrderID)
		wp.wg.Done()
	}
}

// Start 启动所有 worker
func (wp *WorkerPool) Start() {
	for i := 1; i <= wp.workerCount; i++ {
		go wp.worker(i)
	}
}

// Submit 提交任务
func (wp *WorkerPool) Submit(task *Task) {
	wp.wg.Add(1)
	wp.taskChan <- task
}

// Wait 等待全部完成
func (wp *WorkerPool) Wait() {
	wp.wg.Wait()
	close(wp.taskChan)
}

调用:

/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 18:02
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : workerpoolbll.go
*/
package bll

import (
	"fmt"
	"godesginpattern/workerpool/config"
	"godesginpattern/workerpool/core"
	"godesginpattern/workerpool/tasks"
	"godesginpattern/workerpool/utils"
)

func WorkerPoolMain() {
	// 初始化日志
	utils.InitLogger()
	logger := utils.Logger

	logger.Println("================================================")
	logger.Println("Jewelry Production System Start (Go Worker Pool)")
	logger.Println("================================================")

	// 初始化工作池
	pool := core.NewWorkerPool(config.WorkerCount, config.QueueMaxSize)
	pool.Start()

	// 批量创建10个珠宝订单
	totalOrder := 10
	logger.Printf("Start submit total %d jewelry orders", totalOrder)

	for orderNo := 1; orderNo <= totalOrder; orderNo++ {
		orderID := fmt.Sprintf("订单-%03d", orderNo)
		// 一个订单执行完整5道工序
		for _, taskFunc := range tasks.FullProcessTasks {
			task := &core.Task{
				OrderID: orderID,
				Func:    taskFunc,
			}
			pool.Submit(task)
		}
	}

	// 等待所有任务处理完毕
	pool.Wait()
	logger.Println("All jewelry order tasks completed")
}

项目结构:

image

/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Worker Pool Pattern 工作池模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 17:56
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : logger.go
*/
package utils

import (
	"godesginpattern/workerpool/config"
	"io"
	"log"
	"os"
)

var Logger *log.Logger

func InitLogger() {
	// 打开日志文件
	file, err := os.OpenFile(config.LogFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		log.Fatal("日志文件创建失败:", err)
	}

	// 同时输出到:控制台 + 文件
	multiWriter := io.MultiWriter(os.Stdout, file)

	// 初始化日志
	Logger = log.New(multiWriter, "", config.LogFlag)
}




/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Worker Pool Pattern 工作池模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 18:12
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : retry.go
*/
package utils

import (
	"godesginpattern/workerpool/config"
	"time"
)

// Retry 执行函数并自动重试
func Retry(task func() error) error {
	var err error
	for i := 0; i < config.MaxRetryTimes; i++ {
		err = task()
		if err == nil {
			return nil
		}
		Logger.Printf("任务失败,第 %d 次重试,错误: %v", i+1, err)
		time.Sleep(500 * time.Millisecond)
	}
	return err
}



/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Worker Pool Pattern 工作池模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 18:12
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : monitor.go
*/
package utils

import "sync/atomic"

type Monitor struct {
	Running  int64
	Waiting  int64
	Finished int64
	Failed   int64
}

func (m *Monitor) IncRunning()  { atomic.AddInt64(&m.Running, 1) }
func (m *Monitor) DecRunning()  { atomic.AddInt64(&m.Running, -1) }
func (m *Monitor) IncWaiting()  { atomic.AddInt64(&m.Waiting, 1) }
func (m *Monitor) DecWaiting()  { atomic.AddInt64(&m.Waiting, -1) }
func (m *Monitor) IncFinished() { atomic.AddInt64(&m.Finished, 1) }
func (m *Monitor) IncFailed()   { atomic.AddInt64(&m.Failed, 1) }

func (m *Monitor) Get() (running, waiting, finished, failed int64) {
	return atomic.LoadInt64(&m.Running),
		atomic.LoadInt64(&m.Waiting),
		atomic.LoadInt64(&m.Finished),
		atomic.LoadInt64(&m.Failed)
}


/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Worker Pool Pattern 工作池模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 17:58
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : settings.go
*/
package config

import "log"

const (
	WorkerCount     = 3
	QueueMaxSize    = 100
	MinTaskDelay    = 0.3
	MaxTaskDelay    = 0.8
	MaxRetryTimes   = 3
	LogFileName     = "jewelry.log"
	DBPath          = "jewelry.db"
	HTTPPort        = ":8080"
	MonitorInterval = 2
)

const LogFlag = log.LstdFlags | log.Lmicroseconds



/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Worker Pool Pattern 工作池模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 18:01
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : task.go
*/
package tasks

import (
	"godesginpattern/workerpool/config"
	"math/rand"
	"time"
)

func RawMaterialCheck(orderID string) error {
	simulateDelay()
	return nil
}

func JewelryProcess(orderID string) error {
	simulateDelay()
	return nil
}

func FinishedGoodsCheck(orderID string) error {
	simulateDelay()
	return nil
}

func InventoryRecord(orderID string) error {
	simulateDelay()
	return nil
}

func OrderDelivery(orderID string) error {
	simulateDelay()
	return nil
}

var FullProcessTasks = []func(string) error{
	RawMaterialCheck,
	JewelryProcess,
	FinishedGoodsCheck,
	InventoryRecord,
	OrderDelivery,
}

func simulateDelay() {
	rand.Seed(time.Now().UnixNano())
	delay := config.MinTaskDelay + rand.Float64()*(config.MaxTaskDelay-config.MinTaskDelay)
	time.Sleep(time.Duration(delay*1000) * time.Millisecond)
}



/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Worker Pool Pattern 工作池模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 18:01
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : worker_pool.go
*/
package core

import (
	"godesginpattern/workerpool/config"
	"godesginpattern/workerpool/utils"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

type Task struct {
	OrderID string
	Func    func(string) error
}

type WorkerPool struct {
	workerCount int
	taskChan    chan *Task
	wg          sync.WaitGroup
	monitor     *utils.Monitor
	quit        chan os.Signal
}

func NewWorkerPool(workerCnt int, queueSize int) *WorkerPool {
	wp := &WorkerPool{
		workerCount: workerCnt,
		taskChan:    make(chan *Task, queueSize),
		monitor:     &utils.Monitor{},
		quit:        make(chan os.Signal, 1),
	}
	signal.Notify(wp.quit, syscall.SIGINT, syscall.SIGTERM)
	return wp
}

func (wp *WorkerPool) worker(id int) {
	utils.Logger.Printf("Worker %d 已启动", id)
	for {
		select {
		case task, ok := <-wp.taskChan:
			if !ok {
				utils.Logger.Printf("Worker %d 安全退出", id)
				return
			}

			wp.monitor.DecWaiting()
			wp.monitor.IncRunning()

			utils.Logger.Printf("Worker %d 开始任务: %s", id, task.OrderID)
			err := utils.Retry(func() error {
				return task.Func(task.OrderID)
			})

			if err != nil {
				utils.Logger.Printf("Worker %d 任务失败: %s, 错误: %v", id, task.OrderID, err)
			} else {
				utils.Logger.Printf("Worker %d 完成任务: %s", id, task.OrderID)
			}

			wp.monitor.DecRunning()
			wp.monitor.IncFinished()
			wp.wg.Done()

		case <-wp.quit:
			utils.Logger.Printf("Worker %d 收到关闭信号,退出", id)
			return
		}
	}
}

func (wp *WorkerPool) Start() {
	utils.Logger.Println("工作池启动")
	for i := 1; i <= wp.workerCount; i++ {
		go wp.worker(i)
	}
	go wp.monitorLoop()
}

func (wp *WorkerPool) Submit(task *Task) {
	wp.wg.Add(1)
	wp.monitor.IncWaiting()
	wp.taskChan <- task
}

func (wp *WorkerPool) monitorLoop() {
	ticker := time.NewTicker(time.Duration(config.MonitorInterval) * time.Second)
	defer ticker.Stop()
	for {
		select {
		case <-ticker.C:
			r, w, f, failed := wp.monitor.Get()
			utils.Logger.Printf("[监控] 运行:%d | 等待:%d | 完成:%d | 失败:%d", r, w, f, failed)
			// 运行、等待都为0,代表所有任务全部完成
			if r == 0 && w == 0 {
				utils.Logger.Println("所有任务处理完成,自动停止监控输出")
				return
			}
		case <-wp.quit:
			utils.Logger.Println("监控循环收到关闭信号,停止监控输出")
			return
		}
	}
}

func (wp *WorkerPool) Wait() {
	// 阻塞等待 Ctrl+C / kill 信号
	<-wp.quit
	utils.Logger.Println("优雅关闭中...")
	// 关闭任务通道,worker 不再接收新任务
	close(wp.taskChan)
	// 等待正在执行的任务全部处理完毕
	wp.wg.Wait()
	utils.Logger.Println("✅ 所有任务执行完毕,服务安全退出")
}



调用:

/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Worker Pool Pattern 工作池模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 18:02
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : workerpoolbll.go
*/
package bll

import (
	"fmt"
	"godesginpattern/workerpool/config"
	"godesginpattern/workerpool/core"
	"godesginpattern/workerpool/tasks"
	"godesginpattern/workerpool/utils"
)

func WorkerPoolMain() {
	utils.InitLogger()
	logger := utils.Logger

	logger.Println("================================================")
	logger.Println("   珠宝企业级生产系统(Go 企业级 Worker Pool)")
	logger.Println("================================================")

	pool := core.NewWorkerPool(config.WorkerCount, config.QueueMaxSize)
	pool.Start()

	totalOrder := 10
	logger.Printf("开始提交 %d 个珠宝订单\n", totalOrder)

	for i := 1; i <= totalOrder; i++ {
		orderID := fmt.Sprintf("订单-%03d", i)
		for _, fn := range tasks.FullProcessTasks {
			pool.Submit(&core.Task{
				OrderID: orderID,
				Func:    fn,
			})
		}
	}

	logger.Println("✅ 所有订单已提交,按 Ctrl+C 优雅关闭")
	pool.Wait()
}

输出:

image

哲学管理(学)人生, 文学艺术生活, 自动(计算机学)物理(学)工作, 生物(学)化学逆境, 历史(学)测绘(学)时间, 经济(学)数学金钱(理财), 心理(学)医学情绪, 诗词美容情感, 美学建筑(学)家园, 解构建构(分析)整合学习, 智商情商(IQ、EQ)运筹(学)生存.---Geovin Du(涂聚文)