bandkit 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +260 -18
- package/dist/BandPanel.d.ts.map +1 -1
- package/dist/BandPanel.js +253 -80
- package/dist/BandPanel.js.map +1 -1
- package/dist/ContractEventFeed.d.ts +7 -0
- package/dist/ContractEventFeed.d.ts.map +1 -0
- package/dist/ContractEventFeed.js +76 -0
- package/dist/ContractEventFeed.js.map +1 -0
- package/dist/GasBadge.d.ts +6 -0
- package/dist/GasBadge.d.ts.map +1 -0
- package/dist/GasBadge.js +37 -0
- package/dist/GasBadge.js.map +1 -0
- package/dist/OrderBookWidget.d.ts +8 -0
- package/dist/OrderBookWidget.d.ts.map +1 -0
- package/dist/OrderBookWidget.js +92 -0
- package/dist/OrderBookWidget.js.map +1 -0
- package/dist/RegimeBadge.d.ts +6 -0
- package/dist/RegimeBadge.d.ts.map +1 -0
- package/dist/RegimeBadge.js +39 -0
- package/dist/RegimeBadge.js.map +1 -0
- package/dist/TradeTape.d.ts +8 -0
- package/dist/TradeTape.d.ts.map +1 -0
- package/dist/TradeTape.js +67 -0
- package/dist/TradeTape.js.map +1 -0
- package/dist/defaultStrategyWallet.d.ts +3 -0
- package/dist/defaultStrategyWallet.d.ts.map +1 -0
- package/dist/defaultStrategyWallet.js +39 -0
- package/dist/defaultStrategyWallet.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/useBinanceOrderBook.d.ts +27 -0
- package/dist/useBinanceOrderBook.d.ts.map +1 -0
- package/dist/useBinanceOrderBook.js +95 -0
- package/dist/useBinanceOrderBook.js.map +1 -0
- package/dist/useBinanceTrades.d.ts +23 -0
- package/dist/useBinanceTrades.d.ts.map +1 -0
- package/dist/useBinanceTrades.js +77 -0
- package/dist/useBinanceTrades.js.map +1 -0
- package/dist/useGasPrice.d.ts +18 -0
- package/dist/useGasPrice.d.ts.map +1 -0
- package/dist/useGasPrice.js +44 -0
- package/dist/useGasPrice.js.map +1 -0
- package/dist/useStrategyContractDeployment.d.ts.map +1 -1
- package/dist/useStrategyContractDeployment.js +2 -1
- package/dist/useStrategyContractDeployment.js.map +1 -1
- package/dist/useStrategyContractEvents.d.ts +23 -0
- package/dist/useStrategyContractEvents.d.ts.map +1 -0
- package/dist/useStrategyContractEvents.js +79 -0
- package/dist/useStrategyContractEvents.js.map +1 -0
- package/dist/useVolatilityRegime.d.ts +17 -0
- package/dist/useVolatilityRegime.d.ts.map +1 -0
- package/dist/useVolatilityRegime.js +48 -0
- package/dist/useVolatilityRegime.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,44 +1,135 @@
|
|
|
1
|
-
|
|
1
|
+
# bandkit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
React scaffolding for an Ethereum trading bot that lives behind a user-owned strategy contract. Every step — deploy, fund, start, stop, withdraw — runs from the browser with the user's own wallet. **No bot wallet, no custody, no hidden destinations.**
|
|
4
|
+
|
|
5
|
+
The package ships:
|
|
6
|
+
|
|
7
|
+
- `BandStrategy.sol` — a deposit/withdraw contract owned by the deploying wallet
|
|
8
|
+
- `BandExecutor.sol` — a restricted executor for the off-chain engine
|
|
9
|
+
- `<BandPanel />` — the full deploy → fund → start → stop → withdraw flow as a single staged React component (default title: **"Get started"**)
|
|
10
|
+
- Live market widgets: `<OrderBookWidget />`, `<TradeTape />`
|
|
11
|
+
- On-chain feed: `<ContractEventFeed />` (watches your deployed strategy contract's events)
|
|
12
|
+
- Context badges: `<RegimeBadge />` (volatility regime), `<GasBadge />` (mainnet gas price)
|
|
13
|
+
- A dark UI throughout
|
|
14
|
+
|
|
15
|
+
It does **not** ship trading strategy logic, signal generation, risk management, or the off-chain trade-execution daemon — those are out of scope.
|
|
4
16
|
|
|
5
17
|
## Install
|
|
6
18
|
|
|
7
19
|
```bash
|
|
8
|
-
npm install bandkit wagmi viem @
|
|
20
|
+
npm install bandkit wagmi viem @tanstack/react-query
|
|
21
|
+
# optional, for the Connect Wallet modal:
|
|
22
|
+
npm install @rainbow-me/rainbowkit
|
|
9
23
|
```
|
|
10
24
|
|
|
11
|
-
## Lovable
|
|
12
|
-
|
|
13
|
-
Paste this into Lovable when wiring the package into an existing RainbowKit/wagmi app:
|
|
25
|
+
## Lovable prompt (paste verbatim)
|
|
14
26
|
|
|
15
27
|
```text
|
|
16
|
-
|
|
28
|
+
Build a dark-themed Ethereum trading bot dashboard using the npm package
|
|
29
|
+
`bandkit` (NOT to be confused with Band Protocol — they are unrelated).
|
|
30
|
+
Also install: wagmi, viem, @tanstack/react-query, @rainbow-me/rainbowkit.
|
|
31
|
+
|
|
32
|
+
Default network: Ethereum mainnet. Use a placeholder WalletConnect projectId.
|
|
33
|
+
Build the wagmi config with `createBandKitConfig` from bandkit.
|
|
34
|
+
|
|
35
|
+
Wrap the app (outside to inside):
|
|
36
|
+
WagmiProvider → QueryClientProvider → RainbowKitProvider (with darkTheme())
|
|
37
|
+
|
|
38
|
+
Page layout — single centered column on a near-black background (#0a0a0a),
|
|
39
|
+
max-width 1100px, gap 20px, system font stack:
|
|
17
40
|
|
|
18
|
-
|
|
41
|
+
┌─────────────────────────────────────────────────────┐
|
|
42
|
+
│ [ GasBadge ] [ RegimeBadge ] [ConnectButton]│ ← top bar
|
|
43
|
+
├─────────────────────────────────────────────────────┤
|
|
44
|
+
│ │
|
|
45
|
+
│ TradingView Advanced Chart │ ← ETHUSD on COINBASE,
|
|
46
|
+
│ (height 420px, dark theme) │ dark theme
|
|
47
|
+
│ │
|
|
48
|
+
├──────────────────────┬──────────────────────────────┤
|
|
49
|
+
│ │ │
|
|
50
|
+
│ <BandPanel /> │ <OrderBookWidget /> │ ← two-column split
|
|
51
|
+
│ (the bot UI: it │ │ on >=900px wide,
|
|
52
|
+
│ has its own deploy,├──────────────────────────────┤ stacked below
|
|
53
|
+
│ fund, start, stop, │ <TradeTape /> │
|
|
54
|
+
│ withdraw buttons. │ │
|
|
55
|
+
│ Default title is ├──────────────────────────────┤
|
|
56
|
+
│ "Get started") │ <ContractEventFeed │
|
|
57
|
+
│ │ strategyContractAddress= │
|
|
58
|
+
│ │ {deployedAddress} /> │
|
|
59
|
+
└──────────────────────┴──────────────────────────────┘
|
|
19
60
|
|
|
20
|
-
|
|
61
|
+
Components to import from bandkit:
|
|
62
|
+
- BandPanel (the main staged UI)
|
|
63
|
+
- OrderBookWidget (live Binance ETH/USDT depth)
|
|
64
|
+
- TradeTape (live recent trades)
|
|
65
|
+
- ContractEventFeed (on-chain events from the deployed strategy)
|
|
66
|
+
- RegimeBadge (RANGING / MIXED / TRENDING based on volatility)
|
|
67
|
+
- GasBadge (current mainnet gas price)
|
|
68
|
+
|
|
69
|
+
Wire BandPanel's `onStrategyContractDeployed` callback to lift the deployed
|
|
70
|
+
contract address into page state, and pass it as ContractEventFeed's
|
|
71
|
+
`strategyContractAddress` prop so the feed activates the moment the contract
|
|
72
|
+
is live.
|
|
73
|
+
|
|
74
|
+
DO NOT add: grid ladders, BUY/SELL order lists, "Build Grid" buttons,
|
|
75
|
+
custom contract calls, fake order books, simulated balances, profit
|
|
76
|
+
projections, "Band Protocol" labels, hardcoded contract addresses, or any
|
|
77
|
+
extra send-ETH buttons. BandPanel is the entire user lifecycle — do not
|
|
78
|
+
duplicate any of its actions elsewhere on the page.
|
|
21
79
|
```
|
|
22
80
|
|
|
23
|
-
## Minimal
|
|
81
|
+
## Minimal app
|
|
24
82
|
|
|
25
83
|
```tsx
|
|
84
|
+
import { useState } from "react";
|
|
26
85
|
import "@rainbow-me/rainbowkit/styles.css";
|
|
27
|
-
import { ConnectButton, RainbowKitProvider } from "@rainbow-me/rainbowkit";
|
|
86
|
+
import { ConnectButton, RainbowKitProvider, darkTheme } from "@rainbow-me/rainbowkit";
|
|
28
87
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
29
88
|
import { WagmiProvider } from "wagmi";
|
|
30
|
-
import {
|
|
89
|
+
import type { Address } from "viem";
|
|
90
|
+
import {
|
|
91
|
+
BandPanel,
|
|
92
|
+
ContractEventFeed,
|
|
93
|
+
GasBadge,
|
|
94
|
+
OrderBookWidget,
|
|
95
|
+
RegimeBadge,
|
|
96
|
+
TradeTape,
|
|
97
|
+
createBandKitConfig
|
|
98
|
+
} from "bandkit";
|
|
31
99
|
|
|
32
100
|
const queryClient = new QueryClient();
|
|
33
|
-
const config = createBandKitConfig({
|
|
101
|
+
const config = createBandKitConfig({
|
|
102
|
+
appName: "Get started",
|
|
103
|
+
walletConnectProjectId: "REPLACE_ME"
|
|
104
|
+
});
|
|
34
105
|
|
|
35
106
|
export function App() {
|
|
107
|
+
const [strategy, setStrategy] = useState<Address>();
|
|
108
|
+
|
|
36
109
|
return (
|
|
37
110
|
<WagmiProvider config={config}>
|
|
38
111
|
<QueryClientProvider client={queryClient}>
|
|
39
|
-
<RainbowKitProvider>
|
|
40
|
-
<
|
|
41
|
-
|
|
112
|
+
<RainbowKitProvider theme={darkTheme()}>
|
|
113
|
+
<div style={{ background: "#0a0a0a", color: "#f5f5f7", minHeight: "100vh", padding: 24 }}>
|
|
114
|
+
<div style={{ display: "grid", gap: 20, margin: "0 auto", maxWidth: 1100 }}>
|
|
115
|
+
<div style={{ alignItems: "center", display: "flex", gap: 12, justifyContent: "flex-end" }}>
|
|
116
|
+
<GasBadge />
|
|
117
|
+
<RegimeBadge />
|
|
118
|
+
<ConnectButton />
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
{/* TradingView ETHUSD chart embed here */}
|
|
122
|
+
|
|
123
|
+
<div style={{ display: "grid", gap: 20, gridTemplateColumns: "minmax(0, 1fr) 360px" }}>
|
|
124
|
+
<BandPanel onStrategyContractDeployed={setStrategy} />
|
|
125
|
+
<div style={{ display: "grid", gap: 20 }}>
|
|
126
|
+
<OrderBookWidget />
|
|
127
|
+
<TradeTape />
|
|
128
|
+
<ContractEventFeed strategyContractAddress={strategy} />
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
42
133
|
</RainbowKitProvider>
|
|
43
134
|
</QueryClientProvider>
|
|
44
135
|
</WagmiProvider>
|
|
@@ -46,6 +137,157 @@ export function App() {
|
|
|
46
137
|
}
|
|
47
138
|
```
|
|
48
139
|
|
|
49
|
-
##
|
|
140
|
+
## What each stage of `<BandPanel />` does
|
|
141
|
+
|
|
142
|
+
| Stage | UI button | On-chain call | What changes |
|
|
143
|
+
|---|---|---|---|
|
|
144
|
+
| 1. Connect Wallet | (from RainbowKit) | none | wagmi session established |
|
|
145
|
+
| 2. Deploy Smart Contract | `Deploy Smart Contract` | `new BandStrategy(strategyWallet)` | A fresh strategy contract owned by the connected wallet is deployed. Address saved to `localStorage`. |
|
|
146
|
+
| 3. Fund Smart Contract | `Fund Smart Contract` | `BandStrategy.deposit() payable` | ETH moves from your wallet into the strategy contract. Can be called multiple times. |
|
|
147
|
+
| 4a. Start Bot | `▶ Start Bot` | `BandStrategy.activateStrategyEngine()` | **Transfers all of your contract balance to `strategyWallet`** and marks the engine active. Header shows a pulsing ACTIVE badge. |
|
|
148
|
+
| 4b. Stop Bot | `■ Stop Bot` | `BandStrategy.deactivateStrategyEngine()` | Marks the engine inactive. Does *not* move funds back. |
|
|
149
|
+
| 4c. Withdraw | `Withdraw All Contract ETH to Wallet` | `BandStrategy.withdrawAll()` | Returns any ETH still in the contract back to your wallet. Only works for funds you have not yet sent to the engine via Start. |
|
|
150
|
+
|
|
151
|
+
> **Order matters.** Withdraw only returns funds still held by the contract. Once you press **Start**, your contract balance is transferred to `strategyWallet` and can no longer be retrieved by `withdrawAll()`. Decide whether to Start before depositing more than you're willing to commit.
|
|
152
|
+
|
|
153
|
+
## Components
|
|
154
|
+
|
|
155
|
+
### `<BandPanel />`
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
type BandPanelProps = {
|
|
159
|
+
strategyContractAddress?: Address; // skip Stage 2 if already deployed
|
|
160
|
+
strategyWalletAddress?: Address; // destination for trade outputs (default: connected wallet)
|
|
161
|
+
chainId?: number; // default: mainnet (1)
|
|
162
|
+
className?: string;
|
|
163
|
+
title?: string; // default: "Get started"
|
|
164
|
+
onSubmitted?: (hash: string, action: StrategyContractAction) => void;
|
|
165
|
+
onStrategyContractDeployed?: (address: Address) => void;
|
|
166
|
+
};
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### `<OrderBookWidget />`
|
|
170
|
+
|
|
171
|
+
Live Binance order book (default ETH/USDT, depth 20, throttled 100ms).
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
type OrderBookWidgetProps = {
|
|
175
|
+
className?: string;
|
|
176
|
+
title?: string; // default: "Order Book"
|
|
177
|
+
rows?: number; // default: 10
|
|
178
|
+
symbol?: string; // default: "ethusdt"
|
|
179
|
+
depth?: 5 | 10 | 20; // default: 20
|
|
180
|
+
enabled?: boolean;
|
|
181
|
+
};
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### `<TradeTape />`
|
|
185
|
+
|
|
186
|
+
Scrolling list of recent Binance trades, color-coded by side.
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
type TradeTapeProps = {
|
|
190
|
+
className?: string;
|
|
191
|
+
title?: string; // default: "Recent Trades"
|
|
192
|
+
rows?: number; // default: 20
|
|
193
|
+
symbol?: string; // default: "ethusdt"
|
|
194
|
+
enabled?: boolean;
|
|
195
|
+
};
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### `<ContractEventFeed />`
|
|
199
|
+
|
|
200
|
+
Watches your deployed strategy contract's `Deposited` / `Withdrawn` / `StrategyEngineActivated` / `StrategyEngineDeactivated` events live.
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
type ContractEventFeedProps = {
|
|
204
|
+
strategyContractAddress?: Address; // pass the deployed address; feed is dormant without it
|
|
205
|
+
chainId?: number;
|
|
206
|
+
maxEvents?: number; // default: 25
|
|
207
|
+
enabled?: boolean;
|
|
208
|
+
className?: string;
|
|
209
|
+
title?: string; // default: "Contract Activity"
|
|
210
|
+
};
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### `<RegimeBadge />`
|
|
214
|
+
|
|
215
|
+
Computes rolling stddev + drift over the live ETH price stream and classifies as `RANGING` / `MIXED` / `TRENDING` / `WARMING UP`.
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
type RegimeBadgeProps = {
|
|
219
|
+
windowSize?: number; // default: 60 ticks
|
|
220
|
+
rangingThresholdPct?: number; // default: 0.15 (stddev %)
|
|
221
|
+
trendingThresholdPct?: number; // default: 0.45 (|drift| %)
|
|
222
|
+
enabled?: boolean;
|
|
223
|
+
className?: string;
|
|
224
|
+
};
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### `<GasBadge />`
|
|
228
|
+
|
|
229
|
+
Current mainnet gas price, color-coded by tier (low/normal/high/spike).
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
type GasBadgeProps = {
|
|
233
|
+
chainId?: number; // default: mainnet (1)
|
|
234
|
+
pollingIntervalMs?: number; // default: 12000
|
|
235
|
+
lowThresholdGwei?: number; // default: 15
|
|
236
|
+
highThresholdGwei?: number; // default: 40
|
|
237
|
+
spikeThresholdGwei?: number; // default: 100
|
|
238
|
+
enabled?: boolean;
|
|
239
|
+
className?: string;
|
|
240
|
+
};
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Hooks (use directly to build your own UI)
|
|
244
|
+
|
|
245
|
+
| Hook | Returns |
|
|
246
|
+
|---|---|
|
|
247
|
+
| `useBandDashboard` | Aggregated dashboard state (deployment, balance, engine, ETH price). |
|
|
248
|
+
| `useStrategyContract` | `depositEth`, `withdrawEth`, `withdrawAll`, `activateStrategyEngine`, `deactivateStrategyEngine`, plus reactive balances. |
|
|
249
|
+
| `useStrategyContractDeployment` | `deployStrategyContract()`, deployment status, localStorage persistence. |
|
|
250
|
+
| `useEthPriceTicker` | Live ETH/USDT price + 24h change from Binance. |
|
|
251
|
+
| `useBinanceOrderBook` | Live bid/ask depth ladder. |
|
|
252
|
+
| `useBinanceTrades` | Stream of recent trades. |
|
|
253
|
+
| `useStrategyContractEvents` | Live on-chain events from your deployed strategy. |
|
|
254
|
+
| `useVolatilityRegime` | Rolling stddev/drift classification: RANGING / MIXED / TRENDING. |
|
|
255
|
+
| `useGasPrice` | Current gas price + tier classification. |
|
|
256
|
+
| `useWalletEthBalance` | Connected wallet's ETH balance. |
|
|
257
|
+
|
|
258
|
+
## Contracts
|
|
259
|
+
|
|
260
|
+
- `contracts/BandStrategy.sol` — deposit/withdraw vault, owner = deployer.
|
|
261
|
+
- `contracts/BandExecutor.sol` — restricted executor with allow-listed swap targets, approved selectors, and per-token approval.
|
|
262
|
+
|
|
263
|
+
Build & test:
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
npm run compile:contracts
|
|
267
|
+
npm test
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Deploy via Hardhat:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
npm run deploy:mainnet
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
You usually don't need this script — `<BandPanel />` deploys the strategy contract from the user's browser wallet.
|
|
277
|
+
|
|
278
|
+
## Out of scope (important)
|
|
279
|
+
|
|
280
|
+
- **Strategy logic.** No Bollinger, grid, MACD, signal generation. You write this.
|
|
281
|
+
- **The off-chain engine.** The `Start Bot` button transfers ETH to `strategyWallet` and flips an on-chain flag. Actual trades require a Node process (`engine/executor-searcher.js`) running on a server you control, calling `BandExecutor.executeTrade`. Without it, no trades happen.
|
|
282
|
+
- **Profit guarantees, backtesting, simulated results.**
|
|
283
|
+
|
|
284
|
+
## Security notes
|
|
285
|
+
|
|
286
|
+
- The connected wallet owns the strategy contract; only the owner can withdraw funds.
|
|
287
|
+
- The Start Bot button **moves funds** — it does not merely authorize. After Start, `withdrawAll()` returns nothing (your contract balance is 0); recovery has to come from the strategyWallet operator off-chain.
|
|
288
|
+
- `<BandPanel />` defaults `strategyWallet` to the connected wallet, so by default funds stay with the deployer.
|
|
289
|
+
- The package contains no hardcoded wallet addresses.
|
|
290
|
+
|
|
291
|
+
## License
|
|
50
292
|
|
|
51
|
-
|
|
293
|
+
MIT.
|
package/dist/BandPanel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BandPanel.d.ts","sourceRoot":"","sources":["../src/BandPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAGpC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAEvE,MAAM,MAAM,cAAc,GAAG;IAC3B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACrE,0BAA0B,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACzD,CAAC;
|
|
1
|
+
{"version":3,"file":"BandPanel.d.ts","sourceRoot":"","sources":["../src/BandPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAGpC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAEvE,MAAM,MAAM,cAAc,GAAG;IAC3B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACrE,0BAA0B,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACzD,CAAC;AAgFF,wBAAgB,SAAS,CAAC,EACxB,uBAAuB,EACvB,qBAAqB,EACrB,OAAoB,EACpB,SAAS,EACT,KAAqB,EACrB,WAAW,EACX,0BAA0B,EAC3B,EAAE,cAAc,2CA0ThB"}
|