ZHIWEI666 commited on
Commit
e4b11fa
·
verified ·
1 Parent(s): c1e5e15

增加更多详细交易数据

Browse files
Files changed (4) hide show
  1. database_sql.py +4 -0
  2. models_sql.py +6 -0
  3. router_tasks.py +47 -8
  4. router_wallet.py +91 -15
database_sql.py CHANGED
@@ -153,6 +153,10 @@ def _auto_migrate_p7_fields():
153
  'withdraw_status': 'VARCHAR',
154
  'payment_order_id': 'VARCHAR',
155
  'net_amount': 'INTEGER',
 
 
 
 
156
  }
157
 
158
  for col_name, col_type in new_columns.items():
 
153
  'withdraw_status': 'VARCHAR',
154
  'payment_order_id': 'VARCHAR',
155
  'net_amount': 'INTEGER',
156
+ 'description': 'VARCHAR',
157
+ 'item_title': 'VARCHAR',
158
+ 'item_type': 'VARCHAR',
159
+ 'related_user_name': 'VARCHAR',
160
  }
161
 
162
  for col_name, col_type in new_columns.items():
models_sql.py CHANGED
@@ -75,6 +75,12 @@ class Transaction(Base):
75
  payment_order_id = Column(String, nullable=True) # 管理员填写的打款订单号
76
  net_amount = Column(Integer, nullable=True) # 实际到账金额(用于解冻时准确扣减)
77
 
 
 
 
 
 
 
78
  # 🚀 P1性能优化:复合索引
79
  __table_args__ = (
80
  Index('ix_transactions_account_type', 'account', 'tx_type'),
 
75
  payment_order_id = Column(String, nullable=True) # 管理员填写的打款订单号
76
  net_amount = Column(Integer, nullable=True) # 实际到账金额(用于解冻时准确扣减)
77
 
78
+ # 交易详情增强字段
79
+ description = Column(String, nullable=True) # 交易自描述文本
80
+ item_title = Column(String, nullable=True) # 资源/任务标题
81
+ item_type = Column(String, nullable=True) # 资源类型 (tool/app/recommend/post/task)
82
+ related_user_name = Column(String, nullable=True) # 对方用户名
83
+
84
  # 🚀 P1性能优化:复合索引
85
  __table_args__ = (
86
  Index('ix_transactions_account_type', 'account', 'tx_type'),
router_tasks.py CHANGED
@@ -37,7 +37,9 @@ def calculate_tx_hash(tx_id, account, tx_type, amount, prev_hash):
37
  data = f"{tx_id}{account}{tx_type}{amount}{prev_hash}"
38
  return hashlib.sha256(data.encode()).hexdigest()
39
 
40
- def create_task_transaction(db_session: Session, account: str, tx_type: str, amount: int, related_account: str = None, task_id: str = None):
 
 
41
  """
42
  创建任务相关交易记录
43
  tx_type: TASK_FREEZE, TASK_DEPOSIT, TASK_PAYMENT, TASK_INCOME, TASK_REFUND
@@ -48,6 +50,18 @@ def create_task_transaction(db_session: Session, account: str, tx_type: str, amo
48
  prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH"
49
  tx_hash = calculate_tx_hash(tx_id, account, tx_type, amount, prev_hash)
50
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  new_tx = Transaction(
52
  tx_id=tx_id,
53
  account=account,
@@ -56,7 +70,11 @@ def create_task_transaction(db_session: Session, account: str, tx_type: str, amo
56
  related_account=related_account,
57
  item_id=task_id, # 复用 item_id 字段存储任务ID
58
  prev_hash=prev_hash,
59
- tx_hash=tx_hash
 
 
 
 
60
  )
61
  db_session.add(new_tx)
62
 
@@ -152,7 +170,8 @@ def check_and_update_expired_tasks(tasks_db, db_session=None):
152
  # 记录退款交易
153
  create_task_transaction(
154
  db_session, item["publisher"], "TASK_REFUND",
155
- item["amount"], task_id=item["task_id"]
 
156
  )
157
 
158
  refund_results.append(item)
@@ -411,7 +430,8 @@ async def create_task(task: TaskCreate, current_user: str = Depends(require_auth
411
  # 💳 记录冻结交易
412
  create_task_transaction(
413
  db_session, current_user, "TASK_FREEZE",
414
- -task.totalPrice, task_id=task_id
 
415
  )
416
  db_session.commit()
417
 
@@ -518,7 +538,8 @@ async def cancel_task(task_id: str, current_user: str = Depends(require_auth), d
518
  # 记录退款交易
519
  create_task_transaction(
520
  db_session, current_user, "TASK_CANCEL_REFUND",
521
- frozen_amount, task_id=task_id
 
522
  )
523
  db_session.commit()
524
  refund_success = True
@@ -654,10 +675,17 @@ async def assign_task(task_id: str, assignee: str, current_user: str = Depends(r
654
  # 订金从冻结金额中扣除(但还不给接单者,待任务完成后一起支付)
655
  wallet.frozen_balance -= deposit
656
 
 
 
 
 
 
657
  # 💳 记录订金支付交易
658
  create_task_transaction(
659
  db_session, current_user, "TASK_DEPOSIT",
660
- -deposit, related_account=assignee, task_id=task_id
 
 
661
  )
662
 
663
  # 更新任务状态
@@ -779,16 +807,27 @@ async def accept_task(task_id: str, is_accepted: bool, feedback: str = None, cur
779
 
780
  assignee_wallet.balance += total_price # 全款进入可用余额
781
 
 
 
 
 
 
 
 
782
  # 💳 记录交易流水
783
  # 1. 发布者支付尾款
784
  create_task_transaction(
785
  db_session, current_user, "TASK_PAYMENT",
786
- -remaining, related_account=assignee_account, task_id=task_id
 
 
787
  )
788
  # 2. 接单者收入
789
  create_task_transaction(
790
  db_session, assignee_account, "TASK_INCOME",
791
- total_price, related_account=current_user, task_id=task_id
 
 
792
  )
793
 
794
  task["status"] = "completed"
 
37
  data = f"{tx_id}{account}{tx_type}{amount}{prev_hash}"
38
  return hashlib.sha256(data.encode()).hexdigest()
39
 
40
+ def create_task_transaction(db_session: Session, account: str, tx_type: str, amount: int,
41
+ related_account: str = None, task_id: str = None,
42
+ task_title: str = None, related_user_name: str = None):
43
  """
44
  创建任务相关交易记录
45
  tx_type: TASK_FREEZE, TASK_DEPOSIT, TASK_PAYMENT, TASK_INCOME, TASK_REFUND
 
50
  prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH"
51
  tx_hash = calculate_tx_hash(tx_id, account, tx_type, amount, prev_hash)
52
 
53
+ # 根据 tx_type 构造 description
54
+ type_labels = {
55
+ "TASK_FREEZE": "任务冻结",
56
+ "TASK_DEPOSIT": "任务订金",
57
+ "TASK_PAYMENT": "任务尾款",
58
+ "TASK_INCOME": "任务收入",
59
+ "TASK_REFUND": "任务退款",
60
+ "TASK_CANCEL_REFUND": "任务取消退款",
61
+ }
62
+ label = type_labels.get(tx_type, tx_type)
63
+ desc = f"{label}: {task_title}" if task_title else label
64
+
65
  new_tx = Transaction(
66
  tx_id=tx_id,
67
  account=account,
 
70
  related_account=related_account,
71
  item_id=task_id, # 复用 item_id 字段存储任务ID
72
  prev_hash=prev_hash,
73
+ tx_hash=tx_hash,
74
+ description=desc,
75
+ item_title=task_title,
76
+ item_type="task",
77
+ related_user_name=related_user_name
78
  )
79
  db_session.add(new_tx)
80
 
 
170
  # 记录退款交易
171
  create_task_transaction(
172
  db_session, item["publisher"], "TASK_REFUND",
173
+ item["amount"], task_id=item["task_id"],
174
+ task_title=item["title"]
175
  )
176
 
177
  refund_results.append(item)
 
430
  # 💳 记录冻结交易
431
  create_task_transaction(
432
  db_session, current_user, "TASK_FREEZE",
433
+ -task.totalPrice, task_id=task_id,
434
+ task_title=task.title
435
  )
436
  db_session.commit()
437
 
 
538
  # 记录退款交易
539
  create_task_transaction(
540
  db_session, current_user, "TASK_CANCEL_REFUND",
541
+ frozen_amount, task_id=task_id,
542
+ task_title=task.get("title")
543
  )
544
  db_session.commit()
545
  refund_success = True
 
675
  # 订金从冻结金额中扣除(但还不给接单者,待任务完成后一起支付)
676
  wallet.frozen_balance -= deposit
677
 
678
+ # 获取接单者用户名
679
+ users_db = db.load_data("users.json", default_data={})
680
+ assignee_info = users_db.get(assignee, {})
681
+ assignee_name = assignee_info.get("name", assignee)
682
+
683
  # 💳 记录订金支付交易
684
  create_task_transaction(
685
  db_session, current_user, "TASK_DEPOSIT",
686
+ -deposit, related_account=assignee, task_id=task_id,
687
+ task_title=task.get("title"),
688
+ related_user_name=assignee_name
689
  )
690
 
691
  # 更新任务状态
 
807
 
808
  assignee_wallet.balance += total_price # 全款进入可用余额
809
 
810
+ # 获取双方用户名
811
+ users_db = db.load_data("users.json", default_data={})
812
+ publisher_info = users_db.get(current_user, {})
813
+ assignee_info = users_db.get(assignee_account, {})
814
+ publisher_name = publisher_info.get("name", current_user)
815
+ assignee_name = assignee_info.get("name", assignee_account)
816
+
817
  # 💳 记录交易流水
818
  # 1. 发布者支付尾款
819
  create_task_transaction(
820
  db_session, current_user, "TASK_PAYMENT",
821
+ -remaining, related_account=assignee_account, task_id=task_id,
822
+ task_title=task.get("title"),
823
+ related_user_name=assignee_name
824
  )
825
  # 2. 接单者收入
826
  create_task_transaction(
827
  db_session, assignee_account, "TASK_INCOME",
828
+ total_price, related_account=current_user, task_id=task_id,
829
+ task_title=task.get("title"),
830
+ related_user_name=publisher_name
831
  )
832
 
833
  task["status"] = "completed"
router_wallet.py CHANGED
@@ -161,7 +161,8 @@ async def alipay_notify(request: Request, db: Session = Depends(get_db)):
161
 
162
  new_tx = Transaction(
163
  tx_id=order_id, account=account, tx_type="RECHARGE", amount=amount,
164
- prev_hash=prev_hash, tx_hash=tx_hash
 
165
  )
166
  db.add(new_tx)
167
  db.commit()
@@ -210,7 +211,8 @@ async def check_order(order_id: str, account: str = None, db: Session = Depends(
210
 
211
  new_tx = Transaction(
212
  tx_id=order_id, account=account, tx_type="RECHARGE", amount=amount,
213
- prev_hash=prev_hash, tx_hash=tx_hash
 
214
  )
215
  db.add(new_tx)
216
  db.commit()
@@ -330,10 +332,19 @@ async def purchase_item(request: Request, req: PurchaseRequest, db: Session = De
330
  prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH"
331
  tx_hash = calculate_tx_hash(tx_id, req.account, "PURCHASE", -price, prev_hash)
332
 
 
 
 
 
 
333
  # 创建交易记录 (字段名为 related_account,与 models_sql.py 中 Transaction 模型保持一致)
334
  new_tx = Transaction(
335
  tx_id=tx_id, account=req.account, tx_type="PURCHASE", amount=-price,
336
- related_account=seller_account, item_id=req.item_id, prev_hash=prev_hash, tx_hash=tx_hash
 
 
 
 
337
  )
338
  db.add(new_tx)
339
  db.commit()
@@ -397,15 +408,44 @@ async def tip_user(request: Request, req: TipRequest, db: Session = Depends(get_
397
  prev_hash_sender = last_tx_sender.tx_hash if last_tx_sender else "GENESIS_HASH"
398
  prev_hash_target = last_tx_target.tx_hash if last_tx_target else "GENESIS_HASH"
399
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
400
  # 发送方交易记录 (字段名为 related_account,与 models_sql.py 中 Transaction 模型保持一致)
401
- tx_sender = Transaction(tx_id=tx_id_sender, account=req.sender_account, tx_type="TIP_OUT", amount=-req.amount,
402
- related_account=req.target_account, prev_hash=prev_hash_sender,
403
- tx_hash=calculate_tx_hash(tx_id_sender, req.sender_account, "TIP_OUT", -req.amount, prev_hash_sender))
 
 
 
 
 
 
404
 
405
  # 接收方交易记录
406
- tx_target = Transaction(tx_id=tx_id_target, account=req.target_account, tx_type="TIP_IN", amount=req.amount,
407
- related_account=req.sender_account, prev_hash=prev_hash_target,
408
- tx_hash=calculate_tx_hash(tx_id_target, req.target_account, "TIP_IN", req.amount, prev_hash_target))
 
 
 
 
 
 
409
 
410
  db.add(tx_sender)
411
  db.add(tx_target)
@@ -536,13 +576,18 @@ async def withdraw(request: Request, req: WithdrawRequest, db: Session = Depends
536
  prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH"
537
  tx_hash = calculate_tx_hash(tx_id, req.account, "WITHDRAW", -actual_withdraw, prev_hash)
538
 
 
 
 
 
539
  new_tx = Transaction(
540
  tx_id=tx_id, account=req.account, tx_type="WITHDRAW", amount=-actual_withdraw,
541
  alipay_account=req.alipayAccount,
542
  real_name=req.real_name,
543
  withdraw_status="pending",
544
  net_amount=net_amount, # 记录实际到账金额,用于解冻时准确扣减
545
- prev_hash=prev_hash, tx_hash=tx_hash
 
546
  )
547
  db.add(new_tx)
548
 
@@ -552,7 +597,8 @@ async def withdraw(request: Request, req: WithdrawRequest, db: Session = Depends
552
  fee_tx_hash = calculate_tx_hash(fee_tx_id, req.account, "WITHDRAW_FEE", -fee_amount, tx_hash)
553
  fee_tx = Transaction(
554
  tx_id=fee_tx_id, account=req.account, tx_type="WITHDRAW_FEE", amount=-fee_amount,
555
- prev_hash=tx_hash, tx_hash=fee_tx_hash
 
556
  )
557
  db.add(fee_tx)
558
 
@@ -604,14 +650,32 @@ async def get_transactions(
604
  # 格式化输出
605
  tx_list = []
606
  for tx in transactions:
607
- tx_list.append({
608
  "tx_id": tx.tx_id,
609
  "tx_type": tx.tx_type,
610
  "amount": tx.amount,
611
  "related_account": tx.related_account,
612
  "item_id": tx.item_id,
613
- "created_at": tx.created_at.isoformat() if tx.created_at else None
614
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
615
 
616
  return {
617
  "status": "success",
@@ -828,6 +892,11 @@ async def refund_purchase(request: Request, account: str, item_id: str, db: Sess
828
  )
829
  db.add(new_refund)
830
 
 
 
 
 
 
831
  # 记录退款交易
832
  tx_id = f"REFUND_{int(time.time())}_{uuid.uuid4().hex[:6]}"
833
  last_tx = db.query(Transaction).filter(Transaction.account == account).order_by(Transaction.created_at.desc()).first()
@@ -836,7 +905,11 @@ async def refund_purchase(request: Request, account: str, item_id: str, db: Sess
836
 
837
  new_tx = Transaction(
838
  tx_id=tx_id, account=account, tx_type="REFUND", amount=refund_amount,
839
- related_account=seller_account, item_id=item_id, prev_hash=prev_hash, tx_hash=tx_hash
 
 
 
 
840
  )
841
  db.add(new_tx)
842
  db.commit()
@@ -938,4 +1011,7 @@ async def complete_withdrawal(
938
 
939
  db.commit()
940
 
 
 
 
941
  return {"status": "success", "message": f"提现 {tx_id} 已确认打款完成"}
 
161
 
162
  new_tx = Transaction(
163
  tx_id=order_id, account=account, tx_type="RECHARGE", amount=amount,
164
+ prev_hash=prev_hash, tx_hash=tx_hash,
165
+ description="支付宝充值"
166
  )
167
  db.add(new_tx)
168
  db.commit()
 
211
 
212
  new_tx = Transaction(
213
  tx_id=order_id, account=account, tx_type="RECHARGE", amount=amount,
214
+ prev_hash=prev_hash, tx_hash=tx_hash,
215
+ description="支付宝充值"
216
  )
217
  db.add(new_tx)
218
  db.commit()
 
332
  prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH"
333
  tx_hash = calculate_tx_hash(tx_id, req.account, "PURCHASE", -price, prev_hash)
334
 
335
+ # 获取卖家用户名
336
+ users_db = json_db.load_data("users.json", default_data={})
337
+ seller_info = users_db.get(seller_account, {})
338
+ seller_user_name = seller_info.get("name", seller_account)
339
+
340
  # 创建交易记录 (字段名为 related_account,与 models_sql.py 中 Transaction 模型保持一致)
341
  new_tx = Transaction(
342
  tx_id=tx_id, account=req.account, tx_type="PURCHASE", amount=-price,
343
+ related_account=seller_account, item_id=req.item_id, prev_hash=prev_hash, tx_hash=tx_hash,
344
+ description=f"购买 {item.get('title', '未知资源')}",
345
+ item_title=item.get('title', ''),
346
+ item_type=item.get('type', ''),
347
+ related_user_name=seller_user_name
348
  )
349
  db.add(new_tx)
350
  db.commit()
 
408
  prev_hash_sender = last_tx_sender.tx_hash if last_tx_sender else "GENESIS_HASH"
409
  prev_hash_target = last_tx_target.tx_hash if last_tx_target else "GENESIS_HASH"
410
 
411
+ # 获取用户名和资源信息
412
+ users_db = json_db.load_data("users.json", default_data={})
413
+ target_user_info = users_db.get(req.target_account, {})
414
+ sender_user_info = users_db.get(req.sender_account, {})
415
+ target_user_name = target_user_info.get("name", req.target_account)
416
+ sender_user_name = sender_user_info.get("name", req.sender_account)
417
+
418
+ # 如果有关联资源,获取资源信息
419
+ item_title = None
420
+ item_type = None
421
+ if req.item_id:
422
+ items_db = json_db.load_data("items.json", default_data=[])
423
+ item = next((i for i in items_db if i["id"] == req.item_id), None)
424
+ if item:
425
+ item_title = item.get("title")
426
+ item_type = item.get("type")
427
+
428
  # 发送方交易记录 (字段名为 related_account,与 models_sql.py 中 Transaction 模型保持一致)
429
+ tx_sender = Transaction(
430
+ tx_id=tx_id_sender, account=req.sender_account, tx_type="TIP_OUT", amount=-req.amount,
431
+ related_account=req.target_account, prev_hash=prev_hash_sender,
432
+ tx_hash=calculate_tx_hash(tx_id_sender, req.sender_account, "TIP_OUT", -req.amount, prev_hash_sender),
433
+ description=f"打赏给 {target_user_name}" + (f" 的 {item_title}" if item_title else ""),
434
+ item_title=item_title,
435
+ item_type=item_type,
436
+ related_user_name=target_user_name
437
+ )
438
 
439
  # 接收方交易记录
440
+ tx_target = Transaction(
441
+ tx_id=tx_id_target, account=req.target_account, tx_type="TIP_IN", amount=req.amount,
442
+ related_account=req.sender_account, prev_hash=prev_hash_target,
443
+ tx_hash=calculate_tx_hash(tx_id_target, req.target_account, "TIP_IN", req.amount, prev_hash_target),
444
+ description=f"收到 {sender_user_name} 的打赏" + (f" ({item_title})" if item_title else ""),
445
+ item_title=item_title,
446
+ item_type=item_type,
447
+ related_user_name=sender_user_name if not req.is_anonymous else "匿名用户"
448
+ )
449
 
450
  db.add(tx_sender)
451
  db.add(tx_target)
 
576
  prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH"
577
  tx_hash = calculate_tx_hash(tx_id, req.account, "WITHDRAW", -actual_withdraw, prev_hash)
578
 
579
+ # 脱敏支付宝账号和姓名
580
+ masked_alipay = req.alipayAccount[:3] + "****" + req.alipayAccount[-4:] if len(req.alipayAccount) > 7 else req.alipayAccount
581
+ masked_name = req.real_name[0] + "*" * (len(req.real_name) - 1) if req.real_name else ""
582
+
583
  new_tx = Transaction(
584
  tx_id=tx_id, account=req.account, tx_type="WITHDRAW", amount=-actual_withdraw,
585
  alipay_account=req.alipayAccount,
586
  real_name=req.real_name,
587
  withdraw_status="pending",
588
  net_amount=net_amount, # 记录实际到账金额,用于解冻时准确扣减
589
+ prev_hash=prev_hash, tx_hash=tx_hash,
590
+ description=f"提现到支付宝 {masked_alipay} ({masked_name})"
591
  )
592
  db.add(new_tx)
593
 
 
597
  fee_tx_hash = calculate_tx_hash(fee_tx_id, req.account, "WITHDRAW_FEE", -fee_amount, tx_hash)
598
  fee_tx = Transaction(
599
  tx_id=fee_tx_id, account=req.account, tx_type="WITHDRAW_FEE", amount=-fee_amount,
600
+ prev_hash=tx_hash, tx_hash=fee_tx_hash,
601
+ description="提现手续费"
602
  )
603
  db.add(fee_tx)
604
 
 
650
  # 格式化输出
651
  tx_list = []
652
  for tx in transactions:
653
+ tx_data = {
654
  "tx_id": tx.tx_id,
655
  "tx_type": tx.tx_type,
656
  "amount": tx.amount,
657
  "related_account": tx.related_account,
658
  "item_id": tx.item_id,
659
+ "created_at": tx.created_at.isoformat() if tx.created_at else None,
660
+ # 新增字段
661
+ "description": tx.description,
662
+ "item_title": tx.item_title,
663
+ "item_type": tx.item_type,
664
+ "related_user_name": tx.related_user_name,
665
+ }
666
+
667
+ # 提现类型额外返回脱敏信息
668
+ if tx.tx_type == "WITHDRAW":
669
+ # 脱敏支付宝账号
670
+ if tx.alipay_account:
671
+ a = tx.alipay_account
672
+ tx_data["alipay_account"] = a[:3] + "****" + a[-4:] if len(a) > 7 else a
673
+ if tx.real_name:
674
+ tx_data["real_name"] = tx.real_name[0] + "*" * (len(tx.real_name) - 1)
675
+ tx_data["withdraw_status"] = tx.withdraw_status
676
+ tx_data["net_amount"] = tx.net_amount
677
+
678
+ tx_list.append(tx_data)
679
 
680
  return {
681
  "status": "success",
 
892
  )
893
  db.add(new_refund)
894
 
895
+ # 获取卖家用户名
896
+ users_db = json_db.load_data("users.json", default_data={})
897
+ seller_info = users_db.get(seller_account, {})
898
+ seller_user_name = seller_info.get("name", seller_account)
899
+
900
  # 记录退款交易
901
  tx_id = f"REFUND_{int(time.time())}_{uuid.uuid4().hex[:6]}"
902
  last_tx = db.query(Transaction).filter(Transaction.account == account).order_by(Transaction.created_at.desc()).first()
 
905
 
906
  new_tx = Transaction(
907
  tx_id=tx_id, account=account, tx_type="REFUND", amount=refund_amount,
908
+ related_account=seller_account, item_id=item_id, prev_hash=prev_hash, tx_hash=tx_hash,
909
+ description=f"退款: {item.get('title', '未知资源')}",
910
+ item_title=item.get('title', ''),
911
+ item_type=item.get('type', ''),
912
+ related_user_name=seller_user_name
913
  )
914
  db.add(new_tx)
915
  db.commit()
 
1011
 
1012
  db.commit()
1013
 
1014
+ # 📝 P2优化:提现完成审计日志
1015
+ logger.info(f"WITHDRAW_COMPLETED | admin={current_user} | tx_id={tx_id} | account={tx.account} | amount={tx.amount} | net_amount={tx.net_amount} | order_id={req.payment_order_id}")
1016
+
1017
  return {"status": "success", "message": f"提现 {tx_id} 已确认打款完成"}