refactor: 使用 BC Math 替换浮点运算以提高精度

将多处基于浮点的数值计算替换为 BC Math 字符串运算以避免浮点精度问题,涉及支付、退款、转账、比较与统计逻辑的重构。主要改动包括:

- 将比较与判断替换为 bccomp,累加与合并使用 bcadd,乘以 100 等使用 bcmul;
- 将部分初始数值与统计结果从数值类型改为字符串形式(如 '0.00'),并调整相关返回类型(如 Payment::paidAmount 改为返回 string);
- 修正订单/退款金额计算与超额校验逻辑以使用高精度算术;
- 更新微信支付相关 SDK 调用中金额乘 100 的计算以避免精度误差;
- 在若干插件中用高精度运算替换 floatval/int 转换(包括 SystemQueue、Wemall、Wuma 等);
- 更新文档(readme)添加 BC Math/高精度计算等说明并统一版权年份至 2014-2026;
- 新增 .copilot-commit-message-instructions.md(提交信息规范)。

此改动旨在增强金融/金额相关业务的计算正确性与一致性,避免因浮点运算导致的金额误差。
This commit is contained in:
邹景立 2026-02-01 13:27:10 +08:00
parent 987ad41765
commit d2b499d14a
19 changed files with 57 additions and 36 deletions

View File

@ -0,0 +1,4 @@
请用中文生成提交信息,遵循规范提交格式:
- 标题:类型:以业务内容为主简短描述
- 正文:详细说明改动原因与内容
- 类型feat/fix/docs/style/refactor/test/chore

View File

@ -21,6 +21,7 @@
- **表单验证机制**: 支持规则别名和自定义验证,确保数据输入安全
- **异步任务队列**: 支持延时执行和循环任务,提升系统响应性能
- **CSRF 令牌验证**: 内置表单安全验证,防止跨站请求伪造攻击
- **高精度计算支持**: 集成 BC Math 高精度数学函数,确保金融计算的准确性
**技术特性:**
- **PSR-12 标准**: 严格遵循 PHP-FIG 编码规范,确保代码质量和可维护性
@ -28,6 +29,7 @@
- **高性能优化**: 针对高并发场景进行专门优化,支持缓存和数据库连接池
- **异常处理完善**: 完善的异常捕获和日志记录机制,便于问题排查
- **向后兼容**: 保持 API 稳定性,确保平滑升级
- **数据完整性保障**: 通过数据库约束确保业务数据的一致性和有效性
## 功能说明
@ -117,6 +119,8 @@
* **Github** 仓库地址https://github.com/zoujingli/ThinkLibrary
* **Gitcode** 仓库地址: https://gitcode.com/ThinkAdmin/ThinkLibrary
版权所有 Copyright © 2014-2026 by ThinkAdmin (https://thinkadmin.top) All rights reserved。
## 使用说明
1. **依赖管理**ThinkLibrary 需要 Composer 支持进行安装和依赖管理。

View File

@ -64,7 +64,7 @@ class SystemQueue extends Model
*/
public function getEnterTimeAttr($value): string
{
return floatval($value) > 0 ? format_datetime(intval($value)) : '';
return bccomp(strval($value), '0.00', 2) > 0 ? format_datetime(intval($value)) : '';
}
/**

View File

@ -38,7 +38,7 @@
### 加入我们
我们的代码仓库已移至 **Github**,而 **Gitee** 则仅作为国内镜像仓库,方便广大开发者获取和使用。若想提交 **PR****ISSUE** 请在 [ThinkAdminDeveloper](https://github.com/zoujingli/ThinkAdminDeveloper) 仓库进行操作,如果在其他仓库操作或提交问题将无法处理!
我们的代码仓库已移至 **Github**,而 **Gitee** 则仅作为国内镜像仓库,方便广大开发者获取和使用。若想提交 **PR****ISSUE** 请在 [ThinkAdminDeveloper](https://github.com/zoujingli/ThinkAdminDeveloper) 仓库进行操作,如果在其他仓库操作或提交问题将无法处理!.
### 开放接口
@ -165,13 +165,14 @@ var_dump($types);
- **动态通道注册**: 支持运行时动态注册新的登录通道类型,灵活扩展登录方式
- **手机号绑定验证**: 通过短信验证码实现手机号绑定,确保账号安全性和唯一性
- **账号解绑管理**: 支持终端账号与主账号的灵活绑定和解绑操作
**技术特性:**
- **高并发安全**: 支持高并发场景下的账号创建和绑定操作
- **数据一致性保障**: 通过数据库事务确保账号数据的一致性
**技术特性:**
- **缓存优化**: 集成缓存机制,提升账号信息查询性能
- **异常处理完善**: 完善的异常捕获和错误处理机制
- **扩展性设计**: 抽象的账号接口设计,便于扩展新的认证方式
- **向后兼容**: 保持 API 稳定性,确保平滑升级
### 插件数据
@ -188,4 +189,4 @@ var_dump($types);
未获得此插件授权时仅供参考学习不可商用,了解商用授权请阅读 [《会员授权》](https://thinkadmin.top/vip-introduce)。
版权所有 Copyright © 2014-2025 by ThinkAdmin (https://thinkadmin.top) All rights reserved。
版权所有 Copyright © 2014-2026 by ThinkAdmin (https://thinkadmin.top) All rights reserved。

View File

@ -68,6 +68,7 @@ composer remove zoujingli/think-plugs-payment
- **支付事件驱动**: 通过支付事件(审核、完成、取消、确认)实现业务逻辑解耦
- **退款管理**: 支持部分退款和全额退款,自动处理余额、积分的退回操作
- **支付配置管理**: 可视化配置各种支付通道参数,支持动态启用/禁用支付方式
- **高精度金融计算**: 全面采用 BC Math 高精度数学函数,确保金融计算的准确性,避免浮点数精度丢失问题
**账户资金管理:**
- **余额管理系统**: 完整的余额充值、消费、锁定、解锁、作废等操作
@ -75,12 +76,14 @@ composer remove zoujingli/think-plugs-payment
- **高精度计算**: 使用 BC Math 高精度数学函数,确保金融计算的准确性
- **资金流水追踪**: 完整的资金变动记录,支持来源追溯和审计
- **并发安全控制**: 支持高并发场景下的余额和积分操作,避免超支问题
- **数据完整性保障**: 通过数据库约束确保业务数据的一致性和有效性
**技术特性:**
- **支付接口抽象**: 统一的支付接口标准,便于扩展新的支付方式
- **数据库约束优化**: 添加金额非负约束、状态枚举约束,确保数据完整性
- **异常处理机制**: 完善的异常捕获和日志记录,便于问题排查
- **事务一致性**: 关键业务操作保证数据一致性,避免脏数据产生
- **向后兼容**: 保持 API 稳定性,确保平滑升级
### 插件数据
@ -99,4 +102,4 @@ composer remove zoujingli/think-plugs-payment
未获得此插件授权时仅供参考学习不可商用,了解商用授权请阅读 [《会员授权》](https://thinkadmin.top/vip-introduce)。
版权所有 Copyright © 2014-2025 by ThinkAdmin (https://thinkadmin.top) All rights reserved。
版权所有 Copyright © 2014-2026 by ThinkAdmin (https://thinkadmin.top) All rights reserved。

View File

@ -3,7 +3,7 @@
// +----------------------------------------------------------------------
// | Payment Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2025 ThinkAdmin [ thinkadmin.top ]
// | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
@ -427,11 +427,11 @@ abstract class Payment
* @param string $orderNo 订单单号
* @param bool $realtime 有效金额
*/
public static function paidAmount(string $orderNo, bool $realtime = false): float
public static function paidAmount(string $orderNo, bool $realtime = false): string
{
$map = ['order_no' => $orderNo, 'payment_status' => 1];
$raw = new Raw($realtime ? 'payment_amount - refund_amount' : 'payment_amount');
return round(PluginPaymentRecord::mk()->where($map)->sum($raw), 2);
return bcadd('0.00', strval(PluginPaymentRecord::mk()->where($map)->sum($raw)), 2);
}
/**
@ -451,7 +451,7 @@ abstract class Payment
*/
public static function totalPaymentAmount(string $orderNo): array
{
$total = ['amount' => 0, 'payment' => 0, 'balance' => 0, 'integral' => 0];
$total = ['amount' => '0.00', 'payment' => '0.00', 'balance' => '0.00', 'integral' => '0.00'];
try {
PluginPaymentRecord::mk()->where(['order_no' => $orderNo, 'payment_status' => 1])->field([
'channel_type',
@ -460,12 +460,12 @@ abstract class Payment
'sum(used_balance-refund_balance)' => 'balance',
'sum(used_integral-refund_integral)' => 'integral',
])->group('channel_type')->select()->map(static function (PluginPaymentRecord $item) use (&$total) {
$total['amount'] = round($total['amount'] + $item->getAttr('amount'), 2);
$total['amount'] = bcadd($total['amount'], strval($item->getAttr('amount')), 2);
$type = $item->getAttr('channel_type');
if (!in_array($type, [self::INTEGRAL, self::BALANCE])) {
$type = 'payment';
}
$total[$type] = round($total[$type] + $item[$type] ?? 0, 2);
$total[$type] = bcadd($total[$type], strval($item[$type] ?? '0.00'), 2);
});
} catch (\Exception $exception) {
trace_file($exception);
@ -479,17 +479,17 @@ abstract class Payment
*/
public static function totalRefundAmount(string $pCode): array
{
$total = ['amount' => 0, 'payment' => 0, 'balance' => 0, 'integral' => 0];
$total = ['amount' => '0.00', 'payment' => '0.00', 'balance' => '0.00', 'integral' => '0.00'];
try {
PluginPaymentRefund::mk()->where(['record_code' => $pCode, 'refund_status' => [0, 1]])->field([
'refund_account', 'sum(refund_amount) amount', 'sum(used_payment)' => 'payment', 'sum(used_balance)' => 'balance', 'sum(used_integral)' => 'integral',
])->group('refund_account')->select()->map(static function (PluginPaymentRefund $item) use (&$total) {
$total['amount'] = round($total['amount'] + $item->getAttr('amount'), 2);
$total['amount'] = bcadd($total['amount'], strval($item->getAttr('amount')), 2);
$type = $item->getAttr('refund_account');
if (!in_array($type, [self::INTEGRAL, self::BALANCE])) {
$type = 'payment';
}
$total[$type] = round($total[$type] + $item[$type] ?? 0, 2);
$total[$type] = bcadd($total[$type], strval($item[$type] ?? '0.00'), 2);
});
} catch (\Exception $exception) {
trace_file($exception);

View File

@ -85,7 +85,7 @@ class BalancePayment implements PaymentInterface
{
try {
// 记录并退回
if (floatval($amount) <= 0) {
if (bccomp(strval($amount), '0.00', 2) <= 0) {
return [1, '无需退款!'];
}
$record = static::syncRefund($pcode, $rcode, $amount, $reason);

View File

@ -85,7 +85,7 @@ class IntegralPayment implements PaymentInterface
{
try {
// 记录并退回
if (floatval($amount) <= 0) {
if (bccomp(strval($amount), '0.00', 2) <= 0) {
return [1, '无需退款!'];
}
$record = static::syncRefund($pcode, $rcode, $amount, $reason);

View File

@ -92,7 +92,7 @@ class WechatPaymentV2 extends WechatPayment
'attach' => $this->cfgCode,
'out_trade_no' => $payCode,
'trade_type' => static::tradeTypes[$this->cfgType] ?? '',
'total_fee' => intval(floatval($payAmount) * 100),
'total_fee' => intval(strval(bcmul(strval($payAmount), '100', 0))),
'notify_url' => $this->withNotifyUrl($payCode),
'spbill_create_ip' => $this->app->request->ip(),
];
@ -203,7 +203,7 @@ class WechatPaymentV2 extends WechatPayment
'out_trade_no' => $pcode,
'out_refund_no' => $rcode,
'total_fee' => intval($record->getAttr('payment_amount') * 100),
'refund_fee' => intval(floatval($amount) * 100),
'refund_fee' => intval(strval(bcmul(strval($amount), '100', 0))),
'notify_url' => static::withNotifyUrl($rcode, 'refund'),
];
if (strlen($reason) > 0) {

View File

@ -206,7 +206,7 @@ class WechatPaymentV3 extends WechatPayment
'notify_url' => static::withNotifyUrl($rcode, 'refund'),
'amount' => [
'total' => intval($record->getAttr('payment_amount') * 100),
'refund' => intval(floatval($amount) * 100),
'refund' => intval(strval(bcmul(strval($amount), '100', 0))),
'currency' => 'CNY',
],
];

View File

@ -84,8 +84,8 @@ class PaymentService
return ['code' => 1, 'info' => '已完成支付!', 'data' => [], 'params' => []];
}
// 检查剩余支付金额
$pAmount = floatval(is_null($pAmount) ? (floatval($oAmount) - $oPayed) : $pAmount);
if ($oPayed + $pAmount > floatval($oAmount)) {
$pAmount = strval(is_null($pAmount) ? (bcsub(strval($oAmount), strval($oPayed), 2)) : $pAmount);
if (bccomp(bcadd(strval($oPayed), $pAmount, 2), strval($oAmount), 2) > 0) {
return ['code' => 0, 'info' => '支付总额超出!', 'data' => [], 'params' => []];
}
$config = WechatService::getConfig(true);
@ -218,7 +218,7 @@ class PaymentService
if ($record->getAttr('refund_amount') >= $record->getAttr('payment_amount')) {
return [1, '该订单已完成退款!'];
}
if ($record->getAttr('refund_amount') + floatval($amount) > $record->getAttr('payment_amount')) {
if (bccomp(bcadd(strval($record->getAttr('refund_amount')), strval($amount), 2), strval($record->getAttr('payment_amount')), 2) > 0) {
return [0, '退款大于支付金额!'];
}
// 创建支付退款申请
@ -232,7 +232,7 @@ class PaymentService
'out_refund_no' => $rcode,
'notify_url' => static::withNotifyUrl($rcode, 'refund'),
'amount' => [
'refund' => intval(floatval($amount) * 100),
'refund' => intval(strval(bcmul(strval($amount), '100', 0))),
'total' => intval($record->getAttr('payment_amount') * 100),
'currency' => 'CNY',
],
@ -372,10 +372,10 @@ class PaymentService
protected static function createPaymentAction(string $openid, string $oCode, string $oName, string $oAmount, string $pType, string $pCode, string $pAmount): array
{
// 检查是否已经支付
if (static::withPayed($oCode, $oPayed) >= floatval($oAmount)) {
if (bccomp(strval(self::withPayed($oCode, $oPayed)), strval($oAmount), 2) >= 0) {
throw new Exception('已经完成支付', 1);
}
if ($oPayed + floatval($pAmount) > floatval($oAmount)) {
if (bccomp(bcadd(strval($oPayed), strval($pAmount), 2), strval($oAmount), 2) > 0) {
throw new Exception('总支付超出金额', 0);
}
$map = ['order_code' => $oCode, 'payment_status' => 1];

View File

@ -13,7 +13,7 @@
### 加入我们
我们的代码仓库已移至 **Github**,而 **Gitee** 则仅作为国内镜像仓库,方便广大开发者获取和使用。若想提交 **PR****ISSUE** 请在 [ThinkAdminDeveloper](https://github.com/zoujingli/ThinkAdminDeveloper) 仓库进行操作,如果在其他仓库操作或提交问题将无法处理!
我们的代码仓库已移至 **Github**,而 **Gitee** 则仅作为国内镜像仓库,方便广大开发者获取和使用。若想提交 **PR****ISSUE** 请在 [ThinkAdminDeveloper](https://github.com/zoujingli/ThinkAdminDeveloper) 仓库进行操作,如果在其他仓库操作或提交问题将无法处理!.
### 依赖插件
@ -59,6 +59,7 @@ composer remove zoujingli/think-plugs-wemall
- **订单全流程管理**: 从下单、支付、发货到售后的完整订单生命周期管理
- **推广海报管理**: 支持为不同用户等级生成个性化推广海报
- **团队业绩统计**: 实时统计团队销售业绩和返佣数据
- **高精度计算保障**: 全面采用 BC Math 高精度计算,避免浮点数精度丢失问题
**技术特性:**
- **高精度金融计算**: 使用 BC Math 高精度计算,避免浮点数精度丢失问题
@ -66,6 +67,7 @@ composer remove zoujingli/think-plugs-wemall
- **数据库约束优化**: 添加完整的外键约束、检查约束和索引优化
- **并发安全处理**: 支持高并发场景下的余额、积分、库存操作
- **数据完整性保障**: 通过数据库约束确保业务数据的一致性和有效性
- **向后兼容**: 保持 API 稳定性,确保平滑升级
### 插件数据
@ -84,4 +86,4 @@ composer remove zoujingli/think-plugs-wemall
未获得此插件授权时仅供参考学习不可商用,了解商用授权请阅读 [《会员授权》](https://thinkadmin.top/vip-introduce)。
版权所有 Copyright © 2014-2025 by ThinkAdmin (https://thinkadmin.top) All rights reserved。
版权所有 Copyright © 2014-2026 by ThinkAdmin (https://thinkadmin.top) All rights reserved。

View File

@ -127,7 +127,7 @@ class Clear extends Command
$this->queue->message(0, 0, '未启用订单自动取消功能!');
} else {
try {
$time = time() - intval(floatval($this->config['cancel_time']) * 3600);
$time = time() - intval(strval($this->config['cancel_time']) * 3600);
$remark = $this->config['cancel_text'] ?? '自动取消未完成支付';
$where = [['status', 'in', [1, 2, 3]], ['create_time', '<', date('Y-m-d H:i:s', $time)]];
[$count, $total] = [0, ($items = PluginWemallOrder::mk()->where($where)->select())->count()];
@ -157,7 +157,7 @@ class Clear extends Command
$this->queue->message(0, 0, '未启用订单自动清理功能!');
} else {
try {
$time = time() - intval(floatval($this->config['remove_time']) * 3600);
$time = time() - intval(strval($this->config['remove_time']) * 3600);
$remark = $this->config['remove_text'] ?? '系统自动清理已取消的订单!';
$where = [['status', '=', 0], ['deleted_status', '=', 0], ['create_time', '<', date('Y-m-d H:i:s', $time)]];
[$count, $total] = [0, ($items = PluginWemallOrder::mk()->where($where)->select())->count()];

View File

@ -112,7 +112,7 @@ class Trans extends Command
*/
private function createTransferV3(PluginWemallUserTransfer $model): array
{
$amount = floatval($model->getAttr('amount')) - floatval($model->getAttr('charge_amount'));
$amount = strval(bcmul(bcsub(strval($model->getAttr('amount')), strval($model->getAttr('charge_amount')), 2), '100', 0));
return TransfersV3::instance($this->getConfig($model))->batchs([
'out_batch_no' => "B{$model->getAttr('code')}",
'batch_name' => '微信余额提现',

View File

@ -126,7 +126,7 @@ class Agent extends Controller
$key = "{$ats[0]}_{$ats[1]}_status";
if ($vo['number'] > 0) {
isset($vo['extra'][$key]) || $vo['extra'][$key] = 0;
floatval($v) > 0 ? ++$count : ($vo['extra'][$key] = 0);
bccomp(strval($v), '0.00', 2) > 0 ? ++$count : ($vo['extra'][$key] = 0);
} else {
$vo['extra'][$k] = 0;
$vo['extra'][$key] = 0;

View File

@ -18,6 +18,7 @@
- **数据统计分析**: 提供扫码数据统计和分析,了解消费者行为
- **批量操作**: 支持物码的批量生成、导入、导出等操作
- **权限控制**: 完善的权限管理,确保数据安全
- **高精度计算支持**: 集成 BC Math 高精度数学函数,确保金融计算的准确性
- **收费授权**: 作为收费授权插件,提供专业的技术支持和功能更新
**技术特性:**
@ -26,12 +27,13 @@
- **安全防护**: 内置数据加密和权限验证,确保系统安全
- **向后兼容**: 保持与现有 ThinkAdmin 版本的兼容性,确保平滑升级
- **专业支持**: 提供专业的技术支持和定期功能更新
- **数据完整性保障**: 通过数据库约束确保业务数据的一致性和有效性
物码标签管理系统,此插件为收费授权插件,请联系作者获取授权,未授权不可商用。
### 加入我们
我们的代码仓库已移至 **Github**,而 **Gitee** 则仅作为国内镜像仓库,方便广大开发者获取和使用。若想提交 **PR****ISSUE** 请在 [ThinkAdminDeveloper](https://github.com/zoujingli/ThinkAdminDeveloper) 仓库进行操作,如果在其他仓库操作或提交问题将无法处理!
我们的代码仓库已移至 **Github**,而 **Gitee** 则仅作为国内镜像仓库,方便广大开发者获取和使用。若想提交 **PR****ISSUE** 请在 [ThinkAdminDeveloper](https://github.com/zoujingli/ThinkAdminDeveloper) 仓库进行操作,如果在其他仓库操作或提交问题将无法处理!.
### 安装插件
@ -67,4 +69,4 @@ composer remove zoujingli/think-plugs-wuma
未获得此插件授权时仅供参考学习不可商用,了解商用授权请阅读 [《付费授权》](https://thinkadmin.top/fee-introduce.html)。
版权所有 Copyright © 2014-2025 by ThinkAdmin (https://thinkadmin.top) All rights reserved。
版权所有 Copyright © 2014-2026 by ThinkAdmin (https://thinkadmin.top) All rights reserved。

View File

@ -89,7 +89,7 @@ class CodeService
public static function codever(string $code, int $full, int $size = 4): string
{
[$a, $b] = [base_convert($code, 10, $full - 1), base_convert(strrev($code), 10, $full - 2)];
return substr(str_pad(strval(floatval($a) + floatval($b)), $size, '0', STR_PAD_LEFT), 0, $size);
return substr(str_pad(strval(bcadd(strval($a), strval($b), 2)), $size, '0', STR_PAD_LEFT), 0, $size);
}
/**

View File

@ -276,7 +276,7 @@ class WhCoderService extends Service
} elseif (in_array($attr[1], ['MAX', 'MID'])) {
foreach ($rules['nums'] as $range => $num) {
[$start, $after] = explode('-', $range);
if (floatval($start) <= floatval($attr[0]) && floatval($attr[0]) <= floatval($after)) {
if (bccomp(strval($start), strval($attr[0]), 2) <= 0 && bccomp(strval($attr[0]), strval($after), 2) <= 0) {
$number = $num['mode'] === 1 ? $num['tomins'] : substr_count($strs, $code);
$maps[$code] = $code . '#' . $number;
$count += $number;

View File

@ -21,6 +21,7 @@
- **自定义服务基类**: 提供依赖注入和实例化机制,支持服务的统一管理和扩展
- **全局函数库**: 包含数据处理、系统配置、HTTP 请求、JWT 认证等实用函数
- **PSR-12 标准**: 严格遵循 PHP-FIG 编码规范,确保代码质量和可维护性
- **高精度计算支持**: 集成 BC Math 高精度数学函数,确保金融计算的准确性
**ThinkPlugsAccount 多端账号插件**
- **三层账号模型**: 临时用户(usid) ↔ 绑定手机(bind) ↔ 正式用户(unid) 的完整账号生命周期
@ -35,6 +36,7 @@
- **高精度金融计算**: 使用 BC Math 高精度数学函数,确保金融计算的准确性
- **支付事件驱动**: 通过支付事件(审核、完成、取消、确认)实现业务逻辑解耦
- **退款管理**: 支持部分退款和全额退款,自动处理余额、积分的退回操作
- **数据库约束优化**: 添加金额非负约束、状态枚举约束,确保数据完整性
**ThinkPlugsWemall 微商城插件**
- **多级分销体系**: 支持三级分销模式,可配置不同等级的代理返佣规则
@ -43,6 +45,7 @@
- **代理等级管理**: 团队业绩统计,支持多维度的代理等级升级条件
- **商品管理系统**: 完整的商品分类、规格、库存、价格管理
- **订单全流程管理**: 从下单、支付、发货到售后的完整订单生命周期管理
- **高精度计算保障**: 全面采用 BC Math 高精度计算,避免浮点数精度丢失问题
**其他插件**
- **ThinkPlugsCenter**: 插件服务管理中心,提供插件注册、配置和管理功能
@ -112,4 +115,6 @@ start http://127.0.0.1:8088
* 会员授权: [《会员尊享介绍》](https://thinkadmin.top/vip-introduce)
* 收费授权:请通过文档中微信二维码联系作者。
版权所有 Copyright © 2014-2026 by ThinkAdmin (https://thinkadmin.top) All rights reserved。
<img alt="" src="https://thinkadmin.top/static/img/wx.png" width="250">