@wzrd_sol/solana-agent-plugin 0.1.0 → 0.1.1

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/dist/index.d.ts CHANGED
@@ -12,7 +12,7 @@
12
12
  *
13
13
  * Works with:
14
14
  * - Solana Agent Kit (SendAI) — register as plugin
15
- * - ElizaOS — wrap actions as ElizaOS Actions
15
+ * - ElizaOS — wrap actions as ELIZA-style actions
16
16
  * - Standalone — use WzrdClient directly
17
17
  *
18
18
  * Quick start:
@@ -23,275 +23,20 @@
23
23
  export { WzrdClient } from './client.js';
24
24
  export type { WzrdMarket, WzrdLeaderboard, WzrdPosition, WzrdPortfolio, WzrdClaim, WzrdRelayResult, } from './client.js';
25
25
  export { LEADERBOARD_ACTION, PORTFOLIO_ACTION, DEPOSIT_ACTION, CLAIM_ACTION, VELOCITY_ACTION, } from './actions/index.js';
26
- export declare const WZRD_ACTIONS: readonly [{
27
- name: string;
28
- similes: string[];
29
- description: string;
30
- examples: {
31
- user: string;
32
- content: {
33
- text: string;
34
- };
35
- }[][];
36
- validate: () => Promise<boolean>;
37
- handler: (client: import("./client.js").WzrdClient, params: {
38
- limit?: number;
39
- platform?: string;
40
- }) => Promise<{
41
- success: boolean;
42
- text: string;
43
- data: import("./client.js").WzrdLeaderboard;
44
- }>;
45
- }, {
46
- name: string;
47
- similes: string[];
48
- description: string;
49
- examples: {
50
- user: string;
51
- content: {
52
- text: string;
53
- };
54
- }[][];
55
- validate: () => Promise<boolean>;
56
- handler: (client: import("./client.js").WzrdClient) => Promise<{
57
- success: boolean;
58
- text: string;
59
- data: import("./client.js").WzrdPortfolio;
60
- }>;
61
- }, {
62
- name: string;
63
- similes: string[];
64
- description: string;
65
- examples: {
66
- user: string;
67
- content: {
68
- text: string;
69
- };
70
- }[][];
71
- validate: (_client: import("./client.js").WzrdClient, params: import("./actions/deposit.js").DepositParams) => Promise<boolean>;
72
- handler: (_client: import("./client.js").WzrdClient, params: import("./actions/deposit.js").DepositParams, connection: import("@solana/web3.js").Connection, wallet: import("@solana/web3.js").Keypair) => Promise<{
73
- success: boolean;
74
- text: string;
75
- data?: undefined;
76
- } | {
77
- success: boolean;
78
- text: string;
79
- data: {
80
- logs: string[] | undefined;
81
- signature?: undefined;
82
- market_id?: undefined;
83
- amount_usdc?: undefined;
84
- cu_used?: undefined;
85
- elapsed_ms?: undefined;
86
- explorer?: undefined;
87
- };
88
- } | {
89
- success: boolean;
90
- text: string;
91
- data: {
92
- signature: string;
93
- market_id: number;
94
- amount_usdc: number;
95
- cu_used: number | undefined;
96
- elapsed_ms: number;
97
- explorer: string;
98
- logs?: undefined;
99
- };
100
- }>;
101
- }, {
102
- name: string;
103
- similes: string[];
104
- description: string;
105
- examples: {
106
- user: string;
107
- content: {
108
- text: string;
109
- };
110
- }[][];
111
- validate: () => Promise<boolean>;
112
- handler: (client: import("./client.js").WzrdClient, params: {
113
- execute?: boolean;
114
- }) => Promise<{
115
- success: boolean;
116
- text: string;
117
- data: import("./client.js").WzrdClaim;
118
- } | {
119
- success: boolean;
120
- text: string;
121
- data: {
122
- claimable_before: number;
123
- explorer: string;
124
- root_seq: number;
125
- cumulative_total: number;
126
- tx_sig: string;
127
- };
128
- }>;
129
- }, {
130
- name: string;
131
- similes: string[];
132
- description: string;
133
- examples: {
134
- user: string;
135
- content: {
136
- text: string;
137
- };
138
- }[][];
139
- validate: () => Promise<boolean>;
140
- handler: (client: import("./client.js").WzrdClient, params: {
141
- platform?: string;
142
- min_signal?: "BREAKOUT" | "MOMENTUM" | "EMERGING" | "STABLE" | "COOLING" | "WEAK";
143
- }) => Promise<{
144
- success: boolean;
145
- text: string;
146
- data: {
147
- signals: never[];
148
- median_velocity?: undefined;
149
- };
150
- } | {
151
- success: boolean;
152
- text: string;
153
- data: {
154
- signals: import("./actions/velocity.js").MarketSignal[];
155
- median_velocity: number;
156
- };
157
- }>;
158
- }];
159
- /** Plugin metadata for framework registration. */
160
- export declare const WZRD_PLUGIN: {
161
- name: string;
162
- description: string;
163
- actions: readonly [{
164
- name: string;
165
- similes: string[];
166
- description: string;
167
- examples: {
168
- user: string;
169
- content: {
170
- text: string;
171
- };
172
- }[][];
173
- validate: () => Promise<boolean>;
174
- handler: (client: import("./client.js").WzrdClient, params: {
175
- limit?: number;
176
- platform?: string;
177
- }) => Promise<{
178
- success: boolean;
179
- text: string;
180
- data: import("./client.js").WzrdLeaderboard;
181
- }>;
182
- }, {
183
- name: string;
184
- similes: string[];
185
- description: string;
186
- examples: {
187
- user: string;
188
- content: {
189
- text: string;
190
- };
191
- }[][];
192
- validate: () => Promise<boolean>;
193
- handler: (client: import("./client.js").WzrdClient) => Promise<{
194
- success: boolean;
195
- text: string;
196
- data: import("./client.js").WzrdPortfolio;
197
- }>;
198
- }, {
199
- name: string;
200
- similes: string[];
201
- description: string;
202
- examples: {
203
- user: string;
204
- content: {
205
- text: string;
206
- };
207
- }[][];
208
- validate: (_client: import("./client.js").WzrdClient, params: import("./actions/deposit.js").DepositParams) => Promise<boolean>;
209
- handler: (_client: import("./client.js").WzrdClient, params: import("./actions/deposit.js").DepositParams, connection: import("@solana/web3.js").Connection, wallet: import("@solana/web3.js").Keypair) => Promise<{
210
- success: boolean;
211
- text: string;
212
- data?: undefined;
213
- } | {
214
- success: boolean;
215
- text: string;
216
- data: {
217
- logs: string[] | undefined;
218
- signature?: undefined;
219
- market_id?: undefined;
220
- amount_usdc?: undefined;
221
- cu_used?: undefined;
222
- elapsed_ms?: undefined;
223
- explorer?: undefined;
224
- };
225
- } | {
226
- success: boolean;
227
- text: string;
228
- data: {
229
- signature: string;
230
- market_id: number;
231
- amount_usdc: number;
232
- cu_used: number | undefined;
233
- elapsed_ms: number;
234
- explorer: string;
235
- logs?: undefined;
236
- };
237
- }>;
238
- }, {
239
- name: string;
240
- similes: string[];
241
- description: string;
242
- examples: {
243
- user: string;
244
- content: {
245
- text: string;
246
- };
247
- }[][];
248
- validate: () => Promise<boolean>;
249
- handler: (client: import("./client.js").WzrdClient, params: {
250
- execute?: boolean;
251
- }) => Promise<{
252
- success: boolean;
253
- text: string;
254
- data: import("./client.js").WzrdClaim;
255
- } | {
256
- success: boolean;
257
- text: string;
258
- data: {
259
- claimable_before: number;
260
- explorer: string;
261
- root_seq: number;
262
- cumulative_total: number;
263
- tx_sig: string;
264
- };
265
- }>;
266
- }, {
267
- name: string;
268
- similes: string[];
269
- description: string;
270
- examples: {
271
- user: string;
272
- content: {
273
- text: string;
274
- };
275
- }[][];
276
- validate: () => Promise<boolean>;
277
- handler: (client: import("./client.js").WzrdClient, params: {
278
- platform?: string;
279
- min_signal?: "BREAKOUT" | "MOMENTUM" | "EMERGING" | "STABLE" | "COOLING" | "WEAK";
280
- }) => Promise<{
281
- success: boolean;
282
- text: string;
283
- data: {
284
- signals: never[];
285
- median_velocity?: undefined;
286
- };
287
- } | {
288
- success: boolean;
289
- text: string;
290
- data: {
291
- signals: import("./actions/velocity.js").MarketSignal[];
292
- median_velocity: number;
293
- };
294
- }>;
295
- }];
296
- version: string;
297
- };
26
+ export type { MarketSignal } from './actions/index.js';
27
+ import type { Plugin } from 'solana-agent-kit';
28
+ import { getClaimsData, getClientForAgent, getLeaderboardData } from './runtime.js';
29
+ import { type MarketSignal } from './actions/velocity.js';
30
+ export declare const WZRD_ACTIONS: Plugin["actions"];
31
+ export interface WzrdPluginMethods {
32
+ wzrdLeaderboard(limit?: number, platform?: string): Promise<ReturnType<typeof getLeaderboardData>>;
33
+ wzrdPortfolio(): Promise<ReturnType<typeof getClientForAgent>['getPortfolio']>;
34
+ wzrdClaims(): Promise<ReturnType<typeof getClaimsData>>;
35
+ wzrdDeposit(marketId: number, amountUsdc: number, priorityFee?: number): Promise<Record<string, unknown>>;
36
+ wzrdClaim(execute?: boolean): Promise<Record<string, unknown>>;
37
+ wzrdVelocity(platform?: string, minSignal?: MarketSignal['signal']): Promise<Record<string, unknown>>;
38
+ wzrdClient(): ReturnType<typeof getClientForAgent>;
39
+ }
40
+ export declare function createWzrdPlugin(): Plugin;
41
+ /** Default plugin instance for direct registration via `agent.use(...)`. */
42
+ export declare const WZRD_PLUGIN: Plugin;
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@
12
12
  *
13
13
  * Works with:
14
14
  * - Solana Agent Kit (SendAI) — register as plugin
15
- * - ElizaOS — wrap actions as ElizaOS Actions
15
+ * - ElizaOS — wrap actions as ELIZA-style actions
16
16
  * - Standalone — use WzrdClient directly
17
17
  *
18
18
  * Quick start:
@@ -22,12 +22,12 @@
22
22
  */
23
23
  export { WzrdClient } from './client.js';
24
24
  export { LEADERBOARD_ACTION, PORTFOLIO_ACTION, DEPOSIT_ACTION, CLAIM_ACTION, VELOCITY_ACTION, } from './actions/index.js';
25
- // ── Convenience: all actions as array ────────────────────
25
+ import { getClaimsData, getClientForAgent, getLeaderboardData } from './runtime.js';
26
26
  import { LEADERBOARD_ACTION } from './actions/leaderboard.js';
27
27
  import { PORTFOLIO_ACTION } from './actions/portfolio.js';
28
- import { DEPOSIT_ACTION } from './actions/deposit.js';
29
- import { CLAIM_ACTION } from './actions/claim.js';
30
- import { VELOCITY_ACTION } from './actions/velocity.js';
28
+ import { DEPOSIT_ACTION, depositHandler } from './actions/deposit.js';
29
+ import { CLAIM_ACTION, claimHandler } from './actions/claim.js';
30
+ import { VELOCITY_ACTION, velocityHandler } from './actions/velocity.js';
31
31
  export const WZRD_ACTIONS = [
32
32
  LEADERBOARD_ACTION,
33
33
  PORTFOLIO_ACTION,
@@ -35,10 +35,51 @@ export const WZRD_ACTIONS = [
35
35
  CLAIM_ACTION,
36
36
  VELOCITY_ACTION,
37
37
  ];
38
- /** Plugin metadata for framework registration. */
39
- export const WZRD_PLUGIN = {
40
- name: 'wzrd',
41
- description: 'WZRD Liquid Attention Protocol — deposit USDC into AI attention markets, earn CCM yield',
42
- actions: WZRD_ACTIONS,
43
- version: '0.1.0',
44
- };
38
+ export function createWzrdPlugin() {
39
+ let agentRef = null;
40
+ const requireAgent = () => {
41
+ if (!agentRef) {
42
+ throw new Error('WZRD plugin has not been initialized with a SolanaAgentKit instance');
43
+ }
44
+ return agentRef;
45
+ };
46
+ return {
47
+ name: 'wzrd',
48
+ initialize(agent) {
49
+ agentRef = agent;
50
+ },
51
+ methods: {
52
+ wzrdClient() {
53
+ return getClientForAgent(requireAgent());
54
+ },
55
+ async wzrdLeaderboard(limit = 20, platform) {
56
+ return getLeaderboardData(requireAgent(), { limit, platform });
57
+ },
58
+ async wzrdPortfolio() {
59
+ return getClientForAgent(requireAgent()).getPortfolio();
60
+ },
61
+ async wzrdClaims() {
62
+ return getClaimsData(requireAgent());
63
+ },
64
+ async wzrdDeposit(marketId, amountUsdc, priorityFee) {
65
+ return depositHandler(requireAgent(), {
66
+ market_id: marketId,
67
+ amount_usdc: amountUsdc,
68
+ priority_fee: priorityFee,
69
+ });
70
+ },
71
+ async wzrdClaim(execute = true) {
72
+ return claimHandler(requireAgent(), { execute });
73
+ },
74
+ async wzrdVelocity(platform, minSignal) {
75
+ return velocityHandler(requireAgent(), {
76
+ platform,
77
+ min_signal: minSignal,
78
+ });
79
+ },
80
+ },
81
+ actions: WZRD_ACTIONS,
82
+ };
83
+ }
84
+ /** Default plugin instance for direct registration via `agent.use(...)`. */
85
+ export const WZRD_PLUGIN = createWzrdPlugin();
@@ -0,0 +1,16 @@
1
+ import { PublicKey } from '@solana/web3.js';
2
+ import type { SolanaAgentKit } from 'solana-agent-kit';
3
+ import { WzrdClient, type WzrdClaim, type WzrdLeaderboard, type WzrdPortfolio } from './client.js';
4
+ export type SignalTier = 'BREAKOUT' | 'MOMENTUM' | 'EMERGING' | 'STABLE' | 'COOLING' | 'WEAK';
5
+ export declare function resolveApiUrl(explicit?: string): string;
6
+ export declare function getClientForAgent(agent: SolanaAgentKit, apiUrl?: string): WzrdClient;
7
+ export declare function getWalletPublicKey(agent: SolanaAgentKit): PublicKey;
8
+ export declare function formatVelocity(v: number): string;
9
+ export declare function formatUsdc(nativeAmount: number | bigint): string;
10
+ export declare function formatCcm(nativeAmount: number | bigint): string;
11
+ export declare function getLeaderboardData(agent: SolanaAgentKit, input: {
12
+ limit?: number;
13
+ platform?: string;
14
+ }): Promise<WzrdLeaderboard>;
15
+ export declare function getPortfolioData(agent: SolanaAgentKit): Promise<WzrdPortfolio>;
16
+ export declare function getClaimsData(agent: SolanaAgentKit): Promise<WzrdClaim>;
@@ -0,0 +1,33 @@
1
+ import { DEFAULT_API_URL, WzrdClient, } from './client.js';
2
+ export function resolveApiUrl(explicit) {
3
+ const envUrl = process.env.WZRD_API_URL?.trim();
4
+ return explicit?.trim() || envUrl || DEFAULT_API_URL;
5
+ }
6
+ export function getClientForAgent(agent, apiUrl) {
7
+ return new WzrdClient(agent.wallet, resolveApiUrl(apiUrl));
8
+ }
9
+ export function getWalletPublicKey(agent) {
10
+ return agent.wallet.publicKey;
11
+ }
12
+ export function formatVelocity(v) {
13
+ if (v >= 1_000_000)
14
+ return `${(v / 1_000_000).toFixed(1)}M`;
15
+ if (v >= 1_000)
16
+ return `${(v / 1_000).toFixed(0)}K`;
17
+ return v.toFixed(0);
18
+ }
19
+ export function formatUsdc(nativeAmount) {
20
+ return (Number(nativeAmount) / 1_000_000).toFixed(4);
21
+ }
22
+ export function formatCcm(nativeAmount) {
23
+ return (Number(nativeAmount) / 1_000_000).toFixed(4);
24
+ }
25
+ export async function getLeaderboardData(agent, input) {
26
+ return getClientForAgent(agent).getLeaderboard(input.limit ?? 10, input.platform);
27
+ }
28
+ export async function getPortfolioData(agent) {
29
+ return getClientForAgent(agent).getPortfolio();
30
+ }
31
+ export async function getClaimsData(agent) {
32
+ return getClientForAgent(agent).getClaims();
33
+ }
@@ -18,7 +18,7 @@
18
18
 
19
19
  import { readFileSync } from 'node:fs';
20
20
  import { Keypair } from '@solana/web3.js';
21
- import { WzrdClient } from '../dist/index.js';
21
+ import { WzrdClient } from '@wzrd_sol/solana-agent-plugin';
22
22
 
23
23
  const KEYPAIR_PATH = process.env.WZRD_KEYPAIR_PATH;
24
24
  if (!KEYPAIR_PATH) {
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@wzrd_sol/solana-agent-plugin",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "WZRD Liquid Attention Protocol plugin for Solana Agent Kit — deposit, claim, leaderboard, portfolio, velocity signal",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
+ "types": "./dist/index.d.ts",
10
11
  "import": "./dist/index.js",
11
- "types": "./dist/index.d.ts"
12
+ "default": "./dist/index.js"
12
13
  }
13
14
  },
14
15
  "scripts": {
@@ -17,8 +18,9 @@
17
18
  },
18
19
  "dependencies": {
19
20
  "@solana/web3.js": "^1.95.0",
20
- "@wzrd_sol/sdk": "^0.1.0",
21
- "tweetnacl": "^1.0.3"
21
+ "@wzrd_sol/sdk": "^0.1.1",
22
+ "tweetnacl": "^1.0.3",
23
+ "zod": "^3.25.76"
22
24
  },
23
25
  "peerDependencies": {
24
26
  "solana-agent-kit": "^2.0.0"
@@ -28,6 +30,10 @@
28
30
  "optional": true
29
31
  }
30
32
  },
33
+ "devDependencies": {
34
+ "solana-agent-kit": "^2.0.10",
35
+ "typescript": "^5.6.3"
36
+ },
31
37
  "keywords": [
32
38
  "solana",
33
39
  "agent",
@@ -7,9 +7,73 @@
7
7
  * Flow: check claimable amount → relay claim → receive CCM.
8
8
  */
9
9
 
10
- import type { WzrdClient } from '../client.js';
10
+ import { z } from 'zod';
11
+ import type { Action, SolanaAgentKit } from 'solana-agent-kit';
11
12
 
12
- export const CLAIM_ACTION = {
13
+ import { formatCcm, getClaimsData, getClientForAgent } from '../runtime.js';
14
+
15
+ export const claimSchema = z.object({
16
+ execute: z.boolean().optional(),
17
+ });
18
+
19
+ export async function claimHandler(
20
+ agent: SolanaAgentKit,
21
+ input: z.infer<typeof claimSchema>,
22
+ ): Promise<Record<string, unknown>> {
23
+ const claims = await getClaimsData(agent);
24
+ const claimable = claims.cumulative_total - claims.claimed_total;
25
+
26
+ if (claimable <= 0) {
27
+ return {
28
+ success: true,
29
+ text:
30
+ `No CCM to claim. Cumulative: ${claims.cumulative_total}, ` +
31
+ `already claimed: ${claims.claimed_total}. ` +
32
+ `Deposit into markets and wait for the next scoring cycle.`,
33
+ data: claims,
34
+ };
35
+ }
36
+
37
+ if (input.execute === false) {
38
+ return {
39
+ success: true,
40
+ text:
41
+ `${formatCcm(claimable)} CCM claimable ` +
42
+ `(${formatCcm(claims.cumulative_total)} cumulative, ` +
43
+ `${formatCcm(claims.claimed_total)} claimed). ` +
44
+ `Root seq: ${claims.root_seq}. Call with execute=true to claim.`,
45
+ data: claims,
46
+ };
47
+ }
48
+
49
+ const result = await getClientForAgent(agent).claimRelay();
50
+
51
+ if (result.status === 'already_claimed') {
52
+ return {
53
+ success: true,
54
+ text:
55
+ `Already claimed through root ${result.root_seq}. ` +
56
+ `Claimed total: ${formatCcm(result.claimed_total ?? claims.claimed_total)} CCM.`,
57
+ data: result,
58
+ };
59
+ }
60
+
61
+ return {
62
+ success: true,
63
+ text:
64
+ `Claimed CCM via gasless relay. ` +
65
+ `Cumulative total: ${formatCcm(result.cumulative_total)}. ` +
66
+ `Root seq: ${result.root_seq}. ` +
67
+ `Tx: ${result.tx_sig?.slice(0, 16)}...`,
68
+ data: {
69
+ ...result,
70
+ claimable_before: claimable,
71
+ explorer: result.tx_sig ? `https://solscan.io/tx/${result.tx_sig}` : null,
72
+ },
73
+ };
74
+ }
75
+
76
+ export const CLAIM_ACTION: Action = {
13
77
  name: 'wzrd_claim',
14
78
  similes: ['wzrd_harvest', 'claim_ccm', 'redeem_rewards', 'collect_yield'],
15
79
  description:
@@ -22,77 +86,16 @@ export const CLAIM_ACTION = {
22
86
  examples: [
23
87
  [
24
88
  {
25
- user: 'user',
26
- content: { text: 'Claim my CCM rewards' },
27
- },
28
- {
29
- user: 'assistant',
30
- content: {
31
- text: 'Claimed 100,000 CCM via gasless relay. ' +
32
- 'Cumulative total: 250,000 CCM. Tx: 2VKz...J39c',
33
- },
34
- },
35
- ],
36
- [
37
- {
38
- user: 'user',
39
- content: { text: 'How much CCM can I claim?' },
40
- },
41
- {
42
- user: 'assistant',
43
- content: {
44
- text: 'You have 100,000 CCM claimable (250,000 cumulative, 150,000 already claimed). ' +
45
- 'Shall I claim it now?',
89
+ input: { execute: false },
90
+ output: {
91
+ success: true,
92
+ claimable: 100000,
93
+ cumulative_total: 250000,
46
94
  },
95
+ explanation: 'Check how much CCM is available before triggering a relay claim.',
47
96
  },
48
97
  ],
49
98
  ],
50
-
51
- validate: async () => true,
52
-
53
- handler: async (client: WzrdClient, params: { execute?: boolean }) => {
54
- // 1. Check claimable amount
55
- const claims = await client.getClaims();
56
- const claimable = claims.cumulative_total - claims.claimed_total;
57
-
58
- if (claimable <= 0) {
59
- return {
60
- success: true,
61
- text:
62
- `No CCM to claim. Cumulative: ${claims.cumulative_total}, ` +
63
- `already claimed: ${claims.claimed_total}. ` +
64
- `Deposit into markets and wait for the next scoring cycle.`,
65
- data: claims,
66
- };
67
- }
68
-
69
- // 2. If just checking (not executing), report the amount
70
- if (params.execute === false) {
71
- return {
72
- success: true,
73
- text:
74
- `${claimable} CCM claimable ` +
75
- `(${claims.cumulative_total} cumulative, ${claims.claimed_total} claimed). ` +
76
- `Root seq: ${claims.root_seq}. Call with execute=true to claim.`,
77
- data: claims,
78
- };
79
- }
80
-
81
- // 3. Execute gasless relay claim
82
- const result = await client.claimRelay();
83
-
84
- return {
85
- success: true,
86
- text:
87
- `Claimed CCM via gasless relay. ` +
88
- `Cumulative total: ${result.cumulative_total}. ` +
89
- `Root seq: ${result.root_seq}. ` +
90
- `Tx: ${result.tx_sig.slice(0, 16)}...`,
91
- data: {
92
- ...result,
93
- claimable_before: claimable,
94
- explorer: `https://solscan.io/tx/${result.tx_sig}`,
95
- },
96
- };
97
- },
99
+ schema: claimSchema,
100
+ handler: async (agent, input) => claimHandler(agent, claimSchema.parse(input)),
98
101
  };