mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-26 02:57:59 +00:00
feat(p2p): implement OKX-style internal ledger escrow system
Phase 5 implementation - Internal Ledger Escrow (OKX Model): - No blockchain transactions during P2P trades - Blockchain tx only at deposit/withdraw - Fast and fee-free P2P trading Database: - Add user_internal_balances table - Add p2p_deposit_withdraw_requests table - Add p2p_balance_transactions table - Add lock_escrow_internal(), release_escrow_internal() functions - Add process_deposit(), request_withdraw() functions UI Components: - Add InternalBalanceCard showing available/locked balances - Add DepositModal for crypto deposits to P2P balance - Add WithdrawModal for withdrawals from P2P balance - Integrate balance card into P2PDashboard Backend: - Add process-withdrawal Edge Function - Add verify-deposit Edge Function Updated p2p-fiat.ts: - createFiatOffer() uses internal balance lock - confirmPaymentReceived() uses internal balance transfer - Add internal balance management functions
This commit is contained in:
@@ -85,7 +85,502 @@ Bu döküman, PezkuwiChain P2P trading platformunun OKX seviyesine çıkarılmas
|
||||
- AdList.tsx filter integration complete
|
||||
|
||||
### What's Remaining
|
||||
1. **Blockchain Integration**: Actual HEZ transfers to/from platform wallet (backend service needed)
|
||||
1. **Phase 5**: OKX-Style Internal Ledger Escrow System
|
||||
|
||||
---
|
||||
|
||||
# PHASE 5: OKX-Style Internal Ledger Escrow
|
||||
|
||||
**Goal**: Implement OKX-style escrow where blockchain transactions only occur at deposit/withdraw
|
||||
|
||||
**Duration**: 1 week
|
||||
|
||||
**Prerequisites**: Phase 4 completed
|
||||
|
||||
**Reference Documentation**:
|
||||
- `docs/p2p/P2P-USER-AGREEMENT.md` - User agreement (created 2025-12-11)
|
||||
- `docs/p2p/P2P-TRADING-GUIDE.md` - Trading guide (created 2025-12-11)
|
||||
- `docs/p2p/WHAT-IS-P2P.md` - P2P explainer (created 2025-12-11)
|
||||
|
||||
## OKX Escrow Model (Research Summary)
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ OKX ESCROW MODEL │
|
||||
├────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ DEPOSIT (Blockchain TX) │
|
||||
│ ════════════════════════ │
|
||||
│ User Wallet ───[blockchain tx]──→ Platform Wallet │
|
||||
│ (Internal Balance: +amount) │
|
||||
│ │
|
||||
│ P2P TRADE (Database Only - NO blockchain) │
|
||||
│ ═════════════════════════════════════════ │
|
||||
│ Seller Internal Balance ──→ Escrow Lock (DB update) │
|
||||
│ Escrow Lock ──→ Buyer Internal Balance (DB update) │
|
||||
│ │
|
||||
│ WITHDRAW (Blockchain TX) │
|
||||
│ ═════════════════════════ │
|
||||
│ Internal Balance: -amount │
|
||||
│ Platform Wallet ───[blockchain tx]──→ User External Wallet │
|
||||
│ │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Key Insights from OKX**:
|
||||
- OKX uses **centralized internal ledger** - NO blockchain transactions during P2P trades
|
||||
- Crypto is locked in OKX internal escrow (database), released to buyer's internal account
|
||||
- Blockchain transactions ONLY occur at deposit/withdraw from exchange
|
||||
- OKX moderators handle disputes, send crypto to deserving party
|
||||
- "Release Crypto" = instruction to update internal database balances
|
||||
- Zero trading fees for P2P
|
||||
|
||||
## 5.1 Database Schema Updates
|
||||
|
||||
### New Table: user_internal_balances
|
||||
```sql
|
||||
-- User internal balances (like exchange balances)
|
||||
CREATE TABLE user_internal_balances (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES auth.users(id),
|
||||
token TEXT NOT NULL, -- 'HEZ', 'PEZ'
|
||||
available_balance DECIMAL(20, 12) NOT NULL DEFAULT 0,
|
||||
locked_balance DECIMAL(20, 12) NOT NULL DEFAULT 0, -- locked in escrow/pending
|
||||
total_deposited DECIMAL(20, 12) NOT NULL DEFAULT 0,
|
||||
total_withdrawn DECIMAL(20, 12) NOT NULL DEFAULT 0,
|
||||
last_deposit_at TIMESTAMPTZ,
|
||||
last_withdraw_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
UNIQUE(user_id, token)
|
||||
);
|
||||
|
||||
-- Deposit/Withdraw requests
|
||||
CREATE TABLE p2p_deposit_withdraw_requests (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES auth.users(id),
|
||||
request_type TEXT NOT NULL CHECK (request_type IN ('deposit', 'withdraw')),
|
||||
token TEXT NOT NULL,
|
||||
amount DECIMAL(20, 12) NOT NULL,
|
||||
wallet_address TEXT NOT NULL,
|
||||
blockchain_tx_hash TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'processing', 'completed', 'failed', 'cancelled')),
|
||||
processed_at TIMESTAMPTZ,
|
||||
processed_by UUID REFERENCES auth.users(id), -- admin/system
|
||||
error_message TEXT,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Index for quick lookups
|
||||
CREATE INDEX idx_internal_balances_user ON user_internal_balances(user_id);
|
||||
CREATE INDEX idx_deposit_withdraw_status ON p2p_deposit_withdraw_requests(status);
|
||||
CREATE INDEX idx_deposit_withdraw_user ON p2p_deposit_withdraw_requests(user_id);
|
||||
```
|
||||
|
||||
### Updated Functions
|
||||
```sql
|
||||
-- Atomic function for internal balance escrow lock (P2P trade acceptance)
|
||||
CREATE OR REPLACE FUNCTION lock_escrow_internal(
|
||||
p_user_id UUID,
|
||||
p_token TEXT,
|
||||
p_amount DECIMAL(20, 12)
|
||||
) RETURNS JSON AS $$
|
||||
DECLARE
|
||||
v_balance RECORD;
|
||||
BEGIN
|
||||
-- Lock user's balance row
|
||||
SELECT * INTO v_balance
|
||||
FROM user_internal_balances
|
||||
WHERE user_id = p_user_id AND token = p_token
|
||||
FOR UPDATE;
|
||||
|
||||
IF v_balance IS NULL THEN
|
||||
RETURN json_build_object('success', false, 'error', 'No balance found for this token');
|
||||
END IF;
|
||||
|
||||
IF v_balance.available_balance < p_amount THEN
|
||||
RETURN json_build_object('success', false, 'error', 'Insufficient balance. Available: ' || v_balance.available_balance);
|
||||
END IF;
|
||||
|
||||
-- Move from available to locked
|
||||
UPDATE user_internal_balances
|
||||
SET
|
||||
available_balance = available_balance - p_amount,
|
||||
locked_balance = locked_balance + p_amount,
|
||||
updated_at = NOW()
|
||||
WHERE user_id = p_user_id AND token = p_token;
|
||||
|
||||
RETURN json_build_object('success', true, 'locked_amount', p_amount);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Atomic function for escrow release (trade completion)
|
||||
CREATE OR REPLACE FUNCTION release_escrow_internal(
|
||||
p_from_user_id UUID,
|
||||
p_to_user_id UUID,
|
||||
p_token TEXT,
|
||||
p_amount DECIMAL(20, 12)
|
||||
) RETURNS JSON AS $$
|
||||
DECLARE
|
||||
v_from_balance RECORD;
|
||||
BEGIN
|
||||
-- Lock seller's balance row
|
||||
SELECT * INTO v_from_balance
|
||||
FROM user_internal_balances
|
||||
WHERE user_id = p_from_user_id AND token = p_token
|
||||
FOR UPDATE;
|
||||
|
||||
IF v_from_balance IS NULL OR v_from_balance.locked_balance < p_amount THEN
|
||||
RETURN json_build_object('success', false, 'error', 'Insufficient locked balance');
|
||||
END IF;
|
||||
|
||||
-- Reduce seller's locked balance
|
||||
UPDATE user_internal_balances
|
||||
SET
|
||||
locked_balance = locked_balance - p_amount,
|
||||
updated_at = NOW()
|
||||
WHERE user_id = p_from_user_id AND token = p_token;
|
||||
|
||||
-- Increase buyer's available balance (upsert)
|
||||
INSERT INTO user_internal_balances (user_id, token, available_balance)
|
||||
VALUES (p_to_user_id, p_token, p_amount)
|
||||
ON CONFLICT (user_id, token)
|
||||
DO UPDATE SET
|
||||
available_balance = user_internal_balances.available_balance + p_amount,
|
||||
updated_at = NOW();
|
||||
|
||||
RETURN json_build_object('success', true, 'transferred_amount', p_amount);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Atomic function for escrow refund (trade cancellation)
|
||||
CREATE OR REPLACE FUNCTION refund_escrow_internal(
|
||||
p_user_id UUID,
|
||||
p_token TEXT,
|
||||
p_amount DECIMAL(20, 12)
|
||||
) RETURNS JSON AS $$
|
||||
BEGIN
|
||||
-- Move from locked back to available
|
||||
UPDATE user_internal_balances
|
||||
SET
|
||||
locked_balance = locked_balance - p_amount,
|
||||
available_balance = available_balance + p_amount,
|
||||
updated_at = NOW()
|
||||
WHERE user_id = p_user_id AND token = p_token
|
||||
AND locked_balance >= p_amount;
|
||||
|
||||
IF NOT FOUND THEN
|
||||
RETURN json_build_object('success', false, 'error', 'Insufficient locked balance for refund');
|
||||
END IF;
|
||||
|
||||
RETURN json_build_object('success', true, 'refunded_amount', p_amount);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
```
|
||||
|
||||
### Checklist 5.1
|
||||
- [ ] Create `user_internal_balances` table
|
||||
- [ ] Create `p2p_deposit_withdraw_requests` table
|
||||
- [ ] Create `lock_escrow_internal()` function
|
||||
- [ ] Create `release_escrow_internal()` function
|
||||
- [ ] Create `refund_escrow_internal()` function
|
||||
- [ ] Configure RLS policies
|
||||
- [ ] Deploy migration to Supabase
|
||||
|
||||
---
|
||||
|
||||
## 5.2 Backend Withdrawal Service
|
||||
|
||||
**Purpose**: Process blockchain transactions for deposits/withdrawals
|
||||
|
||||
### Architecture
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────┐
|
||||
│ WITHDRAWAL SERVICE │
|
||||
├────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ [User clicks Withdraw] │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ [Create withdraw request in DB] │
|
||||
│ status: 'pending' │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ [Backend service picks up pending requests] │
|
||||
│ (cron job or queue) │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ [Sign and send blockchain transaction] │
|
||||
│ using platform private key (secure environment) │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ [Update request status: 'completed'] │
|
||||
│ [Deduct from internal balance] │
|
||||
│ │
|
||||
└────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Implementation Options
|
||||
|
||||
**Option A: Supabase Edge Function** (Recommended for MVP)
|
||||
- Easy to deploy
|
||||
- Access to Supabase DB
|
||||
- Can use environment variables for private key
|
||||
- Limitations: 150s timeout, no persistent connections
|
||||
|
||||
**Option B: Node.js Backend Service**
|
||||
- Full control
|
||||
- Can run as systemd service on VPS
|
||||
- Better for high volume
|
||||
- More complex setup
|
||||
|
||||
### Supabase Edge Function Code (Option A)
|
||||
```typescript
|
||||
// supabase/functions/process-withdrawals/index.ts
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api'
|
||||
|
||||
const PLATFORM_SEED = Deno.env.get('PLATFORM_WALLET_SEED')!
|
||||
const SUPABASE_URL = Deno.env.get('SUPABASE_URL')!
|
||||
const SUPABASE_SERVICE_KEY = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
|
||||
const RPC_ENDPOINT = 'wss://rpc.pezkuwichain.io:9944'
|
||||
|
||||
Deno.serve(async (req) => {
|
||||
const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_KEY)
|
||||
|
||||
// Get pending withdrawal requests
|
||||
const { data: pendingRequests, error } = await supabase
|
||||
.from('p2p_deposit_withdraw_requests')
|
||||
.select('*')
|
||||
.eq('request_type', 'withdraw')
|
||||
.eq('status', 'pending')
|
||||
.limit(10)
|
||||
|
||||
if (error || !pendingRequests?.length) {
|
||||
return new Response(JSON.stringify({ processed: 0 }))
|
||||
}
|
||||
|
||||
// Connect to blockchain
|
||||
const provider = new WsProvider(RPC_ENDPOINT)
|
||||
const api = await ApiPromise.create({ provider })
|
||||
const keyring = new Keyring({ type: 'sr25519' })
|
||||
const platformAccount = keyring.addFromUri(PLATFORM_SEED)
|
||||
|
||||
let processed = 0
|
||||
|
||||
for (const request of pendingRequests) {
|
||||
try {
|
||||
// Mark as processing
|
||||
await supabase
|
||||
.from('p2p_deposit_withdraw_requests')
|
||||
.update({ status: 'processing' })
|
||||
.eq('id', request.id)
|
||||
|
||||
// Send blockchain transaction
|
||||
const amount = BigInt(request.amount * 1e12)
|
||||
const tx = api.tx.balances.transfer(request.wallet_address, amount)
|
||||
const hash = await tx.signAndSend(platformAccount)
|
||||
|
||||
// Update status to completed
|
||||
await supabase
|
||||
.from('p2p_deposit_withdraw_requests')
|
||||
.update({
|
||||
status: 'completed',
|
||||
blockchain_tx_hash: hash.toString(),
|
||||
processed_at: new Date().toISOString()
|
||||
})
|
||||
.eq('id', request.id)
|
||||
|
||||
// Deduct from internal balance
|
||||
await supabase
|
||||
.from('user_internal_balances')
|
||||
.update({
|
||||
available_balance: supabase.raw('available_balance - ?', [request.amount]),
|
||||
total_withdrawn: supabase.raw('total_withdrawn + ?', [request.amount]),
|
||||
last_withdraw_at: new Date().toISOString()
|
||||
})
|
||||
.eq('user_id', request.user_id)
|
||||
.eq('token', request.token)
|
||||
|
||||
processed++
|
||||
} catch (err) {
|
||||
// Mark as failed
|
||||
await supabase
|
||||
.from('p2p_deposit_withdraw_requests')
|
||||
.update({
|
||||
status: 'failed',
|
||||
error_message: err.message
|
||||
})
|
||||
.eq('id', request.id)
|
||||
}
|
||||
}
|
||||
|
||||
await api.disconnect()
|
||||
|
||||
return new Response(JSON.stringify({ processed }))
|
||||
})
|
||||
```
|
||||
|
||||
### Checklist 5.2
|
||||
- [ ] Choose implementation option (Edge Function vs Node.js)
|
||||
- [ ] Create Supabase Edge Function for withdrawals
|
||||
- [ ] Store platform private key securely (env variable)
|
||||
- [ ] Test withdrawal flow on testnet
|
||||
- [ ] Set up cron job to trigger function periodically
|
||||
- [ ] Add monitoring and alerts
|
||||
|
||||
---
|
||||
|
||||
## 5.3 Deposit Flow (User → Platform)
|
||||
|
||||
### User Flow
|
||||
1. User clicks "Deposit" in app
|
||||
2. App shows platform wallet address + QR code
|
||||
3. User sends crypto from external wallet
|
||||
4. Backend service monitors for incoming transactions
|
||||
5. When confirmed, credit user's internal balance
|
||||
|
||||
### Monitoring Options
|
||||
|
||||
**Option A: Supabase Edge Function + Indexer**
|
||||
- Poll blockchain periodically for new deposits
|
||||
|
||||
**Option B: Substrate Event Listener**
|
||||
- Listen to Transfer events in real-time
|
||||
- More complex but immediate
|
||||
|
||||
### Simplified Deposit (Manual Confirmation)
|
||||
For MVP, users can manually confirm deposits:
|
||||
1. User sends crypto
|
||||
2. User enters TX hash in app
|
||||
3. Backend verifies TX on-chain
|
||||
4. Credits internal balance
|
||||
|
||||
### Checklist 5.3
|
||||
- [ ] Create deposit UI with platform wallet address
|
||||
- [ ] Add QR code generation
|
||||
- [ ] Create deposit verification endpoint
|
||||
- [ ] Credit internal balance after verification
|
||||
- [ ] Add deposit history view
|
||||
|
||||
---
|
||||
|
||||
## 5.4 Updated p2p-fiat.ts Functions
|
||||
|
||||
### Changes Required
|
||||
|
||||
1. **createFiatOffer()**: Lock from internal balance instead of blockchain tx
|
||||
2. **acceptFiatOffer()**: Already atomic, no changes needed
|
||||
3. **confirmPaymentReceived()**: Release via internal ledger, not blockchain tx
|
||||
4. **cancelTrade()**: Refund to internal balance
|
||||
|
||||
### Updated Function Signatures
|
||||
```typescript
|
||||
// NO blockchain tx - just internal balance update
|
||||
export async function createFiatOffer(params: CreateOfferParams): Promise<string> {
|
||||
// 1. Lock seller's internal balance (DB call)
|
||||
const { data: lockResult } = await supabase.rpc('lock_escrow_internal', {
|
||||
p_user_id: userId,
|
||||
p_token: token,
|
||||
p_amount: amountCrypto
|
||||
});
|
||||
|
||||
if (!lockResult.success) throw new Error(lockResult.error);
|
||||
|
||||
// 2. Create offer record (NO blockchain tx needed!)
|
||||
// ... rest same as before
|
||||
}
|
||||
|
||||
// NO blockchain tx - just internal balance transfer
|
||||
export async function confirmPaymentReceived(tradeId: string): Promise<void> {
|
||||
// 1. Get trade details
|
||||
const trade = await getTradeById(tradeId);
|
||||
|
||||
// 2. Release escrow internally (DB call)
|
||||
const { data: releaseResult } = await supabase.rpc('release_escrow_internal', {
|
||||
p_from_user_id: trade.seller_id,
|
||||
p_to_user_id: trade.buyer_id,
|
||||
p_token: trade.token,
|
||||
p_amount: trade.crypto_amount
|
||||
});
|
||||
|
||||
if (!releaseResult.success) throw new Error(releaseResult.error);
|
||||
|
||||
// 3. Update trade status
|
||||
// ... same as before
|
||||
}
|
||||
```
|
||||
|
||||
### Checklist 5.4
|
||||
- [ ] Update `createFiatOffer()` - use internal balance lock
|
||||
- [ ] Update `confirmPaymentReceived()` - use internal release
|
||||
- [ ] Update `cancelTrade()` - use internal refund
|
||||
- [ ] Remove `signAndSendWithPlatformKey()` placeholder
|
||||
- [ ] Add `getInternalBalance()` function
|
||||
- [ ] Add `requestWithdraw()` function
|
||||
- [ ] Add `requestDeposit()` function
|
||||
- [ ] Test full flow with internal balances
|
||||
|
||||
---
|
||||
|
||||
## 5.5 UI Components
|
||||
|
||||
### New Components Needed
|
||||
|
||||
1. **InternalBalanceCard.tsx** - Show available/locked balances
|
||||
2. **DepositModal.tsx** - Show platform address, QR code, verify deposit
|
||||
3. **WithdrawModal.tsx** - Enter amount, wallet address, submit request
|
||||
4. **TransactionHistory.tsx** - List deposits/withdrawals
|
||||
|
||||
### Checklist 5.5
|
||||
- [ ] Create InternalBalanceCard.tsx
|
||||
- [ ] Create DepositModal.tsx
|
||||
- [ ] Create WithdrawModal.tsx
|
||||
- [ ] Create TransactionHistory.tsx
|
||||
- [ ] Integrate into P2PDashboard
|
||||
- [ ] Show balance in header
|
||||
|
||||
---
|
||||
|
||||
## Phase 5 Final Checklist
|
||||
|
||||
### Database
|
||||
- [ ] `user_internal_balances` table created
|
||||
- [ ] `p2p_deposit_withdraw_requests` table created
|
||||
- [ ] All escrow functions created (lock/release/refund)
|
||||
- [ ] RLS policies configured
|
||||
- [ ] Migration deployed to Supabase
|
||||
|
||||
### Backend Service
|
||||
- [ ] Withdrawal processing Edge Function created
|
||||
- [ ] Platform private key stored securely
|
||||
- [ ] Cron job configured for withdrawal processing
|
||||
- [ ] Deposit verification endpoint created
|
||||
|
||||
### Frontend
|
||||
- [ ] Updated p2p-fiat.ts functions (no blockchain during trade)
|
||||
- [ ] InternalBalanceCard component
|
||||
- [ ] DepositModal component
|
||||
- [ ] WithdrawModal component
|
||||
- [ ] TransactionHistory component
|
||||
|
||||
### Testing
|
||||
- [ ] Deposit HEZ to internal balance
|
||||
- [ ] Create P2P offer (locks internal balance)
|
||||
- [ ] Complete P2P trade (internal transfer)
|
||||
- [ ] Cancel P2P trade (internal refund)
|
||||
- [ ] Withdraw HEZ to external wallet
|
||||
- [ ] Full end-to-end flow works
|
||||
|
||||
### Security
|
||||
- [ ] Platform private key in secure environment
|
||||
- [ ] Rate limiting on withdrawals
|
||||
- [ ] Withdrawal amount limits
|
||||
- [ ] Admin approval for large withdrawals
|
||||
- [ ] Audit logging for all balance changes
|
||||
|
||||
**Phase 5 Status: 0% - Not Started**
|
||||
|
||||
---
|
||||
|
||||
|
||||
+343
-86
@@ -1,8 +1,13 @@
|
||||
/**
|
||||
* P2P Fiat Trading System - Production Grade
|
||||
*
|
||||
* P2P Fiat Trading System - Production Grade (OKX-Style Internal Ledger)
|
||||
*
|
||||
* @module p2p-fiat
|
||||
* @description Enterprise-level P2P fiat-to-crypto trading with escrow
|
||||
* @description Enterprise-level P2P fiat-to-crypto trading with internal ledger escrow
|
||||
*
|
||||
* OKX Model Implementation:
|
||||
* - Blockchain transactions ONLY occur at deposit/withdraw
|
||||
* - P2P trades use internal database balance transfers
|
||||
* - No blockchain transactions during actual P2P trading
|
||||
*/
|
||||
|
||||
import { ApiPromise } from '@polkadot/api';
|
||||
@@ -100,8 +105,6 @@ export interface P2PReputation {
|
||||
}
|
||||
|
||||
export interface CreateOfferParams {
|
||||
api: ApiPromise;
|
||||
account: InjectedAccountWithMeta;
|
||||
token: CryptoToken;
|
||||
amountCrypto: number;
|
||||
fiatCurrency: FiatCurrency;
|
||||
@@ -111,13 +114,55 @@ export interface CreateOfferParams {
|
||||
timeLimitMinutes?: number;
|
||||
minOrderAmount?: number;
|
||||
maxOrderAmount?: number;
|
||||
// NOTE: api and account no longer needed - uses internal ledger
|
||||
}
|
||||
|
||||
export interface AcceptOfferParams {
|
||||
api: ApiPromise;
|
||||
account: InjectedAccountWithMeta;
|
||||
offerId: string;
|
||||
buyerWallet: string;
|
||||
amount?: number; // If partial order
|
||||
// NOTE: api and account no longer needed - uses internal ledger
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// INTERNAL BALANCE TYPES (OKX-Style)
|
||||
// =====================================================
|
||||
|
||||
export interface InternalBalance {
|
||||
token: CryptoToken;
|
||||
available_balance: number;
|
||||
locked_balance: number;
|
||||
total_balance: number;
|
||||
total_deposited: number;
|
||||
total_withdrawn: number;
|
||||
}
|
||||
|
||||
export interface DepositWithdrawRequest {
|
||||
id: string;
|
||||
user_id: string;
|
||||
request_type: 'deposit' | 'withdraw';
|
||||
token: CryptoToken;
|
||||
amount: number;
|
||||
wallet_address: string;
|
||||
blockchain_tx_hash?: string;
|
||||
status: 'pending' | 'processing' | 'completed' | 'failed' | 'cancelled';
|
||||
processed_at?: string;
|
||||
error_message?: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface BalanceTransaction {
|
||||
id: string;
|
||||
user_id: string;
|
||||
token: string;
|
||||
transaction_type: 'deposit' | 'withdraw' | 'escrow_lock' | 'escrow_release' | 'escrow_refund' | 'trade_receive' | 'admin_adjustment';
|
||||
amount: number;
|
||||
balance_before: number;
|
||||
balance_after: number;
|
||||
reference_type?: string;
|
||||
reference_id?: string;
|
||||
description?: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
@@ -222,17 +267,17 @@ function decryptPaymentDetails(encrypted: string): Record<string, string> {
|
||||
// =====================================================
|
||||
|
||||
/**
|
||||
* Create a new P2P fiat offer
|
||||
*
|
||||
* Create a new P2P fiat offer (OKX-Style Internal Ledger)
|
||||
*
|
||||
* Steps:
|
||||
* 1. Lock crypto in platform escrow (blockchain tx)
|
||||
* 1. Lock crypto from internal balance (NO blockchain tx)
|
||||
* 2. Create offer record in Supabase
|
||||
* 3. Update escrow balance tracking
|
||||
* 3. Update escrow tracking
|
||||
*
|
||||
* NOTE: Blockchain transactions only occur at deposit/withdraw
|
||||
*/
|
||||
export async function createFiatOffer(params: CreateOfferParams): Promise<string> {
|
||||
const {
|
||||
api,
|
||||
account,
|
||||
token,
|
||||
amountCrypto,
|
||||
fiatCurrency,
|
||||
@@ -245,24 +290,30 @@ export async function createFiatOffer(params: CreateOfferParams): Promise<string
|
||||
} = params;
|
||||
|
||||
try {
|
||||
// 1. Lock crypto in escrow (blockchain)
|
||||
toast.info('Locking crypto in escrow...');
|
||||
|
||||
const amount = BigInt(amountCrypto * 1e12); // Convert to Planck
|
||||
|
||||
let txHash: string;
|
||||
if (token === 'HEZ') {
|
||||
// Native token transfer
|
||||
const tx = api.tx.balances.transfer(PLATFORM_ESCROW_ADDRESS, amount);
|
||||
txHash = await signAndSendTx(api, account, tx);
|
||||
} else {
|
||||
// Asset transfer (PEZ)
|
||||
const assetId = ASSET_IDS[token];
|
||||
const tx = api.tx.assets.transfer(assetId, PLATFORM_ESCROW_ADDRESS, amount);
|
||||
txHash = await signAndSendTx(api, account, tx);
|
||||
// Get current user
|
||||
const { data: userData } = await supabase.auth.getUser();
|
||||
const userId = userData.user?.id;
|
||||
if (!userId) throw new Error('Not authenticated');
|
||||
|
||||
toast.info('Locking crypto from your balance...');
|
||||
|
||||
// 1. Lock crypto from internal balance (NO blockchain tx!)
|
||||
const { data: lockResult, error: lockError } = await supabase.rpc('lock_escrow_internal', {
|
||||
p_user_id: userId,
|
||||
p_token: token,
|
||||
p_amount: amountCrypto
|
||||
});
|
||||
|
||||
if (lockError) throw lockError;
|
||||
|
||||
// Parse result
|
||||
const lockResponse = typeof lockResult === 'string' ? JSON.parse(lockResult) : lockResult;
|
||||
|
||||
if (!lockResponse.success) {
|
||||
throw new Error(lockResponse.error || 'Failed to lock balance');
|
||||
}
|
||||
|
||||
toast.success('Crypto locked in escrow');
|
||||
toast.success('Balance locked successfully');
|
||||
|
||||
// 2. Encrypt payment details
|
||||
const encryptedDetails = encryptPaymentDetails(paymentDetails);
|
||||
@@ -271,12 +322,13 @@ export async function createFiatOffer(params: CreateOfferParams): Promise<string
|
||||
const { data: offer, error: offerError } = await supabase
|
||||
.from('p2p_fiat_offers')
|
||||
.insert({
|
||||
seller_id: (await supabase.auth.getUser()).data.user?.id,
|
||||
seller_wallet: account.address,
|
||||
seller_id: userId,
|
||||
seller_wallet: '', // No longer needed with internal ledger
|
||||
token,
|
||||
amount_crypto: amountCrypto,
|
||||
fiat_currency: fiatCurrency,
|
||||
fiat_amount: fiatAmount,
|
||||
price_per_unit: fiatAmount / amountCrypto,
|
||||
payment_method_id: paymentMethodId,
|
||||
payment_details_encrypted: encryptedDetails,
|
||||
min_order_amount: minOrderAmount,
|
||||
@@ -284,41 +336,39 @@ export async function createFiatOffer(params: CreateOfferParams): Promise<string
|
||||
time_limit_minutes: timeLimitMinutes,
|
||||
status: 'open',
|
||||
remaining_amount: amountCrypto,
|
||||
escrow_tx_hash: txHash,
|
||||
escrow_locked_at: new Date().toISOString()
|
||||
// NOTE: No escrow_tx_hash - internal ledger doesn't use blockchain during trades
|
||||
})
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (offerError) throw offerError;
|
||||
|
||||
// 4. Record escrow in platform_escrow table
|
||||
await supabase
|
||||
.from('p2p_platform_escrow')
|
||||
.insert({
|
||||
offer_id: offer.id,
|
||||
seller_id: offer.seller_id,
|
||||
seller_wallet: account.address,
|
||||
token,
|
||||
amount: amountCrypto,
|
||||
blockchain_tx_lock: txHash,
|
||||
status: 'locked'
|
||||
});
|
||||
// 4. Update the lock with offer reference
|
||||
await supabase.rpc('lock_escrow_internal', {
|
||||
p_user_id: userId,
|
||||
p_token: token,
|
||||
p_amount: 0, // Just updating reference, not locking more
|
||||
p_reference_type: 'offer',
|
||||
p_reference_id: offer.id
|
||||
}).catch(() => {}); // Non-critical, just for tracking
|
||||
|
||||
// 5. Audit log
|
||||
await logAction('offer', offer.id, 'create_offer', {
|
||||
token,
|
||||
amount_crypto: amountCrypto,
|
||||
fiat_currency: fiatCurrency,
|
||||
fiat_amount: fiatAmount
|
||||
fiat_amount: fiatAmount,
|
||||
escrow_type: 'internal_ledger'
|
||||
});
|
||||
|
||||
toast.success(`Offer created! Selling ${amountCrypto} ${token} for ${fiatAmount} ${fiatCurrency}`);
|
||||
|
||||
|
||||
return offer.id;
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
console.error('Create offer error:', error);
|
||||
toast.error(error.message || 'Failed to create offer');
|
||||
const message = error instanceof Error ? error.message : 'Failed to create offer';
|
||||
toast.error(message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -460,15 +510,21 @@ export async function markPaymentSent(
|
||||
// =====================================================
|
||||
|
||||
/**
|
||||
* Seller confirms payment received and releases crypto
|
||||
* Seller confirms payment received and releases crypto (OKX-Style Internal Ledger)
|
||||
*
|
||||
* This function transfers crypto from seller's locked balance to buyer's available balance.
|
||||
* NO blockchain transaction occurs - just database update.
|
||||
*
|
||||
* Buyer can later withdraw to external wallet if needed (separate blockchain tx).
|
||||
*/
|
||||
export async function confirmPaymentReceived(
|
||||
api: ApiPromise,
|
||||
account: InjectedAccountWithMeta,
|
||||
tradeId: string
|
||||
): Promise<void> {
|
||||
export async function confirmPaymentReceived(tradeId: string): Promise<void> {
|
||||
try {
|
||||
// 1. Get trade details
|
||||
// 1. Get current user (seller)
|
||||
const { data: userData } = await supabase.auth.getUser();
|
||||
const sellerId = userData.user?.id;
|
||||
if (!sellerId) throw new Error('Not authenticated');
|
||||
|
||||
// 2. Get trade details
|
||||
const { data: trade, error: tradeError } = await supabase
|
||||
.from('p2p_fiat_trades')
|
||||
.select('*')
|
||||
@@ -477,62 +533,76 @@ export async function confirmPaymentReceived(
|
||||
|
||||
if (tradeError) throw tradeError;
|
||||
if (!trade) throw new Error('Trade not found');
|
||||
|
||||
// Verify caller is the seller
|
||||
if (trade.seller_id !== sellerId) {
|
||||
throw new Error('Only seller can confirm payment');
|
||||
}
|
||||
|
||||
if (trade.status !== 'payment_sent') {
|
||||
throw new Error('Payment has not been marked as sent');
|
||||
}
|
||||
|
||||
// 2. Release crypto from escrow to buyer (blockchain tx)
|
||||
toast.info('Releasing crypto to buyer...');
|
||||
|
||||
const amount = BigInt(trade.crypto_amount * 1e12);
|
||||
// 3. Get offer to get token type
|
||||
const { data: offer } = await supabase
|
||||
.from('p2p_fiat_offers')
|
||||
.select('token')
|
||||
.eq('id', trade.offer_id)
|
||||
.single();
|
||||
|
||||
let releaseTxHash: string;
|
||||
if (offer?.token === 'HEZ') {
|
||||
const tx = api.tx.balances.transfer(trade.buyer_wallet, amount);
|
||||
releaseTxHash = await signAndSendWithPlatformKey(api, tx);
|
||||
} else {
|
||||
const assetId = ASSET_IDS[offer?.token as CryptoToken];
|
||||
const tx = api.tx.assets.transfer(assetId, trade.buyer_wallet, amount);
|
||||
releaseTxHash = await signAndSendWithPlatformKey(api, tx);
|
||||
if (!offer) throw new Error('Offer not found');
|
||||
|
||||
toast.info('Releasing crypto to buyer...');
|
||||
|
||||
// 4. Release escrow internally (NO blockchain tx!)
|
||||
// This transfers from seller's locked_balance to buyer's available_balance
|
||||
const { data: releaseResult, error: releaseError } = await supabase.rpc('release_escrow_internal', {
|
||||
p_from_user_id: trade.seller_id,
|
||||
p_to_user_id: trade.buyer_id,
|
||||
p_token: offer.token,
|
||||
p_amount: trade.crypto_amount,
|
||||
p_reference_type: 'trade',
|
||||
p_reference_id: tradeId
|
||||
});
|
||||
|
||||
if (releaseError) throw releaseError;
|
||||
|
||||
// Parse result
|
||||
const releaseResponse = typeof releaseResult === 'string' ? JSON.parse(releaseResult) : releaseResult;
|
||||
|
||||
if (!releaseResponse.success) {
|
||||
throw new Error(releaseResponse.error || 'Failed to release escrow');
|
||||
}
|
||||
|
||||
// 3. Update trade status
|
||||
// 5. Update trade status
|
||||
const { error: updateError } = await supabase
|
||||
.from('p2p_fiat_trades')
|
||||
.update({
|
||||
seller_confirmed_at: new Date().toISOString(),
|
||||
escrow_release_tx_hash: releaseTxHash,
|
||||
escrow_released_at: new Date().toISOString(),
|
||||
status: 'completed',
|
||||
completed_at: new Date().toISOString()
|
||||
// NOTE: No escrow_release_tx_hash - internal ledger doesn't use blockchain during trades
|
||||
})
|
||||
.eq('id', tradeId);
|
||||
|
||||
if (updateError) throw updateError;
|
||||
|
||||
// 4. Update escrow balance
|
||||
await supabase.rpc('decrement_escrow_balance', {
|
||||
p_token: offer?.token,
|
||||
p_amount: trade.crypto_amount
|
||||
});
|
||||
|
||||
// 5. Update reputations
|
||||
// 6. Update reputations
|
||||
await updateReputations(trade.seller_id, trade.buyer_id, tradeId);
|
||||
|
||||
// 6. Audit log
|
||||
// 7. Audit log
|
||||
await logAction('trade', tradeId, 'confirm_payment', {
|
||||
release_tx_hash: releaseTxHash
|
||||
released_amount: trade.crypto_amount,
|
||||
token: offer.token,
|
||||
escrow_type: 'internal_ledger'
|
||||
});
|
||||
|
||||
toast.success('Payment confirmed! Crypto released to buyer.');
|
||||
} catch (error: any) {
|
||||
toast.success('Payment confirmed! Crypto released to buyer\'s balance.');
|
||||
} catch (error: unknown) {
|
||||
console.error('Confirm payment error:', error);
|
||||
toast.error(error.message || 'Failed to confirm payment');
|
||||
const message = error instanceof Error ? error.message : 'Failed to confirm payment';
|
||||
toast.error(message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -579,11 +649,9 @@ async function signAndSendTx(
|
||||
});
|
||||
}
|
||||
|
||||
async function signAndSendWithPlatformKey(api: ApiPromise, tx: any): Promise<string> {
|
||||
// TODO: Implement multisig or server-side signing
|
||||
// For now, this is a placeholder
|
||||
throw new Error('Platform signing not implemented - requires multisig setup');
|
||||
}
|
||||
// NOTE: signAndSendWithPlatformKey removed - OKX-style internal ledger
|
||||
// doesn't need blockchain transactions during P2P trades.
|
||||
// Blockchain transactions only occur at deposit/withdraw via backend service.
|
||||
|
||||
async function updateReputations(sellerId: string, buyerId: string, tradeId: string): Promise<void> {
|
||||
await supabase.rpc('update_p2p_reputation', {
|
||||
@@ -808,3 +876,192 @@ export async function updateUserReputation(
|
||||
console.error('Update reputation error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// INTERNAL BALANCE FUNCTIONS (OKX-Style)
|
||||
// =====================================================
|
||||
|
||||
/**
|
||||
* Get user's internal balances for P2P trading
|
||||
*/
|
||||
export async function getInternalBalances(): Promise<InternalBalance[]> {
|
||||
try {
|
||||
const { data: userData } = await supabase.auth.getUser();
|
||||
const userId = userData.user?.id;
|
||||
if (!userId) throw new Error('Not authenticated');
|
||||
|
||||
const { data, error } = await supabase.rpc('get_user_internal_balance', {
|
||||
p_user_id: userId
|
||||
});
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
// Parse the JSON result
|
||||
const balances = typeof data === 'string' ? JSON.parse(data) : data;
|
||||
return balances || [];
|
||||
} catch (error) {
|
||||
console.error('Get internal balances error:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user's internal balance for a specific token
|
||||
*/
|
||||
export async function getInternalBalance(token: CryptoToken): Promise<InternalBalance | null> {
|
||||
const balances = await getInternalBalances();
|
||||
return balances.find(b => b.token === token) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a withdrawal from internal balance to external wallet
|
||||
* This creates a pending request that will be processed by backend service
|
||||
*/
|
||||
export async function requestWithdraw(
|
||||
token: CryptoToken,
|
||||
amount: number,
|
||||
walletAddress: string
|
||||
): Promise<string> {
|
||||
try {
|
||||
const { data: userData } = await supabase.auth.getUser();
|
||||
const userId = userData.user?.id;
|
||||
if (!userId) throw new Error('Not authenticated');
|
||||
|
||||
// Validate amount
|
||||
if (amount <= 0) throw new Error('Amount must be greater than 0');
|
||||
|
||||
// Validate wallet address (basic check)
|
||||
if (!walletAddress || walletAddress.length < 40) {
|
||||
throw new Error('Invalid wallet address');
|
||||
}
|
||||
|
||||
toast.info('Processing withdrawal request...');
|
||||
|
||||
// Call the database function
|
||||
const { data, error } = await supabase.rpc('request_withdraw', {
|
||||
p_user_id: userId,
|
||||
p_token: token,
|
||||
p_amount: amount,
|
||||
p_wallet_address: walletAddress
|
||||
});
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
// Parse result
|
||||
const result = typeof data === 'string' ? JSON.parse(data) : data;
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || 'Withdrawal request failed');
|
||||
}
|
||||
|
||||
toast.success(`Withdrawal request submitted! ${amount} ${token} will be sent to your wallet.`);
|
||||
|
||||
return result.request_id;
|
||||
} catch (error: unknown) {
|
||||
console.error('Request withdraw error:', error);
|
||||
const message = error instanceof Error ? error.message : 'Withdrawal request failed';
|
||||
toast.error(message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user's deposit/withdraw request history
|
||||
*/
|
||||
export async function getDepositWithdrawHistory(): Promise<DepositWithdrawRequest[]> {
|
||||
try {
|
||||
const { data, error } = await supabase
|
||||
.from('p2p_deposit_withdraw_requests')
|
||||
.select('*')
|
||||
.order('created_at', { ascending: false })
|
||||
.limit(50);
|
||||
|
||||
if (error) throw error;
|
||||
return data || [];
|
||||
} catch (error) {
|
||||
console.error('Get deposit/withdraw history error:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user's balance transaction history
|
||||
*/
|
||||
export async function getBalanceTransactionHistory(limit: number = 50): Promise<BalanceTransaction[]> {
|
||||
try {
|
||||
const { data, error } = await supabase
|
||||
.from('p2p_balance_transactions')
|
||||
.select('*')
|
||||
.order('created_at', { ascending: false })
|
||||
.limit(limit);
|
||||
|
||||
if (error) throw error;
|
||||
return data || [];
|
||||
} catch (error) {
|
||||
console.error('Get balance transaction history error:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get platform escrow wallet address (for deposits)
|
||||
*/
|
||||
export async function getPlatformWalletAddress(): Promise<string> {
|
||||
try {
|
||||
const { data, error } = await supabase
|
||||
.from('p2p_config')
|
||||
.select('value')
|
||||
.eq('key', 'platform_escrow_wallet')
|
||||
.single();
|
||||
|
||||
if (error) throw error;
|
||||
return data?.value || PLATFORM_ESCROW_ADDRESS;
|
||||
} catch (error) {
|
||||
console.error('Get platform wallet address error:', error);
|
||||
return PLATFORM_ESCROW_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a deposit transaction and credit internal balance
|
||||
* NOTE: In production, this should be called by backend service after verifying on-chain
|
||||
*/
|
||||
export async function verifyDeposit(
|
||||
txHash: string,
|
||||
token: CryptoToken,
|
||||
amount: number
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
const { data: userData } = await supabase.auth.getUser();
|
||||
const userId = userData.user?.id;
|
||||
if (!userId) throw new Error('Not authenticated');
|
||||
|
||||
toast.info('Verifying deposit...');
|
||||
|
||||
// Call the database function
|
||||
const { data, error } = await supabase.rpc('process_deposit', {
|
||||
p_user_id: userId,
|
||||
p_token: token,
|
||||
p_amount: amount,
|
||||
p_tx_hash: txHash
|
||||
});
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
// Parse result
|
||||
const result = typeof data === 'string' ? JSON.parse(data) : data;
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || 'Deposit verification failed');
|
||||
}
|
||||
|
||||
toast.success(`Deposit verified! ${amount} ${token} added to your balance.`);
|
||||
|
||||
return true;
|
||||
} catch (error: unknown) {
|
||||
console.error('Verify deposit error:', error);
|
||||
const message = error instanceof Error ? error.message : 'Deposit verification failed';
|
||||
toast.error(message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQEAOzAAAAEEACoAAQBQpyoA8wIBZTswAAABBQCBAAIA94yAAO6ZAABhRwUA/ZX+lf+VAJYBlgKWA5YBAwA7MAAAAQUAVQABAKY9VQCjAISwlZcAAAGgUAAFPoMBQAk7MAAAAQIAVQABABbOVQBhRwUA6JXpleqV65Xsle2V7pVhSAUAPpY/lkCWQZZClkOWRJaTAASgMAAFlvygcAAFmD1haHB2OzACAAUCAIIBBAABAAUACAACAGtjVwEj0yoAtDIWogIAgD4BAMqVBgD7A2Flbw==")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQIAOzAAAAEEACsAAQA7NSsAAQMAOzAAAAEFACoAAQCXRyoA8wMBZAGLBwMAAQUBoGAABZlFYzswAAABBQAqAAEAfY8qAEFABQD1lfaV95X4lfKZQUAFAPGV8pXzlfSV8ZnzAMWGBIAAOzABAAMCAAMBBQCvAAEAlXgDAQMApY6sAHOZAQDvmQAA")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQIBoDAABZVhZDswAAABBAAqAAEAlaEqAPMDAXM7MAAAAQEAKgABAFpZKgBhRgUAJpYnliiWKZYqliuWLJb7AmVr")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("YUYFAD6WP5ZAlkGWQpZDlkSWAQcAOzAAAAEFAJAAAQBsl5AAE4ECoHAABZcCYWUBAQA7MAAAAQQAKgABAFCnKgDzAgFlOzAAAAEFAIEAAgD3jIAA7pkAAPFABQDcmd2Z3pnfmeCZ4ZnimeOZ5JnlmeaZ55nomemZ6pn1mfMCAXM7MAAAAQQAgAABADxKgAABBgA7MAEAAgQAAAAFALEDF6IBABghsQNhRwUA/ZX+lf+VAJYBlgKWA5YBAAGgUAAFlg10OzAAAAEDACoAAQD0ECoAAQMAOzAAAAEFAFUAAQCmPVUAAQMAOzAAAAEFAJAAAQCkmJAAAQQAOzAAAAEFAJAAAQBsl5AAZx0AybCVlwAAAaBwAAWZaqBQAAU+g0BClA07MAQAHQAAKgABAAAAAgBVAAMAKgAFACoALQAAADMAAAA1AAAAOwAAAEEAAAABAAL0KgBxUAEAFs5VAAEAyRAqAAEAt1cqAAELADswAAABBQAVAAEAGJgVAAUBwwUAA/2XB3eZaXDzBQF3AVQ+BQABAwGgEAAFPlNvOzABAAIEAAAABQAWABmiAgABkQAA0ZUVAIUARAUAC2iZd44cN5Y4ljmWOpY7ljyWPZZpmQELADswAAABBQAVAAEAApgVAAEAADswAAABBQCEAgEAyiSEAvMDAXP2GqIEAN/zAQABAAEA9wP3CgHIoHAABZEAsKWW+gABwESQCjswAQADAQCvAgQALAEBABB0rwIBAAnvLAFhRwUA6JXpleqV65Xsle2V7pVhSAUAPpY/lkCWQZZClkOWRJaTAASgMAAFlvygcAAFmD1haHB2OzACAAUCAIIBBAABAAUACAACAGtjVwEj0yoAtDIWogIAgD4BAMqVBgD3DQDIoCAAAs5sQEUQDjswAAABBQBTEAIAwkf0D2uVXgA=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("BQHBBQAGDpY+2pnbmfCZ9JlnaQELADswAAABBQAVAAEAGJgVAAUBwwUAA/2XB3eZaXDzBQF3AVQ+BQABAwGgEAAFPlNvOzABAAIEAAAABQAWABmiAgABkQAA0ZUVAIUARAUAC2iZd44cN5Y4ljmWOpY7ljyWPZZpmQELADswAAABBQAVAAEAApgVAAEAADswAAABBQCEAgEAyiSEAvMDAXP2GqIEAN/zAQABAAEA9wP3CgPIoHAABZEAsKWW+gABwESQCjswAQADAQCvAgQALAEBABB0rwIBAAnvLAH7AmFl")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQUAOzAAAAEEAFoYAQDqS1oYAQIAOzAAAAEBALUwAQB2p7UwAQIAOzAAAAEBALUwAQDAdrUwYUwFADeWOJY5ljqWO5Y8lj2W8wCECBADOzACAAcAABojAgBcGQUALAEBAMtGGiMBAJl5XBkBAHiNLAE=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("YUUFAOr76/vs++377vvv+/D7AQcAOzAAAAEFAFwAAgCYm1sA2fkAAGFABQAg/SH9Iv0j/ST9Jf0m/fMCAWQ7MAEAAwMA8wMFABUAAQCfAfMDAQCK+hUA8wICaXA7MAIABwEAtwAEAC0ABQAtAAEAOS63AAEAGfYtAAEAFoktAGFMBQAW+xf7GPsZ+xr7G/sc+zcBAIWgIAAF+ZuwIQsoAAGQgQI7MAMADgAAAQABAB00AgANGgMAKU4lAAAAKQAAADMAAAA5AAAAhitAygIAKAsBAOKQGzQBALJYDRoDAMEFDRqpkA0a28wNGg==")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQAAOzAAAAEBAKsAAQC4cqsA8wIBczswAQABAQAqAAUAAAABAG9PKgAklgEFADswAAABBQBVAAEA5YNVAPsCY24=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQAAOzAAAAEEAEEBAQBR6UEBAQMAOzAAAAEFAC0AAQDepS0A8wEBZAGjPQMA+wJjdAECADswAAABAwANGgEAwQUNGvMAAW07MAAAAQAADRoBAJnjDRphQwUA2vnb+dz53fne+d/54Pl7hKAwAAWcKCEgAg==")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQIBoDAABZVhZDswAAABBAAqAAEAlaEqAPMCAXM7MAAAAQEAKgABAFpZKgAFAcAFAAQ1lgVrmWd3AQIAOzAAAAEEACwBAQAxMSwB+wJkZwEAADswAAABBQAsAQEAuhwsAfsCZG7hQAUAWZlamVuZXJldmV6ZX5lgmWGZYpljmWSZZZlmmWeZAQQAOzABAAMEAOwLBQAHBAEAE/TsCwEAAAAHBPMAAmVzOzABAAMCAFoYBQBbGAEALRlaGAIACARaGGmVAAABAAGgAAAFmDJzOzAAAAEFAIQCAQByioQCAQEAOzAAAAEEACoAAQAnqCoAAQMAOzAAAAEFAFoYAQDiV1oYMUIFAC+YMJgxmPaZMwADoJAABZVpZWlzOzAAAAEFAJEAAgBFlpAARZkAAAECADswAAABAwD0DwEAd330DwEFADswAAABBQBeAAEAa5VeAPMCAWM7MAAAAQMA9A8BAIJt9A/7AjEy+8UCAohAxwQAh6EQAAWZaqAwAAWVYaCAAAU+UqAAAAWZSRwhCjswAAABBABXAQIADTQsAZWhKgA=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("YUAFAJz5nfme+Z/5oPmh+aL58wIBczswAQACBAAAAAUAGQTT9AUAsHzzAyecAADy+QYA6fwOAP78DgDzAAFpOzAAAAEFAC4AAgCndy0A5vsAAA==")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQMAOzAAAAEEACoAAQCJMioAAQUAOzAAAAEFACoAAQA+cCoA8wABYzswAgADAgBVAAQAVQAFAAAAAQBuzlUAAQAtL1UA/ZYrA6BAAAWWJKDQAAWZRGxyc/MAAmFjOzAAAAEBACoAAQBGUCoA")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQAAOzABAAIBAAAABAANGmIFAQADWQ0aGwKgIAAF+x1laeUARAUADan9c8b5x/nI+cn5yvnL+cz5zfnO+c/50PnR+dL50/nU+fsCZ2w=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQQAOzAAAAEBAKsAAQBkc6sAAQMAOzAAAAEFACoAAQDVkCoAE4QDoFAABZYEoGAABZYjbnByBQBBBQAAEJZzapUBBwA7MAAAAQUAkAABAGyXkAC/AYWgcAAFlwI1AAE=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQAAOzAAAAEFACoAAQBSjyoA8wUBcwF2mQUAGwKgUAAFl2ludQELADswAAABBQAVAAEAGJgVAAUBwwUAA/2XB3eZaXDzBQF3AVQ+BQABAwGgEAAFPlNvOzABAAIEAAAABQAWABmiAgABkQAA0ZUVAIUARAUAC2iZd44cN5Y4ljmWOpY7ljyWPZZpmQELADswAAABBQAVAAEAApgVAAEAADswAAABBQCEAgEAyiSEAvMDAXP2GqIEAN/zAQABAAEA9wP3CgDIoHAABZEAsKWW+gABwESQCjswAQADAQCvAgQALAEBABB0rwIBAAnvLAEBAAA7MAAAAQUAsQMBADVBsQPzAwFzOzAAAAEFAIQCAQClJ4QCYUcFAMqVy5XMlc2VzpXPldCVAQMAOzAAAAEFAIQCAQBZkYQCAQEAOzAAAAEFAIQCAQCwPoQC84ICZWkBAwA7MAAAAQUALAEBAHiNLAHzAQFmOzAAAAEEACwBAQAEMCwB84KEEDEA+wNhaG8=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("BQFMBQAA8ZkA8pkyM++ZGwKg4AAFmfNpbwkDoEAABDK0oMAABZnuoDAABZgzbW50DwaIoCAABZb9oKAABZnroTAABZn2sCWW/gABoJAABZnZsHWZcwABOlAG")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("IUwFAEaZR5nXmYUAQgUAC2iZd44cN5Y4ljmWOpY7ljyWPZZpmQEDADswAAABBAAqAAEAAi8qAAECADswAAABBAAsAQEAVZcsAecAAMWg0AAFliWg0AAFmDVABKAIOzABAAEAAIAABQAAAAEAVfOAADOYAQcAOzAAAAEEACoAAQBj8SoAAQMAOzAAAAEFAFoYAQDiV1oYMUIFAC+YMJgxmPaZ8wMCZWk7MAAAAQUAkQACAEWWkABFmQAA+4QECCE=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQoAOzAAAAEFABUAAQCK+hUAAQMAOzAAAAEDAFsAAQALj1sAUwCEoEAABICOsJX6rgABAFEBOzACAAcBAJ4BBAAtAAUALgACAOgSAAA1ZZ0BAQB29C0AAgDn+C0AH/0AAA==")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("BQBHBQAG7ZllNJgrAqDAAAWWBWl0AQcAOzAAAAEFAHsTAQBpcHsTAQMAOzAAAAEDAHsTAQDHpXsTAQIAOzAAAAEEAHsTAQBoNXsT8wCEAgEkOzAAAAEAANUVAgB7n1kCwr57Ew==")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQMAOzAAAAEFAA0aAQAVLQ0aGwKg4AAF+dhiZgUBwAUACh796/78//wA/QH9Av0D/QT9Bf0G/Qf9CP0J/Qr9C/0M/WFvAQsAOzAAAAEFAJAAAQBY/JAAI4ECoKAABfsUcHQVAEIFAAah/WWk+ej7BQHCBQBgsfmy+bP5tPm1+bb5t/lg8vvz+/T79fv2+/f7+PtkcgUAQAUAB8X5ZRX7+wRjZ292AQIAOzAAAAEEAC4AAQBfgC4AAQUBoGAABfz5YzswAAABBQAtAAEAyPItAEFABQCp+ar5q/ms+ab9QUAFAKX5pvmn+aj5pf3zAgQyM2JyOzABAAMCABUBBQC7AAEAtKQVAQMA4fG4ACf9AQCj/QAAAQEAOzABAAEEAIoABQAAAAEAF+2KAI39BQBHBQAE/Pxl6PkFAEkFAAah/WXo+2FJBQAg/SH9Iv0j/ST9Jf0m/bMEBKBQAAX5HmFlc3bzaPQFAEYGAQD7AmNm1wwAiKBgAAX9oaBAAAX5HqCQAAX5wjHBDDswAQADBAAtAAUAGQABAE/7LQAGAJz5BgCk+QAAt/oAAOj7AACQ/Q4Aqf0AAA==")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQoAOzAAAAEFAJAAAQAg+5AAAQEAOzAAAAEBAC0AAQAa+S0AAQIAOzAAAAEDAA0aAQCpkA0a8wABbTswAAABAQANGgEAKxQNGisCoKAABf2pZHkBAQA7MAEAAQQAigAFAAAAAQAX7YoAjf0FAEcFAAT8/GXo+QUASQUABqH9Zej7YUkFACD9If0i/SP9JP0l/Sb9swQEoFAABfkeYWVzdvNo9AUARgYBAPuFJCAF")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQEAOzAAAAEEALUwAQBFZLUwAQIAOzAAAAEDAFoYAQAnVVoYAQIAOzAAAAEEAFsuAQBSqFsu8wADYW1yOzACAAYAAAAAAQDjLwIALBlVEgIAKwJaGHfoiBcBAAAALBk=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQEAOzAAAAEFABQAAwAW+QYAuvkGANr5BgDzAAFvOzAAAAEDABERAQDPHxERAQ0AOzAAAAEFAF4AAQAs/V4A4VAFAJD9kf2S/ZP9lP2V/Zb9l/2Y/Zn9mv2b/Zz9nf2e/fMBAnJ3OzABAAMDAD4EBADSDAEAwfs+BAEAAADSDJuEsIX6tAABoEAABfu1AKgC")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQIAOzAAAAEFAEEBAQBue0EBYUsFAPL78/v0+/X79vv3+/j7AQUAOzAAAAEEAEEBAQAn+UEB4wCEoHAABfsfBUABOzACAAcBAIsHBABBAQUADQACAN8NBwWxYoMCAQAP6EEBAgCg+gYA6vsGAOFLBQAN/Q79D/0Q/RH9Ev0T/RT9Ff0W/Rf9GP0Z/Rr9G/07A6CAAAX5uWRtbg==")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQQAOzAAAAEFAC0AAQBWgy0AAQMAOzAAAAEFAEEBAQAEeEEBOwOhUAAF/aBjZ3ABBQA7MAAAAQUALQABAKdJLQABBQA7MAAAAQUALQABAB63LQD7AmFw4U8FAA39Dv0P/RD9Ef0S/RP9FP0V/Rb9F/0Y/Rn9Gv0b/QEGADswAAABBQAtAAEAl/QtAPMCAXI7MAAAAQQA8wMBABFz8wPvAYWgsAAF++IRSQA=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQIAOzAAAAEFACwBAQDrHywBYUsFAD6YP5hAmEGYQphDmESYAQUAOzAAAAEEACwBAQAjpiwB4wKEoHAABZdrBUABOzADAA8AALcDAQBVAwQALAEFAA0AJQAAACsAAAA1AAAAOwAAAAEASPy3AwIAAAD7AJJLWQIBACiWLAECAOyWBgA2mAYA8wABdDswAAABBQAOAAEAWZkOAA==")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQEAOzAAAAEEAC0AAQBp+i0A8wIBZTswAAABBQCKAAIAFfCJAKL9AABhRwUAsfmy+bP5tPm1+bb5t/kBAwA7MAAAAQUAWwABADybWwCjAISwlfq0AAGgUAAFnCgBQAk7MAAAAQMAWwABACwAWwBhRwUAnPmd+Z75n/mg+aH5ovlhSAUA8vnz+fT59fn2+ff5+PmTAASgMAAF+rCgcAAF+/FhaHB2OzADAAsCAG8BAwAtAAQAAQAFAAgAJQAAACsAAAAxAAAANQAAAAEAEI5vAQEAkwUtAKt90vQCACWcAQB++QYA+wNhZW8=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQQAOzAAAAEFACoAAQA2lSoAAQQAOzAAAAEFACoAAQALlSoA8wACbHQ7MAIAAwIAqwAEAFUABQABAAEAxM6rAAEAgy9VAP6W/5YbAqBgAAWV729yAQQAOzAAAAEEACwBAQA28CwBOwOgcAAFlwNpb3U=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQAAOzAAAAEFACoAAQBSjyoABQBHBQAESJllNJYFAEkFAAbtmWU0mGFJBQBsmW2ZbplvmXCZcZlymbMCBKBQAAWVamFlc3bzApEFAPgFAQDzAAJpcwF2mQUAAQMAOzAAAAEFACoAAQC3VyoABQHABQALaZUHNZZlaQEEAaAAAAWXa3M7MAAAAQUAVgACAOWDVQAFlgAAAQIAOzAAAAEEACoAAQBeMioAvwaHoEAABZlqoKAABZXnhUQF")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("YUoFANr52/nc+d353vnf+eD54VMFAJD9kf2S/ZP9lP2V/Zb9l/2Y/Zn9mv2b/Zz9nf2e/RsCoMAABf2MYXgTgQKgUAAF+dVlbwECADswAAABAwANGgEAwQUNGgEBAaAQAAX78WU7MAAAAQEAsQIBAHtdsQIBAwA7MAAAAQUALQABAN6lLQDzBAFkAaM9AwABCwA7MAAAAQUAkAABAFj8kAAjhAKgoAAF+xRwdPsCbnIBAwA7MAAAAQEAbwEBAJtqbwHzAIYRUQE7MAMADwAADRoBABs0AgANGgUAQQElAAAAKwAAADEAAAA3AAAAAQCZ4w0aAQD+xBs0AQDAcg0aAQBue0EB")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQMAOzAAAAEBACoAAQBM6CoAQUAFAPWV9pX3lfiV8plBQAUA8ZXylfOV9JXxmfMHAjIzOzAAAAEFAK0AAgCljqwA75kAAPMAAXQ7MAEAAwEAgAAFACsAAQCaT4AAAgADkSoA7ZkAAAEDADswAAABAwAqAAEA9BAqAPsDYWVp")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQIAOzAAAAEFAEEBAQBue0EBYUsFAPL78/v0+/X79vv3+/j7AQUAOzAAAAEEAEEBAQAn+UEB4wKEoHAABfsfBUABOzACAAcBAIsHBABBAQUADQACAN8NBwWxYoMCAQAP6EEBAgCg+gYA6vsGAPMAAXQ7MAAAAQUADgABAA39DgA=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("YUUFAD6YP5hAmEGYQphDmESYAQAAOzAAAAEFACoAAQBPJyoAAQUAOzAAAAEEACwBAQAboiwBVwEBhaAgAALObaAQAAWRAGRAAjswAwANAABWAAIAAAAEACoABQCMASUAAAArAAAALQAAADMAAAABAGf5VgBwzwEA/KcqAAgA5x1XAVU+KgDvlQAAIZYAAP6XAgBGmQEAdZkAANeZAQA=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("YUUFADaYN5g4mDmYOpg7mDyYAQcAOzAAAAEFAFYAAgD8PVUAJZYAAGFABQBsmW2ZbplvmXCZcZlymfMCAWQ7MAEAAwIAsQMFABUAAQBxz7EDAQDWlhUA8wICaXA7MAIABwEAqwAEACoABQAqAAEAhhqrAAEASKMqAAEArywqAGFMBQBil2OXZJdll2aXZ5dolzcBAIWgIAAFleewIPm+AAGQgQI7MAMADgAAAwABALUwAgC1MAMAtTAlAAAALQAAADMAAAA9AAAAsCgRvb75v/kBAMB2tTACAIgxWhhO01oYAgAnVVoYbI1aGA==")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQUAOzAAAAEFADEAAwD3my0A+vwBAIv9AQAxSwUA4/vk++X7qv0zggOggAAF+cRsb3IBAgA7MAAAAQQAQQEBAGGXQQEbAqBQAAX8+WFoUwADoEAABZwoY2VuOzAEABUAAEEBAQAAAAMAQgEEAAAABQC0AS0AAAAzAAAANQAAAD8AAABBAAAAAQBkpUEBnXECAIgAAABnj0EBjoAFAGVIQQEpnC0AyPItALb7FQDp+wAA")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQAAOzAAAAEBAKsAAQBkc6sAAQMDoMAABZlpoBAABT6voAAABZcDZGlzOzAAAAEFACMAAwAtlgYAYpcGABiYFQABBgA7MAAAAQUAKgABAAORKgDzAgFlARGWBQABAQA7MAEAAwIAYQQDAIIDAQCe+2EEAQAAAIID4U0FADWZNpk3mTiZOZk6mTuZPJk9mT6ZP5lAmUGZQplDmQECADswAAABBQA2BgEAO4Q2BiMAAqCwAAWXYWVsOzAAAAEFAEYOAQBfL0YOAQEAOzAAAAECAPQPAQCp6/QP8wCECQAGOzABAAIAAAAAAQAqAN/2AQDcRSoA84ECZWkBAwA7MAAAAQUAWhgBAOJXWhjzBAFpOzAAAAEFAJAAAQBFlpAA4VAFAEqZS5lMmU2ZTplPmVCZUZlSmVOZVJlVmVaZV5lYmTsDoMAABZlrYWVtAQAAOzAAAAEBAKsAAQC4cqsAAQMAOzAAAAEFACoAAQCXRyoA8wACZHM7MAMACgAAAAABACoAAwAAAAUArAAlAAAAJwAAAC0AAAAvAAAA4PYBAG9PKgCLBwIAPx+rACSWAAABBAA7MAAAAQUAkAABAKSYkADzAAFlOzAAAAEFAFMQAgDCR/QPa5VeAAEDADswAAABBAAsAQEAG6IsAfsCbHTfB4egsAAFljWTQEQ=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQYAOzAAAAEFAK8CAQDnRK8C8UQFANyZ3Znemd+Z4JnhmeKZ45nkmeWZ5pnnmeiZ6ZnqmfWZ5QBBBQAN9ZlzEpYTlhSWFZYWlheWGJYZlhqWG5Yclh2WHpYfliCWWwOwRZdgAeRkbXT7AmFp")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQUAOzAAAAEFAC0AAQBp9C0AAQMAOzAAAAEEALECAQAFd7ECAQQAOzAAAAEFAEUPAQD2i0UP+wJjZfsCbngTAISgQAAF+emg0AAF/P2gUAAF/R9QABQ7MAIABgEAAAAEAIkABQA0AN4NAQCX+okACABWgy0Am/kAAMX5AAAU+wAAHfsAAOL7AAD4/AAAn/0AAA==")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQAAOzAAAAEFAEEBAQB390EB8wMBczswAAABBADzAwEAou3zA/MCAW47MAAAAQEAsQIBABgIsQIBBgA7MAAAAQUALQABAGn0LQDzAgFlAcX5BQABBwA7MAAAAQUAWwABALj6WwABCQA7MAAAAQUAXgABAPn7XgDzgwJkbQEBADswAAABAwBxCAEA4TBxCOFNBQDp/Or86/zs/O387vzv/PD88fzy/PP89Pz1/Pb89/wBAgA7MAAAAQUApQYBAL3mpQYjAAKgsAAF+xVlbDswAAABBQBFDwEA9otFDwEAADswAAABAwAREQEAzx8REQENADswAAABBQBeAAEALP1eAPMBAXc7MAEAAwMAPgQEANIMAQDB+z4EAQAAANIM+wJsc/MAhQkAFjswAgAHAQBAEQMALQAFAC0AAgAWCAAAg0s/EQEARz0tAAEAOPQtAOuEoCAABZwmEQEI")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("IUwFAPr8+/yL/YUAQgUACxz9d9V36/ns+e357vnv+fD58fkd/QEDADswAAABBAAtAAEAt3ktAAECADswAAABBABBAQEAUelBAecAAMWg0AAF+dmg0AAF++lABKAIOzABAAEBAIkABQAAAAEATQSJAOf7AQcAOzAAAAEFAC0AAQCnSS0AAQMAOzAAAAEFAA0aAQBMtw0aMUIFAOP75Pvl+6r98wMCZWk7MAAAAQUAkQACAPn5kAD5/AAA+4QECCE=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQIAOzAAAAEFACwBAQDrHywBYUsFAD6YP5hAmEGYQphDmESYAQUAOzAAAAEEACwBAQAjpiwB4wCEoHAABZdrBUABOzADAA8AALcDAQBVAwQALAEFAA0AJQAAACsAAAA1AAAAOwAAAAEASPy3AwIAAAD7AJJLWQIBACiWLAECAOyWBgA2mAYA4UsFAFmZWplbmVyZXZlemV+ZYJlhmWKZY5lkmWWZZplnmTsDoIAABZYFZG1u")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQcAOzAAAAEFAC0AAQCndy0AAQAAOzAAAAEBALECAQCbAbECAQABoBAABfz9awGJAAMAwwCEoDAABZwmoBAABZv1CEADOzACAAUDAGcTBAABAAUAywIDAPBhyRHIjUEBC49bAF6A1fQGANVJsQJn9AAAhfkVALH7AAAc/QAAK/0AAAEFADswAAABBACxAgEAlvGxAgEAADswAgAHAQDzAwQAQQEFAGIAAgBkBbECK2lBAQEAJ/lBAQMA1nctAFvRLQCn+gYA+wJnbvsDaW90")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("YUoFAOH54vnj+eT55fnm+ef5AQAAOzAAAAEEAC0AAQCdei0AOwOg0AAF/SoyaXPlAEYFAA2p/XPG+cf5yPnJ+cr5y/nM+c35zvnP+dD50fnS+dP51PkBAgA7MAAAAQQAQQEBABx/QQEbAqAwAAX56mF5YUoFALr5u/m8+b35vvm/+cD5AQUAOzAAAAEFAG8BAQBGeW8BBQHABQAO8fvokP2R/ZL9k/2U/ZX9lv2X/Zj9mf2a/Zv9nP2d/Z79ZWkBBQA7MAAAAQUAQQEBAAR4QQFhSQUAFvkX+Rj5Gfka+Rv5HPlhTAUAp/qo+qn6qvqr+qz6rfphSgUA2vnb+dz53fne+d/54PkFAcEFAA2M/QXV+WVv+wJvcgEDADswAAABBACdAQEAifedAQEDADswAAABBABBAQEAR/ZBAfsCcnYBAwA7MAEAAQQAbwEFAAMAAQCsfW8Bjv2P/aT9qP0BAM6gUAAF+7VRtYhQGIBBnW4ckj03eNeEJylufu/p0asIogHPHttjfHfTA/BiwJ7cInZZaG4SwGct+NgkQg9Ua/T4rhgAwtoqLFdsxYUyeoyhYAAF/ahAPRYfOzABAAMBAMsBBQBcAAIA6GdBAfpxiQADAISDLQCX9C0A1/kAAA==")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQYAOzAAAAEFAL0AAgD5+14ALP1eAAEAADswAQABAQBbAAUAAQABAJ5xWwC0+rX6AQUAOzAAAAEFAC4AAgApnC0A6fsAAPsCYWUrA6CwAAX7HaBAAAX6tmxyeZuEoIAABfnDoJAABfsUAUAF")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQEAOzAAAAEEABs0AQCxshs0AQIAOzAAAAEDAA0aAQCpkA0aAQIAOzABAAMEAIIEBQAULQEAffuCBAEAAAAULfMAA2FtcjswAgAGAAAAAAEADRoCABs0nBMBACsUDRoBAIgKGzQ=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQUAOzAAAAEFAC4AAwBVPioARpkBANeZAQAxSwUAL5gwmDGY9pkBAgA7MAAAAQQAhAIBABCfhAJ7hKCAAAWWEABJAQ==")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQAAOzAAAAEBALcAAQBKjbcAAQMDoMAABf0doBAABZxXoAAABfq3ZGlzOzAAAAEFACMAAwDh+QYAFvsGAMz7FQABBgA7MAAAAQUALQABAGn0LQDzAgFlAcX5BQABAQA7MAAAAQMAcQgBAOEwcQjhTQUA6fzq/Ov87Pzt/O787/zw/PH88vzz/PT89fz2/Pf8AQIAOzAAAAEFAKUGAQC95qUGIwACoLAABfsVZWw7MAAAAQUARQ8BAPaLRQ8BAQA7MAAAAQMAEREBAM8fERHzAIQJAAY7MAAAAQEALgACABYIAACVXC0A84ECZWkBAwA7MAAAAQUADRoBAEy3DRrzBAFpOzAAAAEFAJAAAQD5+ZAA4VAFAP78//wA/QH9Av0D/QT9Bf0G/Qf9CP0J/Qr9C/0M/TsDoMAABf0fYWVtAQAAOzAAAAEBALcAAQCSjLcAAQMAOzAAAAEFAC0AAQDepS0A8wACZHM7MAIABQEALgADAAAABQC4AAIAFwgAANNmLQCjPQIAtnq3ANj5AAABBAA7MAAAAQUAkAABAFj8kADzAAFlOzAAAAEFAHARAgAMphERH/leAAEDADswAAABBABBAQEA1/RBAfsCbHTfB4egsAAF+emTQEQ=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQMAOzAAAAECAC0AAQBaCi0AQUAFAKn5qvmr+az5pv1BQAUApfmm+af5qPml/fMHAjIzOzAAAAEFALkAAgDh8bgAo/0AAPMAAXQ7MAEAAwEAiQAFAC4AAQABZ4kAAgBp9C0Aof0AAAEDADswAAABAwAtAAEAtEctAPsDYWVp")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQAAOzAAAAEFALICAgBEibEC6vkAAAEDADswAAABAwANGgEAunMNGgECADswAAABAwDJEQEA8GHJEQEAADswAAABAQAOGgIA5xIAAIRyDRr7AmRu8wADaW5zOzABAAIAAAAABACDAt4vAQCT6oMCAQgAOzAAAAEFABUAAQC2+xUA+wJhZQ==")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("YUcFAJz5nfme+Z/5oPmh+aL5YUgFAPL58/n0+fX59vn3+fj5kwIEoDAABfqwoHAABfvxYWhwdjswAgAFAgBvAQQAAAAFAAcAAQAQjm8B0vQCACWcAAB++QYA")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("YUcFAOiV6ZXqleuV7JXtle6VYUgFAD6WP5ZAlkGWQpZDlkSWkwIEoDAABZb8oHAABZg9YWhwdjswAgAFAgBXAQQAAAAFAAcAAQBrY1cBFqICAIA+AADKlQYA")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("YUcFAOr76/vs++377vvv+/D7AQcAOzAAAAEFAFwAAgCYm1sA2fkAAGFABQAg/SH9Iv0j/ST9Jf0m/fMBAWQ7MAEAAwMA8wMFABUAAQCfAfMDAQCK+hUAKwKgQAAF9GZnevMAAmlwOzACAAcBALcABAAtAAUALQABADkutwABABn2LQABABaJLQBhRQUAFvkX+Rj5Gfka+Rv5HPkBAgA7MAAAAQUALQABAKd3LQDzgQJlcruEoKAABfq3AAgL")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("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")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQEAOzAAAAEEAC0AAQBp+i0A8wABZTswAAABBQCKAAIAFfCJAKL9AAABAQA7MAAAAQIADRoBAMByDRoBBgA7MAAAAQUAHgADACecAADp/A4A/vwOAAEEADswAAABBQCxAgEARImxAgUAQgUA4A39Dv0P/RD9Ef0S/RP9FP0V/Rb9F/0Y/Rn9Gv0b/XMd+QEDADswAQACBAAAAAUAsQJegAEA1UmxAucBAsWgYAAF+x4AQgEKAippAQDB+QUA+wNhZXM=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQIAOzAAAAEFACwBAQDrHywBAQUAOzAAAAEDACoAAQD0ECoABQHABQAIYZdqPpg/mECYQZhCmEOYRJhlcgEEADswAAABBQBbAAEABJdbAOFIBQDcmd2Z3pnfmeCZ4ZnimeOZ5JnlmeaZ55nomemZ6pkFAUYFAAP8lgc9mGhwgD4BBQA7MAAAAQQALAEBACOmLAEFAcEFAAVrlwRqmWNo8wCIFckBOzADAA8AALcDAQBVAwQALAEFAA0AJQAAACsAAAA1AAAAOwAAAAEASPy3AwIAAAD7AJJLWQIBACiWLAECAOyWBgA2mAYA")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQsAOzAAAAEFABUAAQAYmBUABQHDBQAD/ZcHd5lpcPMFAXcBVD4FAAEDAaAQAAU+U287MAEAAgQAAAAFABYAGaICAAGRAADRlRUAhQBEBQALaJl3jhw3ljiWOZY6ljuWPJY9lmmZAQsAOzAAAAEFABUAAQACmBUAAQAAOzAAAAEFAIQCAQDKJIQC8wMBc/YaogQA3/MBAAEAAQD3A/cKAMigcAAFkQCwpZb6AAHARJAKOzABAAMBAK8CBAAsAQEAEHSvAgEACe8sAQ==")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQAAOzAAAAEFACoAAQBSjyoABQBHBQAESJllNJYFAEAFAARqlW8DlwUASQUABu2ZZTSYYUkFAGyZbZlumW+ZcJlxmXKZVwMCxqDAAAWZaaAQAAU+r0BGAAk7MAAAAQUAJgAFAAKRAAAtlgYA+pYBAGKXBgAYmBUA8wACaXMBdpkFAA==")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQQAOzAAAAEFACoAAQBPJyoAAQMAOzAAAAEFACwBAQC6HCwBOwOhUAAFmexjZ3ABBQA7MAAAAQQAKgABAGPxKgABBQA7MAAAAQUAKgABALdXKgD7AmFw4U8FAFmZWplbmVyZXZlemV+ZYJlhmWKZY5lkmWWZZplnmQEGADswAAABBQAqAAEALpEqAPMCAXI7MAAAAQQAsQMBAMsosQPvAYWgsAAFmC4RSQA=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("BQBHBQAE/Pxl6PkBAAKgYAAF/aGgQAAF+R5lbzswAAABBQAZAAYAnPkGAKT5AAC3+gAA6PsAAJD9DgCp/QAABQBJBQAGof1l6PthSQUAIP0h/SL9I/0k/SX9Jv1XAwDGoMAABf0doBAABZxXQEYACTswAgAGAQAAAAQAigAFAEAEygoCANeWiQDT9AAACgCwfPMDJ5wAAGj0AADh+QYA8vkGAK76AQAW+wYAzPsVAOn8DgD+/A4A")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQAAOzAAAAEBALcAAQCSjLcA8wIBczswAQABAQAtAAUAAAABANNmLQDY+QEFADswAAABBQBbAAEAYeZbAPsCY24=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("BQHDBQADsfsHK/1pcPMCAXcE3A0BAN0NAQD2mwUAKJwFAAEAADswAAABAQAtAAEANAUtAAECADswAAABAgBbAAEAgI9bAAUBRAUABh775un86vzr/Oz87fzu/O/88Pzx/PL88/z0/PX89vz3/GR2wfkBBgA7MAAAAQQAiQABANeWiQDzAIQAQQM7MAEAAwAAiQAFAN8CAQAiMYkAAQD+ot8CAQYAOzAAAAEFAC0AAQCX9C0A8wABcjswAAABBADzAwEAEXPzA2FJBQC6+bv5vPm9+b75v/nA+QEFADswAAABBQA0AAIA1nctAKf6BgDzAQFjOzABAAEEALECBQAAAAEABXexAsL5AQYAOzAAAAEFAEEBAQBlSEEBAQYBoAAABPTUcjswAAABBABvAQEAZ5VvAfsCcnQBCgA7MAAAAQUAkAABACD7kAArAqCwAAX9qW509w4AiaBQAAX5xKDAAAX7HxFJTjswAgAHAQDlAAMALQAFAE8NAgDDXC0Akoy3AAEAtEctAAgApICxAkSJsQIKn/MDxfTzA8T5AADq+QAAHvsAAB79AAA=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQAAOzAAAAEDABERAQDPHxERAQ0AOzAAAAEFAF4AAQAs/V4A8wEBdzswAQADAwA+BAQA0gwBAMH7PgQBAAAA0gz7Amxz")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("4UAFAA39Dv0P/RD9Ef0S/RP9FP0V/Rb9F/0Y/Rn9Gv0b/QEEADswAAABBQAREQEAh0wREVMAA6CgAAX8/WVyczswAQADAgANGgUADhoBAKQ+DRoCAJldDRod+QAA")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("4VIFAFmZWplbmVyZXZlemV+ZYJlhmWKZY5lkmWWZZplnmQEAADswAAABAwDkBwEA5AjkBwEAADswAQABBACAAAUAAAABAHungADrmQEBAaAQAAU+U287MAEAAgQAAAAFABcAGaIDAAGRAADRlRUA/ZcAAOuEoBAABZlqcAAE+wJudA==")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("YUcFAOiV6ZXqleuV7JXtle6VYUgFAD6WP5ZAlkGWQpZDlkSWkwIEoDAABZb8oHAABZg9YWhwdjswAgAFAgBXAQQAAAAFAAcAAQBrY1cBFqICAIA+AADKlQYAGwKgMAAFmexhdg==")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQUAOzABAAEEAIEABQAAAAEA3JqBANmZBQFMBQAA8ZkA8pkyM++ZEwACoOAABZnzaW8Ba5cFAAEAADswAAABBQAqAAEAUo8qAPMCAXMBdpkFABsCoGAABZXnYWkBAwA7MAAAAQQAWhgBAHAQWhgrAqAgAAWYM2h1AQUAOzAAAAEEACwBAQAoliwBAQIAOzAAAAECAFoYAQDjSVoYAQEAOzAAAAECAFoYAQCIMVoYKwKgMAAEMrRkdQECADswAQADAgBaGAUAWhgBAC0ZWhgBAAgEWhgBBQA7MAAAAQQALAEBAPuULAHnDgCIQ0xigxvioMAABZnuBTQHOzADAA8AAFsYAgA1GwMAexMFAHwZJQAAAC8AAAA1AAAAOwAAAAIAvywAAEGCWhgBAPaSNRsBAMelexMDAOJXWhhsl5AApJiQAAEBADswAAABAQD0DwEAV9j0D2FKBQAtli6WL5YwljGWMpYzlgEAADswAAABBAAqAAEA2S8qADsDoNAABZl2Mmlz5QBGBQAN9ZlzEpYTlhSWFZYWlheWGJYZlhqWG5Yclh2WHpYfliCWAQIAOzAAAAEEACwBAQANNCwBGwKgMAAFljZheWFKBQAGlgeWCJYJlgqWC5YMlgEFADswAAABBQBXAQEA5x1XAQUBwAUADj2Y6NyZ3Znemd+Z4JnhmeKZ45nkmeWZ5pnnmeiZ6ZnqmWVpAQUAOzAAAAEFACwBAQC6HCwBYUkFAGKVY5VklWWVZpVnlWiVYUwFAPOW9Jb1lvaW95b4lvmWYUoFACaWJ5YolimWKpYrliyWBQHBBQAN2JkFIZZlb/sCb3IBAwA7MAAAAQQAggEBAKCkggEBAwA7MAAAAQQALAEBAHOjLAH7AnJ2AQMAOzABAAEEAFcBBQADAAEAtTJXAdqZ25nwmfSZAQHOoFAABZgBJB8EkgtmSy04cHV+LLpwlHaMG+jKVsA6GU+zXlx2XBJfrN86IHG5B13kHUJZDgavQDEvIT5jY0eS5MyDBWbhKk4YAS0WlidEoWAABZn0QD0WHzswAQADAQCtAQUAVgACAHJQLAHcWYAAAwB6JyoALpEqACOWAAD5AgAUbXQBCAA7MAAAAQUArwIBAOdErwIbhKDwAAWZ7KAAAAFZhaEgAAWZ9kAgIQUBwQUABCSWAP2WbHIFAcAFAAUFlgTsmWNktboAjAABoKAABZnrArAllv4AAQSgkAAFmdkaIyawdZlzAAEoO1EPOzAEAB8AANwCAQAsAQMArD4EAB8TBQBWAC0AAAA3AAAAPQAAAEcAAABVAAAAAgC5vFcAPtKEAgEA/gAsAQIA5AjkBzjJxzYDAAAAbxBVlywBoKSCAQIA5YNVAAWWAAA=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQcAOzAAAAEFAPQPAQDCR/QPAQIAOzAAAAECAPQPAQAhvvQPAQIAOzAAAAECAPQPAQAsrvQP8wADMTI2OzABAAIAAAAABAB7E4ISAQBoNXsT")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQEAOzAAAAEEAC0AAQBp+i0A8wIBZTswAAABBQCKAAIAFfCJAKL9AABhRwUAsfmy+bP5tPm1+bb5t/kBAwA7MAAAAQUAWwABADybWwCjAISwlfq0AAGgUAAFnCgBQAk7MAAAAQMAWwABACwAWwD7AmVv")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQMAOzAAAAEFALICAgBEibEC6vkAACFSBQCO/Y/9pP0hTQUA+vz7/Iv9MUsFALL7s/u0+yn984MDY2VzAQEAOzAAAAEDAC0AAQB1PS0AAQgAOzAAAAEFAJAAAQD5+ZAAAQIBoGAABfz5YzswAAABBQAtAAEAyPItAAUBxAUAaOr76/vs++377vvv+/D7ZaD6ofqi+qP6pPql+qb6b3MBCQA7MAAAAQUAkAABAFj8kABBQAUAqfmq+av5rPmm/UFABQCl+ab5p/mo+aX98wUCMjM7MAAAAQUAuQACAOHxuACj/QAA+wJhdQEFADswAAABBQDXFAEAidHXFAEDADswAAABBAAtAAEAT/stAPMAAmt1OzAAAAEDAHEIAQDhMHEIAQoAOzAAAAEFAEEBAQB390EBAQMBoDAABZwmZDswAAABAwBBAQEAyI1BAQEDADswAQABBACJAAUAAAABAJf6iQCf/QEEADswAAABBQAtAAEA5/gtAAEEADswAAABBQAtAAEAufgtAPMAAmx0OzABAAMDALcABABbAAEA5gC3AAEAQXpbABsCoGAABfmjb3IBBAA7MAAAAQUAQQEBAGVIQQH7AmlvAQEAOzABAAIEAAAABQAuAI6AAgApnC0A6fsAAAELADswAAABBQAVAAEAhfkVAAEAADswAAABBQDzAwEACp/zA/MDAXM7MAAAAQUAsQIBALKDsQJhRwUAfvl/+YD5gfmC+YP5hPkBAwA7MAAAAQUAsQIBAMX0sQIBAQA7MAAAAQUAsQIBAFicsQLzggJlaQEDADswAAABBQBBAQEAn/BBAfMBAWY7MAAAAQQAQQEBAMt6QQHzgoQQMQAbAqBgAAX7HWFvAQMAOzAAAAEEAC0AAQB9fS0AAQUAOzAAAAEFAC0AAQBb0S0A8wEBYzswAQADAwBbAAQAWwABAIoAWwABAOV5WwDzAAJhYzswAAABAQAtAAEAuWctAAEEADswAQADBAAtAAUALQABABn2LQABABaJLQABAQA7MAAAAQQAQQEBABx/QQFhRwUAnPmd+Z75n/mg+aH5ovlhSAUA8vnz+fT59fn2+ff5+PmTAwSgMAAF+rCgcAAF+/FhaHB2OzACAAUCAG8BBAAAAAUABwABABCObwHS9AIAJZwAAH75BgABAgA7MAAAAQQALQABAE99LQAbAqCgAAX5m2FvtwEAhaBwAAX51gyACjswAAABAQAtAAEAi2ctAPMA0cBvlF87MAMADwEAOwMDAA0aBAA7GgUAPBolAAAALwAAADUAAAA/AAAAAgAqC7EC8VyJAAEA4kcNGgIAo5gNGmn6LQADABUtDRqnSS0AuPkAAA==")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQIAOzAAAAEEACsAAQA7NSsAAQUBoGAABZlFYzswAAABBQAqAAEAfY8qAEFABQD1lfaV95X4lfKZQUAFAPGV8pXzlfSV8ZnzAgQyM2JyOzABAAMCAAMBBQCvAAEAlXgDAQMApY6sAHOZAQDvmQAABQBHBQAESJllNJYFAEkFAAbtmWU0mGFJBQBsmW2ZbplvmXCZcZlymbMFBKBQAAWVamFlc3bzApEFAPgFAQD7AmFm")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQQAOzAAAAEDAC0AAQCGRy0AAQgAOzAAAAEFAJAAAQD5+ZAA8wEBdTswAgAHAwANGgQADRoFAA0aAQDiRw0aAQCjmA0aAQAVLQ0a+wJldA==")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("YUUFAPL78/v0+/X79vv3+/j7AQAAOzAAAAEFAC0AAQBWgy0AAQUAOzAAAAEEAEEBAQDX9EEBVwEBhaAgAAMAiaAQAAX0ZmRAAjswAwANAQBcAAMAAAAEAC0ABQCnASUAAAArAAAALQAAADMAAAABAMsKXACeAQEAIfstAAgARnlvAfebLQCj+QAA1fkAALL7AgD6/AEAKf0AAIv9AQA=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQMAOzAAAAEFAC0AAQC5+C0AAQAAOzAAAAEBALECAQC9brECYUUFABb5F/kY+Rn5Gvkb+Rz5AQIAOzAAAAEFAC0AAQCndy0A+wJlcvMAA2RsbwIhMQAA1vkFAA==")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("BQFMBQAA8ZkA8pkyM++ZGwKg4AAFmfNpbwUBwAUADO6ZAzOYbnQHBoGIoCAABZb9oKAABZnroTAABZn2sCWW/gABoJAABZnZsHWZcwABOlAGAQAAAqNTAwAYogQA8wIBcjswAgAHAwBXAQQAVwEFAIQCAQCMB1cBAQDkSFcBAQAqKoQCAQYAOzAAAAEFAFUAAQDlg1UA+wJhafsCbG4=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQAAOzAAAAEFAC4AAgDepS0AFfkAAAEBADswAAABBQBBAQEABHhBASsDoRAABf0eoIAABZv0Y2luAQQAOzAAAAEEAEEBAQDN5kEBu4SgEAAF+dYBRAI=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("BQFMBQAApf0Apv0yM6P9GwKg4AAF/adpbwUBwAUADKL9A+f7bnQHBoGIoCAABfqxoKAABf2foTAABf2qsCX6sgABoJAABf2NsHX9JwABOlAGAQAAAgqPAwDU9AQA8wIBcjswAgAHAwBvAQQAbwEFALECAQCkPW8BAQBnlW8BAQBkhrECAQYAOzAAAAEFAFsAAQBh5lsA+wJhafsCbG4=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQMAOzAAAAEEAIMCAQCT6oMCAQQAOzAAAAEDAC0AAQCGRy0AAQgAOzAAAAEFAJAAAQD5+ZAA8wEBdTswAgAHAwANGgQADRoFAA0aAQDiRw0aAQCjmA0aAQAVLQ0a+wJldPsCc3Q=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQIBoDAABZVhZDswAAABBAAqAAEAlaEqAPMDAXM7MAAAAQEAKgABAFpZKgABAQA7MAAAAQAAWhgBADCkWhhhRAUAJpYnliiWKZYqliuWLJbzAAFlAqNTAwAYogQAAQMAOzAAAAEDAOQHAQDkCOQHAQAAOzABAAIAAAAABQAGABK9AQBsmQYA8wADZGhyOzAEAB4AAAAAAgCxAwMAVwEEANwDBQCaAi0AAAAvAAAANQAAADsAAABFAAAAWfQBAHHPsQMBAIwHVwECAORIVwEQn4QCAgAqKoQC1pYVAPsDZWlr")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQIAOzAAAAEFACwBAQB4jSwBAQMAOzAAAAEFACoAAQDVkCoAE4MDoFAABZYEoGAABZYjbnByWwOgEAAFPlJpb3I=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQsAOzAAAAEFAJAAAQBY/JAAI4ECoKAABfsUcHQVAEIFAAah/WWk+ej7+wJvdvMAAWk7MAAAAQQALQABAE/7LQA=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQQAOzAAAAEFABERAQCHTBER8wABZTswAQADAgANGgUADRoBAKQ+DRoBAJldDRoBAQA7MAAAAQQALQABAE/7LQD7Am55")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQMAOzAAAAECANcUAQDcj9cUAQMAOzAAAAEFAC0AAQDn+C0A8wABaTswAAABAACDAgEAHq2DAgEBADswAAABBQAtAAEAufgtAAEDADswAAABBQAtAAEAufgtAPMAAW8BITEAAOcBAIWgAAAFm/UgCBY7MAMABwAAQQEDALcABABbAAUAAQAlAAAALwAAADUAAAA7AAAAAgDNEy0AcioTAQEA5gC3AAEAQXpbALL6s/o=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("BQBFBQAHxfllFfsBBQA7MAAAAQUAMQADAPebLQD6/AEAi/0BADFLBQDj++T75fuq/TODA6CAAAX5xGxvchUARQUABqH9ZaT56Pv7Am5y8wACZXL04/sFAAEAAQDFAQ==")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("BQFMBQAApf0Apv0yM6P9GwKg4AAF/adpbwkDoEAABH2roMAABf2ioDAABfvnbW50DwaIoCAABfqxoKAABf2foTAABf2qsCX6sgABoJAABf2NsHX9JwABOlAG")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("YU4FABb7F/sY+xn7Gvsb+xz7AQcAOzAAAAEFAFsAAQC4+lsAAQkAOzAAAAEFAF4AAQD5+14A84MCZG0BDQA7MAAAAQUAXgABACz9XgDzAgF3OzABAAMDAD4EBADSDAEAwfs+BAEAAADSDPMCAmF3OzAAAAEBABERAQCDSxERAQMAOzAAAAEFAA0aAQBMtw0aMUIFAOP75Pvl+6r98wICZWk7MAAAAQUAkQACAPn5kAD5/AAAMU4FAI79j/2k/aj9AQIBoCAABdFaZjswAQABBABvAQUAAwABAKx9bwGO/Y/9pP2o/dcGAIegYAAF+cKgMAAF+cNBTQg7MAEAAgAAAAAFABER+xMBAIdMERE=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQQAOzAAAAEBALcAAQBKjbcAAQMAOzAAAAEFAC0AAQA49C0AE4QDoFAABfm4oGAABfnXbnByBQBBBQAAxPlzHvkBBwA7MAAAAQUAkAABACD7kAC/AYWgcAAF+rY1AAE=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQABoAAABfsfczswAgAHAACxAgEAQQEFAFwAAQDn4LECAQDpEkEBAgBh5lsAufkAAAEDADswAAABBQDXFAEAidHXFPsCaXQ=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQYAOzAAAAEFACoAAQADkSoA8wIBZQERlgUAAQcAOzAAAAEFAFsAAQAEl1sAAQkAOzAAAAEFAF4AAQBFmF4A84MCZG0BAQA7MAEAAwIAYQQDAIIDAQCe+2EEAQAAAIID4U0FADWZNpk3mTiZOZk6mTuZPJk9mT6ZP5lAmUGZQplDmQECADswAAABBQA2BgEAO4Q2BiMAAqCwAAWXYWVsOzAAAAEFAEYOAQBfL0YOAQAAOzAAAAECAPQPAQCp6/QPAQ0AOzAAAAEFAF4AAQB4mV4A8wEBdzswAAABAwD0DwEAQ7n0D/sCbHPzAIUJABY7MAEAAgAAAAABAB8Q3/YBAOc1HxD7AmVp")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQIAOzAAAAEFALECAQBkhrECAQYAOzAAAAEFAFsAAQBh5lsA84ICYWnzAAFpOzABAAMAAA4aBQDXFAIASHENGqKvAAABAInR1xQBDwA7MAAAAQUAkAABACD7kAABAgA7MAAAAQMALQABAEc9LQABBQA7MAAAAQUAsQIBAGSGsQLzAQFpOzAAAAEFANcUAQCJ0dcU+wJpbwEBADswAAABAQCxAgEAC2yxAvMAAWwBV5wFAPsEZG5xdA==")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQUBoAAABfvmczswAAABBQCxAgEAY+2xAgUBwAUACh796/78//wA/QH9Av0D/QT9Bf0G/Qf9CP0J/Qr9C/0M/WFvKwKgkAAF+cJwdGsDoEAABfz9ZnN3")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQYAOzAAAAEFAB4AAwAnnAAA6fwOAP78DgABBAA7MAAAAQUAsQIBAESJsQIFAEIFAOAN/Q79D/0Q/RH9Ev0T/RT9Ff0W/Rf9GP0Z/Rr9G/1zHfkBAwA7MAEAAgQAAAAFALECXoABANVJsQLnAQDFoGAABfseAEIBCgIqaQEAwfkFAA==")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("hQBABQAGof1lnPmd+Z75n/mg+aH5ovmk+ej78wEBczswAQACBAAAAAUAGQTT9AUAsHzzAyecAADy+QYA6fwOAP78DgA=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQEAOzAAAAEBAPQPAQBX2PQPBQBHBQAESJllNJYBAAGgQAAFlWpvOzAAAAEFABAAAwADlwAA3JkOAPWZAAAFAEkFAAbtmWU0mGFJBQBsmW2ZbplvmXCZcZlymVcDAcagwAAFmWmgEAAFPq9ARgAJOzACAAYAAAAABACAAAUAJgBm+QEAPEqAAAUAApEAAC2WBgD6lgEAYpcGABiYFQABAQGgMAAFPoFkOzABAAEDAIIBBQABAAIAdlIsAaRTVQBomXeZAQQAOzAAAAEEAIAAAQA8SoAAOwOgAAAFledhZmdhSgUALZYuli+WMJYxljKWM5YBAAA7MAAAAQQAKgABANkvKgA7A6DQAAWZdjJpc+UARgUADfWZcxKWE5YUlhWWFpYXlhiWGZYalhuWHJYdlh6WH5YglgECADswAAABBAAsAQEADTQsARsCoDAABZY2YXlhSgUABpYHlgiWCZYKlguWDJYBBQA7MAAAAQUAVwEBAOcdVwEFAcAFAA49mOjcmd2Z3pnfmeCZ4ZnimeOZ5JnlmeaZ55nomemZ6pllaQEFADswAAABBQAsAQEAuhwsAWFJBQBilWOVZJVllWaVZ5VolWFMBQDzlvSW9Zb2lveW+Jb5lmFKBQAmlieWKJYpliqWK5YslgUBwQUADdiZBSGWZW/7Am9yAQMAOzAAAAEEAIIBAQCgpIIBAQMAOzAAAAEEACwBAQBzoywB+wJydgEDADswAQABBABXAQUAAwABALUyVwHamduZ8Jn0mQEBzqBQAAWYASQfBJILZkstOHB1fiy6cJR2jBvoylbAOhlPs15cdlwSX6zfOiBxuQdd5B1CWQ4Gr0AxLyE+Y2NHkuTMgwVm4SpOGAEtFpYnRKFgAAWZ9EA9Fh87MAEAAwEArQEFAFYAAgByUCwB3FmAAAMAeicqAC6RKgAjlgAAAQIAOzAAAAEFACoAAQA2lSoAAQIAOzAAAAEFAIQCAQAqKoQCAQYAOzAAAAEFAFUAAQDlg1UA84ECYWndB4cAoHAABZguAwQYGyBFcAQ=")
|
||||
@@ -0,0 +1 @@
|
||||
rn_("AQIAOzAAAAEEAC4AAQBfgC4AAQMAOzAAAAEFAC0AAQDepS0A8wMBZAGjPQMAAQUBoGAABfz5YzswAAABBQAtAAEAyPItAEFABQCp+ar5q/ms+ab9QUAFAKX5pvmn+aj5pf3zAMWGBIAAOzABAAMCABUBBQC7AAEAtKQVAQMA4fG4ACf9AQCj/QAA")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQEAOzABAAMDAHsTBQCQAAEAx6V7EwEApJiQAAEBADswAQADAwCgEAQAhQIBAHopoBACADo1AACO8YQC+wJmdAEKADswAAABBQAVAAEA1pYVAAEDADswAAABAwBVAAEApFNVAFMCA6BAAAQ1Z2ltbzswAgADAQCDAQQAKgAFAAAAAgD9AAAA7E2CAQEAwKEqAGuZAQAAOzAAAAEBAFsYAgD8AAAAXVpaGPsDZGdu")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQEAOzAAAAEEACoAAQBQpyoA8wIBZTswAAABBQCBAAIA94yAAO6ZAABhRwUA/ZX+lf+VAJYBlgKWA5YBAwA7MAAAAQUAVQABAKY9VQCjAISwlZcAAAGgUAAFPoMBQAk7MAAAAQIAVQABABbOVQD7AmVv")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQABoAAABZdrczswAgAHAACEAgEALAEFAFYAAQA+0oQCAQD+ACwBAgDlg1UABZYAAAEDADswAAABBQB7EwEAaXB7E/sCaXQ=")
|
||||
@@ -1 +0,0 @@
|
||||
rn_("AQwAOzAAAAEFAJAAAQBsl5AAAQgAOzAAAAEFACsAAgCEPioANZgAAGMAA6BwAAU+gG1wczswAAABAABVAAEAE71VAA==")
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user