外观
Oracle 网络服务配置
监听器配置
监听器基础
监听器功能
- 监听客户端连接请求
- 管理服务器进程(专用服务器模式)
- 转发连接请求到数据库实例
- 提供连接状态信息
监听器类型
- 默认监听器:名称为 LISTENER,使用默认端口 1521
- 自定义监听器:用户定义的监听器,可使用不同名称和端口
- SCAN 监听器:RAC 环境中的单客户端访问名称监听器
监听器进程
- tnslsnr:监听器进程
- 启动:
lsnrctl start - 停止:
lsnrctl stop - 状态:
lsnrctl status
listener.ora 配置
基本配置
默认监听器配置:
txtLISTENER = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521)) (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521)) ) )自定义监听器配置:
txtCUSTOM_LISTENER = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = dbserver)(PORT = 1522)) ) )
高级配置
静态注册:
txtSID_LIST_LISTENER = (SID_LIST = (SID_DESC = (SID_NAME = PLSExtProc) (ORACLE_HOME = /u01/app/oracle/product/19.0.0/dbhome_1) (PROGRAM = extproc) ) (SID_DESC = (GLOBAL_DBNAME = orcl.example.com) (SID_NAME = orcl) (ORACLE_HOME = /u01/app/oracle/product/19.0.0/dbhome_1) ) )连接超时配置:
txtLISTENER = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521)) ) ) CONNECT_TIMEOUT_LISTENER = 10日志和跟踪配置:
txtLOG_FILE_LISTENER = listener.log LOG_DIRECTORY_LISTENER = /u01/app/oracle/diag/tnslsnr/dbserver/listener/alert TRACE_FILE_LISTENER = listener.trc TRACE_DIRECTORY_LISTENER = /u01/app/oracle/diag/tnslsnr/dbserver/listener/trace TRACE_LEVEL_LISTENER = OFF
RAC 环境配置
SCAN 监听器配置:
txtLISTENER_SCAN1 = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = scan-cluster)(PORT = 1521)) ) )节点监听器配置:
txtLISTENER_NODE1 = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = node1-vip)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = node1)(PORT = 1526)) ) )
监听器管理
监听器命令
启动监听器:
bashlsnrctl start [监听器名称]停止监听器:
bashlsnrctl stop [监听器名称]查看监听器状态:
bashlsnrctl status [监听器名称]重新加载配置:
bashlsnrctl reload [监听器名称]查看监听器服务:
bashlsnrctl services [监听器名称]
监听器自动启动
- Linux/Unix:配置在 /etc/init.d/ 或 systemd 服务中
- Windows:配置为 Windows 服务
监听器日志管理
查看日志:
bashtail -f $ORACLE_HOME/network/log/listener.log日志轮换:定期备份和清理日志文件
启用详细日志:设置 TRACE_LEVEL_LISTENER = ADMIN
tnsnames.ora 配置
连接描述符
基本格式
txt<连接名称> = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = <主机名>)(PORT = <端口>)) ) (CONNECT_DATA = (SERVER = <服务器类型>) (SERVICE_NAME = <服务名>) # 或 (SID = <实例名>) ) )参数说明
- 连接名称:客户端使用的连接标识符
- PROTOCOL:网络协议,通常为 TCP
- HOST:数据库服务器主机名或 IP 地址
- PORT:监听器端口,默认 1521
- SERVER:服务器类型(DEDICATED、SHARED 或 POOLED)
- SERVICE_NAME:数据库服务名(推荐)
- SID:数据库实例名(旧版格式)
示例配置
基本连接:
txtORCL = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = dbserver)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orcl.example.com) ) )负载均衡连接:
txtORCL_RAC = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = node1-vip)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = node2-vip)(PORT = 1521)) (LOAD_BALANCE = YES) ) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orcl.example.com) ) )故障转移连接:
txtORCL_FO = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = primary)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = standby)(PORT = 1521)) (FAILOVER = ON) ) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orcl.example.com) (FAILOVER_MODE = (TYPE = SELECT) (METHOD = BASIC) (RETRIES = 180) (DELAY = 5) ) ) )
高级配置
连接超时设置
txtORCL = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = dbserver)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orcl.example.com) ) (CONNECT_TIMEOUT = 10) (RETRY_COUNT = 3) )源路由配置
txtORCL_VIA_PROXY = (DESCRIPTION = (SOURCE_ROUTE = YES) (ADDRESS = (PROTOCOL = TCP)(HOST = proxy)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = dbserver)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orcl.example.com) ) )SSL 连接配置
txtORCL_SSL = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCPS)(HOST = dbserver)(PORT = 2484)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orcl.example.com) ) (SECURITY = (SSL_SERVER_CERT_DN = "CN=dbserver,OU=IT,O=Company,L=City,ST=State,C=CN") ) )
配置管理
集中管理
- 使用 LDAP 目录服务存储连接信息
- 配置 ldap.ora 文件指向 LDAP 服务器
- 客户端通过 LDAP 查找连接信息
环境变量
TNS_ADMIN:指定 tnsnames.ora 文件位置
bashexport TNS_ADMIN=/path/to/tnsnames/directoryORACLE_HOME:默认情况下,Oracle 会在 $ORACLE_HOME/network/admin 查找配置文件
测试连接配置
使用 tnsping 测试连接配置:
bashtnsping <连接名称> [超时秒数]示例:
bashtnsping ORCL 10
sqlnet.ora 配置
基本配置
命名方法
- 配置客户端如何解析连接标识符
- 示例:txt
NAMES.DIRECTORY_PATH = (TNSNAMES, EZCONNECT, LDAP)
网络超时
SQLNET.EXPIRE_TIME:检测死连接的时间间隔(分钟)
txtSQLNET.EXPIRE_TIME=10SQLNET.INBOUND_CONNECT_TIMEOUT:入站连接超时(秒)
txtSQLNET.INBOUND_CONNECT_TIMEOUT=60SQLNET.OUTBOUND_CONNECT_TIMEOUT:出站连接超时(秒)
txtSQLNET.OUTBOUND_CONNECT_TIMEOUT=30
认证方式
SQLNET.AUTHENTICATION_SERVICES:认证服务列表
txtSQLNET.AUTHENTICATION_SERVICES = (BEQ, TCPS, NTS)SQLNET.ENCRYPTION_TYPES_CLIENT:客户端加密类型
SQLNET.CRYPTO_CHECKSUM_TYPES_CLIENT:客户端校验和类型
安全配置
加密设置
SQLNET.ENCRYPTION_CLIENT:客户端加密级别
txtSQLNET.ENCRYPTION_CLIENT = REQUIREDSQLNET.ENCRYPTION_TYPES_CLIENT:客户端加密算法
txtSQLNET.ENCRYPTION_TYPES_CLIENT = (AES256, AES192, AES128)
校验和设置
SQLNET.CRYPTO_CHECKSUM_CLIENT:客户端校验和级别
txtSQLNET.CRYPTO_CHECKSUM_CLIENT = REQUIREDSQLNET.CRYPTO_CHECKSUM_TYPES_CLIENT:客户端校验和算法
txtSQLNET.CRYPTO_CHECKSUM_TYPES_CLIENT = (SHA256, SHA1)
访问控制
- tcp.validnode_checking:启用节点检查txt
tcp.validnode_checking = YES tcp.invited_nodes = (192.168.1.0/24, dbserver) # tcp.excluded_nodes = (192.168.1.100)
- tcp.validnode_checking:启用节点检查
高级配置
日志和跟踪
SQLNET.LOG_FILE_CLIENT:客户端日志文件
txtSQLNET.LOG_FILE_CLIENT = client.logSQLNET.LOG_DIRECTORY_CLIENT:客户端日志目录
txtSQLNET.LOG_DIRECTORY_CLIENT = /u01/app/oracle/logSQLNET.TRACE_LEVEL_CLIENT:客户端跟踪级别
txtSQLNET.TRACE_LEVEL_CLIENT = OFF
连接池设置
- SQLNET.INBOUND_CONNECT_TIMEOUT_LISTENER:监听器入站连接超时txt
SQLNET.INBOUND_CONNECT_TIMEOUT_LISTENER = 60
- SQLNET.INBOUND_CONNECT_TIMEOUT_LISTENER:监听器入站连接超时
字符集设置
- NLS_LANG:客户端语言和字符集txt
NLS_LANG = SIMPLIFIED CHINESE_CHINA.AL32UTF8
- NLS_LANG:客户端语言和字符集
网络连接测试
基本测试
tnsping 测试
测试网络连接和解析
示例:
bashtnsping ORCL成功输出:
TNS Ping Utility for Linux: Version 19.0.0.0.0 - Production on 01-JAN-2024 12:00:00 Copyright (c) 1997, 2019, Oracle. All rights reserved. Used parameter files: /u01/app/oracle/product/19.0.0/dbhome_1/network/admin/sqlnet.ora Used TNSNAMES adapter to resolve the alias Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = dbserver)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orcl.example.com))) OK (10 msec)
SQL*Plus 连接测试
测试实际数据库连接
示例:
bashsqlplus username/password@ORCL或使用 EZCONNECT 语法:
bashsqlplus username/password@//dbserver:1521/orcl.example.com
Oracle Net Manager 测试
- 图形化工具测试连接
- 启动:
netmgr - 导航到 "服务命名" → 选择连接 → 点击 "测试"
高级测试
连接时间测试
- 测量连接建立时间
- 示例:bash
time sqlplus -S username/password@ORCL << EOF SELECT 1 FROM dual; EXIT; EOF
网络吞吐量测试
- 使用 Oracle 提供的测试工具
- 或使用第三方工具如 iperf
连接池测试
- 测试连接池性能
- 使用应用程序模拟多用户并发连接
故障转移测试
- 测试 RAC 或 Data Guard 故障转移
- 模拟节点故障,验证连接是否自动转移
高级网络配置
共享服务器配置
配置共享服务器
- 在 init.ora 或 spfile.ora 中设置:txt
dispatchers = "(PROTOCOL=TCP) (SERVICE=orclXDB)" shared_servers = 5 max_shared_servers = 20
- 在 init.ora 或 spfile.ora 中设置:
共享服务器参数
- SHARED_SERVERS:初始共享服务器进程数
- MAX_SHARED_SERVERS:最大共享服务器进程数
- DISPATCHERS:调度器配置
- SHARED_SERVER_SESSIONS:共享服务器最大会话数
客户端配置
- 在 tnsnames.ora 中指定共享服务器连接:txt
ORCL_SHARED = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = dbserver)(PORT = 1521)) (CONNECT_DATA = (SERVER = SHARED) (SERVICE_NAME = orcl.example.com) ) )
- 在 tnsnames.ora 中指定共享服务器连接:
连接管理器配置
连接管理器功能
- 集中连接管理
- 连接池
- 网络访问控制
- 协议转换
配置文件 cman.ora
txtCMAN = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = cman-host)(PORT = 1521)) ) CMAN_PROFILE = (PARAMETER_LIST = (LOG_LEVEL = ADMIN) (TRACING = YES) (TRACE_DIRECTORY = /u01/app/oracle/product/19.0.0/dbhome_1/network/trace) (MAX_GATEWAY_PROCESSES = 8) (MIN_GATEWAY_PROCESSES = 2) (MAX_CONNECTIONS = 100) (INBOUND_CONNECT_TIMEOUT = 120) (SESSION_TIMEOUT = 7200) (IDLE_TIMEOUT = 3600) )启动和管理
- 启动:
cmctl start cmgr - 停止:
cmctl stop cmgr - 状态:
cmctl status cmgr
- 启动:
SSL 配置
证书管理
- 创建或获取 SSL 证书
- 配置 Oracle Wallet 存储证书
- 使用 orapki 工具管理证书
服务器端配置
在 listener.ora 中添加 SSL 监听:
txtLISTENER = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = dbserver)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCPS)(HOST = dbserver)(PORT = 2484)) ) )在 sqlnet.ora 中配置 SSL:
txtWALLET_LOCATION = (SOURCE = (METHOD = FILE) (METHOD_DATA = (DIRECTORY = /u01/app/oracle/wallet) ) ) SSL_CLIENT_AUTHENTICATION = FALSE SSL_CIPHER_SUITES = (SSL_RSA_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_AES_128_CBC_SHA)
客户端配置
在 tnsnames.ora 中添加 SSL 连接:
txtORCL_SSL = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCPS)(HOST = dbserver)(PORT = 2484)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orcl.example.com) ) (SECURITY = (SSL_SERVER_CERT_DN = "CN=dbserver,OU=IT,O=Company,L=City,ST=State,C=CN") ) )在 sqlnet.ora 中配置客户端 SSL:
txtWALLET_LOCATION = (SOURCE = (METHOD = FILE) (METHOD_DATA = (DIRECTORY = /client/wallet) ) ) SSL_CLIENT_AUTHENTICATION = FALSE
网络安全
访问控制
TCP 验证节点检查
- 在 sqlnet.ora 中配置:txt
tcp.validnode_checking = YES tcp.invited_nodes = (192.168.1.0/24, dbserver)
- 在 sqlnet.ora 中配置:
防火墙配置
- 配置防火墙允许 Oracle 端口访问
- 仅允许必要的 IP 地址访问数据库端口
- 示例(iptables):bash
iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 1521 -j ACCEPT iptables -A INPUT -p tcp --dport 1521 -j DROP
连接管理器访问控制
- 在 cman.ora 中配置访问控制列表
- 限制允许的客户端 IP 地址
加密和完整性
网络加密
- 配置 SQLNET.ENCRYPTION_CLIENT 和 SQLNET.ENCRYPTION_SERVER
- 选择合适的加密算法
数据完整性
- 配置 SQLNET.CRYPTO_CHECKSUM_CLIENT 和 SQLNET.CRYPTO_CHECKSUM_SERVER
- 选择合适的校验和算法
SSL/TLS 配置
- 使用 TCPS 协议
- 配置 Oracle Wallet 存储证书
- 验证服务器证书
认证安全
密码认证
- 使用强密码策略
- 启用密码大小写敏感
- 限制失败登录尝试次数
操作系统认证
- 仅在可信环境中使用
- 配置 SQLNET.AUTHENTICATION_SERVICES = (BEQ)
外部认证
- 使用 LDAP、RADIUS 或 Kerberos
- 配置相应的认证服务
特权用户访问
- 限制 SYSDBA 和 SYSOPER 权限的使用
- 使用密码文件或操作系统认证
网络故障排查
常见网络问题
连接超时
- 原因:网络不通、防火墙阻止、监听器未启动
- 解决方法:
- 检查网络连通性:
ping dbserver - 检查端口可达:
telnet dbserver 1521 - 检查监听器状态:
lsnrctl status
- 检查网络连通性:
TNS-12541: TNS:no listener
- 原因:监听器未启动或端口不正确
- 解决方法:
- 启动监听器:
lsnrctl start - 检查监听器端口配置
- 启动监听器:
TNS-12514: TNS:listener does not currently know of service requested in connect descriptor
- 原因:服务名不正确或监听器未注册该服务
- 解决方法:
- 检查服务名是否正确
- 检查监听器服务:
lsnrctl services - 强制注册服务:
ALTER SYSTEM REGISTER;
TNS-12535: TNS:operation timed out
- 原因:网络延迟高、连接超时设置过小
- 解决方法:
- 检查网络延迟
- 增加 SQLNET.OUTBOUND_CONNECT_TIMEOUT 值
TNS-12154: TNS:could not resolve the connect identifier specified
- 原因:tnsnames.ora 中无对应连接名称或文件位置不正确
- 解决方法:
- 检查 tnsnames.ora 文件
- 确认 TNS_ADMIN 环境变量设置正确
- 验证连接名称拼写
故障排查工具
网络工具
- ping:检查网络连通性
- telnet:检查端口可达性
- traceroute:跟踪网络路径
- netstat:查看网络连接状态
Oracle 工具
- lsnrctl:监听器管理和诊断
- tnsping:测试网络服务名称解析
- sqlnetctl:SQL*Net 控制工具
- Oracle Net Manager:图形化网络配置和测试
日志文件
- 监听器日志:
$ORACLE_HOME/network/log/listener.log - SQL*Net 日志:由 sqlnet.ora 中的 LOG_FILE_CLIENT 指定
- 数据库告警日志:
$ORACLE_BASE/diag/rdbms/<dbname>/<instance>/trace/alert_<instance>.log
- 监听器日志:
诊断包
- Oracle Net Services 诊断包:收集网络相关信息
- 自动诊断仓库 (ADR):存储诊断信息
网络服务最佳实践
配置最佳实践
使用服务名
- 优先使用 SERVICE_NAME 而非 SID
- 服务名更灵活,支持多个实例
标准化配置
- 使用统一的命名规范
- 保持配置文件格式一致
- 文档化网络配置
高可用性配置
- 配置多个地址以支持故障转移
- 使用 LOAD_BALANCE 和 FAILOVER 参数
- 定期测试故障转移功能
性能优化
- 使用连接池减少连接开销
- 合理设置超时参数
- 优化网络缓冲区大小
管理最佳实践
监控
- 监控监听器状态
- 监控网络连接数
- 监控网络延迟和吞吐量
备份
- 定期备份网络配置文件
- 记录网络拓扑结构
- 保存网络变更历史
安全
- 启用网络加密
- 配置访问控制
- 定期审查网络安全设置
文档
- 维护网络拓扑图
- 记录 IP 地址和端口分配
- 文档化网络故障处理流程
故障预防
定期检查
- 检查监听器状态
- 检查网络连接
- 检查配置文件完整性
预防性维护
- 定期更新网络设备固件
- 优化网络配置
- 清理过期的连接配置
容量规划
- 预测网络流量增长
- 规划网络带宽需求
- 预留足够的连接资源
灾备计划
- 制定网络故障应急预案
- 建立网络服务恢复流程
- 定期演练网络故障恢复
常见问题(FAQ)
Q1: 监听器启动失败,如何排查?
A1: 排查步骤:
- 检查监听器配置文件:
listener.ora是否有语法错误 - 检查端口是否被占用:
netstat -tuln | grep 1521 - 检查主机名解析:
ping <主机名> - 查看监听器日志:
tail -f $ORACLE_HOME/network/log/listener.log - 尝试启动监听器并查看详细输出:
lsnrctl start LISTENER
Q2: 客户端连接缓慢,如何优化?
A2: 优化方法:
- 检查网络延迟:
ping dbserver - 检查监听器性能:
lsnrctl services - 启用连接池减少连接建立开销
- 优化 tnsnames.ora 配置,添加连接超时参数
- 考虑使用共享服务器模式处理大量短连接
Q3: 如何在防火墙环境中配置 Oracle 网络?
A3: 配置方法:
- 确保数据库服务器和客户端之间的网络连通
- 在防火墙上开放必要的端口:
- 默认监听器端口:1521
- SSL 端口:2484(如需加密连接)
- RAC 集群通信端口
- 配置监听器使用固定端口
- 考虑使用连接管理器集中管理连接
Q4: 如何配置 Oracle 网络以支持多租户环境?
A4: 多租户配置:
- 为每个 PDB 创建不同的服务名
- 在 tnsnames.ora 中为每个 PDB 创建单独的连接条目
- 示例配置:txt
PDB1 = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = dbserver)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = pdb1.example.com) ) )
Q5: RAC 环境中如何配置网络以实现负载均衡和故障转移?
A5: RAC 网络配置:
- 使用 SCAN 监听器实现负载均衡
- 在 tnsnames.ora 中配置多个地址和负载均衡参数
- 示例配置:txt
RAC_SERVICE = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = node1-vip)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = node2-vip)(PORT = 1521)) (LOAD_BALANCE = YES) (FAILOVER = ON) ) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = rac_service.example.com) (FAILOVER_MODE = (TYPE = SELECT) (METHOD = BASIC) (RETRIES = 180) (DELAY = 5) ) ) )
Q6: 如何诊断 TNS-12504: TNS:listener was not given the SERVICE_NAME in CONNECT_DATA 错误?
A6: 解决方法:
- 检查 tnsnames.ora 文件中的连接描述符
- 确保 CONNECT_DATA 部分包含 SERVICE_NAME 或 SID 参数
- 示例正确配置:txt
ORCL = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = dbserver)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orcl.example.com) ) )
Q7: 如何在没有 tnsnames.ora 文件的情况下连接数据库?
A7: 连接方法:
使用 EZCONNECT 语法:
bashsqlplus username/password@//dbserver:1521/service_name使用 LDAP 目录服务(如果配置)
使用 Oracle Names 服务(旧版方法,已不推荐)
Q8: 如何配置 Oracle 网络以支持 IPv6?
A8: IPv6 配置:
确保操作系统支持 IPv6
在监听器配置中添加 IPv6 地址:
txtLISTENER = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = ::1)(PORT = 1521)) # IPv6 localhost (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521)) # IPv4 localhost ) )在 tnsnames.ora 中使用 IPv6 地址:
txtORCL_IPV6 = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 2001:db8::1)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orcl.example.com) ) )
