@embarkai/ui-kit 0.2.8 → 0.3.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/iframe/index.html +1 -1
- package/dist/iframe/main.js +22 -11
- package/dist/iframe/main.js.map +1 -1
- package/dist/index.cjs +205 -136
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +114 -45
- package/dist/index.js.map +1 -1
- package/package.json +15 -14
package/dist/index.js
CHANGED
|
@@ -866,6 +866,7 @@ var init_useLayoutDataStore = __esm({
|
|
|
866
866
|
transitionPageHeight: DEFAULT_MAIN_MENU_HEIGHT,
|
|
867
867
|
settingsNotifications: [],
|
|
868
868
|
isWalletLinking: false,
|
|
869
|
+
pendingWalletLogin: null,
|
|
869
870
|
setPageParams: (pageOptions) => set({ pageParams: pageOptions }),
|
|
870
871
|
setPage: (page) => set((prev) => ({
|
|
871
872
|
page,
|
|
@@ -887,7 +888,8 @@ var init_useLayoutDataStore = __esm({
|
|
|
887
888
|
const filtered = prev.settingsNotifications.filter((n) => n.id !== notification.id);
|
|
888
889
|
return { settingsNotifications: filtered };
|
|
889
890
|
}),
|
|
890
|
-
setIsWalletLinking: (isWalletLinking) => set({ isWalletLinking })
|
|
891
|
+
setIsWalletLinking: (isWalletLinking) => set({ isWalletLinking }),
|
|
892
|
+
setPendingWalletLogin: (pendingWalletLogin) => set({ pendingWalletLogin })
|
|
891
893
|
}));
|
|
892
894
|
}
|
|
893
895
|
});
|
|
@@ -2564,6 +2566,8 @@ function useAutoConnect() {
|
|
|
2564
2566
|
}
|
|
2565
2567
|
} catch (e) {
|
|
2566
2568
|
if (e?.code === "KEYSHARE_RECOVERY_NEEDED") {
|
|
2569
|
+
setSession(null);
|
|
2570
|
+
setAddress(null);
|
|
2567
2571
|
setRecoveryUserId(userId);
|
|
2568
2572
|
setError(null);
|
|
2569
2573
|
setStatus("recovery_needed");
|
|
@@ -5057,6 +5061,8 @@ function useAuthMenuHandlers() {
|
|
|
5057
5061
|
console.warn("[AuthMenu] Keyshare recovery needed for user:", userId);
|
|
5058
5062
|
pendingLoginResponseRef.current = null;
|
|
5059
5063
|
setError(null);
|
|
5064
|
+
setSession(null);
|
|
5065
|
+
setAddress(null);
|
|
5060
5066
|
setRecoveryUserId(userId);
|
|
5061
5067
|
setStatus("recovery_needed");
|
|
5062
5068
|
setTimeout(() => {
|
|
@@ -5462,6 +5468,7 @@ var AuthMenu;
|
|
|
5462
5468
|
var init_AuthMenu = __esm({
|
|
5463
5469
|
"src/internal/components/AuthMenu/AuthMenu.tsx"() {
|
|
5464
5470
|
init_SessionContext();
|
|
5471
|
+
init_auth();
|
|
5465
5472
|
init_constants();
|
|
5466
5473
|
init_useLayoutDataStore();
|
|
5467
5474
|
init_useLayoutStore();
|
|
@@ -5478,8 +5485,20 @@ var init_AuthMenu = __esm({
|
|
|
5478
5485
|
const isIframeReady = useSession((st) => st.isIframeReady);
|
|
5479
5486
|
const maxScrollHeight = useLayoutStore((st) => st.maxScrollHeight);
|
|
5480
5487
|
const setTransitionPageHeight = useLayoutDataStore((st) => st.setTransitionPageHeight);
|
|
5488
|
+
const pendingWalletLogin = useLayoutDataStore((st) => st.pendingWalletLogin);
|
|
5489
|
+
const setPendingWalletLogin = useLayoutDataStore((st) => st.setPendingWalletLogin);
|
|
5481
5490
|
const { step, alert: alert2, setStep, setPasskeyStatus, setEmail, setAlert } = useAuthStore();
|
|
5482
5491
|
const { pendingLoginResponseRef, onAuthSuccess, goBackToSignIn } = useAuthMenuHandlers();
|
|
5492
|
+
useEffect10(() => {
|
|
5493
|
+
if (!pendingWalletLogin) return;
|
|
5494
|
+
const loginResponse = pendingWalletLogin;
|
|
5495
|
+
setPendingWalletLogin(null);
|
|
5496
|
+
console.log("[AuthMenu] Processing wallet login response:", loginResponse);
|
|
5497
|
+
jwtTokenManager2.clearTokens().then(() => {
|
|
5498
|
+
pendingLoginResponseRef.current = loginResponse;
|
|
5499
|
+
onAuthSuccess();
|
|
5500
|
+
});
|
|
5501
|
+
}, [pendingWalletLogin]);
|
|
5483
5502
|
useEffect10(() => {
|
|
5484
5503
|
setTransitionPageHeight(DEFAULT_AUTH_MENU_HEIGHT);
|
|
5485
5504
|
return () => {
|
|
@@ -7967,7 +7986,8 @@ function useCreateBackup() {
|
|
|
7967
7986
|
setIsDialogForced(true);
|
|
7968
7987
|
}
|
|
7969
7988
|
}, [hasServerVault, setIsDialogForced, setMethod]);
|
|
7970
|
-
const
|
|
7989
|
+
const recoveryUserId = useSession((st) => st.recoveryUserId);
|
|
7990
|
+
const passportUserId = session?.mpcUserId || recoveryUserId || "";
|
|
7971
7991
|
const onBackupSuccess = () => console.log("[ConnectWalletButton] Backup created successfully");
|
|
7972
7992
|
const { mutate: createPasswordBackup, isPending: isPasswordBackupCreating } = useMutation7({
|
|
7973
7993
|
mutationFn: async () => {
|
|
@@ -15479,7 +15499,7 @@ var init_package = __esm({
|
|
|
15479
15499
|
"package.json"() {
|
|
15480
15500
|
package_default = {
|
|
15481
15501
|
name: "@embarkai/ui-kit",
|
|
15482
|
-
version: "0.
|
|
15502
|
+
version: "0.3.1",
|
|
15483
15503
|
description: "React UI components and hooks for EmbarkAI authentication and Account Abstraction",
|
|
15484
15504
|
type: "module",
|
|
15485
15505
|
main: "./dist/index.cjs",
|
|
@@ -15517,51 +15537,52 @@ var init_package = __esm({
|
|
|
15517
15537
|
},
|
|
15518
15538
|
peerDependencies: {
|
|
15519
15539
|
"@tanstack/react-query": ">=5.0.0",
|
|
15540
|
+
i18next: "^25.8.0",
|
|
15520
15541
|
react: ">=18",
|
|
15521
15542
|
"react-dom": ">=18",
|
|
15522
|
-
"
|
|
15523
|
-
|
|
15524
|
-
"react-i18next": "^16.5.3"
|
|
15543
|
+
"react-i18next": "^16.5.3",
|
|
15544
|
+
"tailwind-merge": ">=2.2.0"
|
|
15525
15545
|
},
|
|
15526
15546
|
dependencies: {
|
|
15527
|
-
"@
|
|
15547
|
+
"@embarkai/core": "workspace:*",
|
|
15528
15548
|
"@radix-ui/react-checkbox": ">=1.3.3",
|
|
15529
|
-
"@radix-ui/react-select": ">=2.2.6",
|
|
15530
15549
|
"@radix-ui/react-dialog": ">=1.1.15",
|
|
15531
|
-
"@
|
|
15550
|
+
"@radix-ui/react-select": ">=2.2.6",
|
|
15551
|
+
"@radix-ui/react-slot": ">=1.2.4",
|
|
15532
15552
|
"@rainbow-me/rainbowkit": "^2.2.10",
|
|
15533
15553
|
"@sentry/browser": "^10.22.0",
|
|
15534
15554
|
"class-variance-authority": "^0.7.0",
|
|
15535
|
-
"lodash-es": "^4.17.21",
|
|
15536
15555
|
clsx: "^2.1.1",
|
|
15556
|
+
dayjs: "^1.11.9",
|
|
15537
15557
|
"dkls23-wasm": "^0.1.0",
|
|
15558
|
+
"framer-motion": "^12.23.24",
|
|
15559
|
+
"lodash-es": "^4.17.21",
|
|
15538
15560
|
"lucide-react": "^0.454.0",
|
|
15539
15561
|
qrcode: "^1.5.0",
|
|
15540
|
-
zustand: "^5.0.8",
|
|
15541
15562
|
viem: "^2.38.0",
|
|
15542
15563
|
wagmi: "^2.17.5",
|
|
15543
|
-
|
|
15544
|
-
"framer-motion": "^12.23.24"
|
|
15564
|
+
zustand: "^5.0.8"
|
|
15545
15565
|
},
|
|
15546
15566
|
devDependencies: {
|
|
15547
15567
|
"@tailwindcss/typography": "^0.5.16",
|
|
15548
15568
|
"@tanstack/react-query": "^5.90.2",
|
|
15569
|
+
"@types/lodash-es": "^4.17.12",
|
|
15549
15570
|
"@types/qrcode": "^1.5.0",
|
|
15550
15571
|
"@types/react": "^18.3.3",
|
|
15551
15572
|
"@types/react-dom": "^18.3.0",
|
|
15552
15573
|
autoprefixer: "^10.4.20",
|
|
15553
15574
|
dotenv: "^17.2.3",
|
|
15575
|
+
i18next: "^25.8.0",
|
|
15554
15576
|
postcss: "^8.4.47",
|
|
15555
15577
|
react: "^18.3.1",
|
|
15556
15578
|
"react-dom": "^18.3.1",
|
|
15579
|
+
"react-i18next": "^16.5.3",
|
|
15557
15580
|
"tailwind-merge": "^2.2.0",
|
|
15558
|
-
"@types/lodash-es": "^4.17.12",
|
|
15559
15581
|
tailwindcss: "^3.4.10",
|
|
15560
15582
|
tsup: "^8.5.0",
|
|
15561
15583
|
typescript: "^5.4.5",
|
|
15562
15584
|
vite: "^5.0.0",
|
|
15563
|
-
|
|
15564
|
-
"react-i18next": "^16.5.3"
|
|
15585
|
+
vitest: "^4.0.18"
|
|
15565
15586
|
},
|
|
15566
15587
|
repository: {
|
|
15567
15588
|
type: "git",
|
|
@@ -16160,6 +16181,19 @@ var init_TssManager = __esm({
|
|
|
16160
16181
|
});
|
|
16161
16182
|
|
|
16162
16183
|
// src/internal/auth/providers/wallet.ts
|
|
16184
|
+
async function walletLogin(walletData) {
|
|
16185
|
+
const response = await fetch(addProjectIdToUrl(`${getTssUrl3()}/api/auth/wallet/login`), {
|
|
16186
|
+
method: "POST",
|
|
16187
|
+
headers: { "Content-Type": "application/json" },
|
|
16188
|
+
credentials: "include",
|
|
16189
|
+
body: JSON.stringify(walletData)
|
|
16190
|
+
});
|
|
16191
|
+
if (!response.ok) {
|
|
16192
|
+
const errorData = await response.json().catch(() => ({}));
|
|
16193
|
+
throw new Error(errorData.message || `Wallet login failed: ${response.statusText}`);
|
|
16194
|
+
}
|
|
16195
|
+
return response.json();
|
|
16196
|
+
}
|
|
16163
16197
|
async function linkWallet(walletData) {
|
|
16164
16198
|
const hasValidToken = await ensureValidToken();
|
|
16165
16199
|
if (!hasValidToken) throw new Error("No authentication token available");
|
|
@@ -16212,9 +16246,23 @@ Timestamp: ${timestamp}
|
|
|
16212
16246
|
|
|
16213
16247
|
Sign this message to link your wallet to ${projectName} Wallet`;
|
|
16214
16248
|
}
|
|
16249
|
+
function createLoginMessage(address, projectName) {
|
|
16250
|
+
const nonce = crypto.randomUUID();
|
|
16251
|
+
const timestamp = Date.now();
|
|
16252
|
+
return [
|
|
16253
|
+
`${projectName} Wallet Login`,
|
|
16254
|
+
"",
|
|
16255
|
+
`Address: ${address}`,
|
|
16256
|
+
`Nonce: ${nonce}`,
|
|
16257
|
+
`Timestamp: ${timestamp}`,
|
|
16258
|
+
"",
|
|
16259
|
+
`Sign this message to login your wallet to ${projectName}`
|
|
16260
|
+
].join("\n");
|
|
16261
|
+
}
|
|
16215
16262
|
var METADATA_API_URL, METADATA_CACHE_TTL, metadataCache;
|
|
16216
16263
|
var init_wallet = __esm({
|
|
16217
16264
|
"src/internal/auth/providers/wallet.ts"() {
|
|
16265
|
+
init_projectId();
|
|
16218
16266
|
init_auth();
|
|
16219
16267
|
init_types();
|
|
16220
16268
|
METADATA_API_URL = "https://dashboard.lumiapassport.com/api/public/project";
|
|
@@ -16278,6 +16326,7 @@ function WalletConnectHandler() {
|
|
|
16278
16326
|
const walletMode = providerConfig?.wallet?.mode || "linked";
|
|
16279
16327
|
const projectId = providerConfig?.projectId;
|
|
16280
16328
|
const setExternalWallet = useExternalWalletStore((st) => st.setExternalWallet);
|
|
16329
|
+
const setPendingWalletLogin = useLayoutDataStore((st) => st.setPendingWalletLogin);
|
|
16281
16330
|
const onLinkingComplete = useCallback23(
|
|
16282
16331
|
async (success) => {
|
|
16283
16332
|
setIsWalletLinking(false);
|
|
@@ -16317,19 +16366,8 @@ function WalletConnectHandler() {
|
|
|
16317
16366
|
});
|
|
16318
16367
|
setHasStartedLinking(true);
|
|
16319
16368
|
setProviderType(null);
|
|
16320
|
-
|
|
16321
|
-
|
|
16322
|
-
setTimeout(() => {
|
|
16323
|
-
setPage(null);
|
|
16324
|
-
if (openConnectModal) {
|
|
16325
|
-
openConnectModal();
|
|
16326
|
-
} else {
|
|
16327
|
-
console.error("[WalletConnectHandler] openConnectModal is undefined!");
|
|
16328
|
-
setIsWalletLinking(false);
|
|
16329
|
-
setHasStartedLinking(false);
|
|
16330
|
-
}
|
|
16331
|
-
}, 500);
|
|
16332
|
-
} else {
|
|
16369
|
+
disconnect();
|
|
16370
|
+
setTimeout(() => {
|
|
16333
16371
|
setPage(null);
|
|
16334
16372
|
if (openConnectModal) {
|
|
16335
16373
|
openConnectModal();
|
|
@@ -16338,7 +16376,7 @@ function WalletConnectHandler() {
|
|
|
16338
16376
|
setIsWalletLinking(false);
|
|
16339
16377
|
setHasStartedLinking(false);
|
|
16340
16378
|
}
|
|
16341
|
-
}
|
|
16379
|
+
}, 500);
|
|
16342
16380
|
}
|
|
16343
16381
|
if (!isWalletLinking && hasStartedLinking) {
|
|
16344
16382
|
setHasStartedLinking(false);
|
|
@@ -16366,12 +16404,21 @@ function WalletConnectHandler() {
|
|
|
16366
16404
|
if (isWalletLinking) {
|
|
16367
16405
|
const timeout = setTimeout(() => {
|
|
16368
16406
|
console.warn("[WalletConnectHandler] Wallet linking timed out, resetting state");
|
|
16407
|
+
disconnect();
|
|
16369
16408
|
setIsWalletLinking(false);
|
|
16370
16409
|
setHasStartedLinking(false);
|
|
16410
|
+
if (passportWalletAddress) {
|
|
16411
|
+
setManageWalletLinkError("Wallet connection timed out. Please try again.");
|
|
16412
|
+
setPage("manage-wallet" /* MANAGE_WALLET */);
|
|
16413
|
+
} else {
|
|
16414
|
+
setAuthError({ title: "Connection timed out", message: "Wallet did not respond. Please try again." });
|
|
16415
|
+
setPage("auth" /* AUTH */);
|
|
16416
|
+
}
|
|
16371
16417
|
}, 12e4);
|
|
16372
16418
|
return () => clearTimeout(timeout);
|
|
16373
16419
|
}
|
|
16374
|
-
}, [isWalletLinking, setIsWalletLinking]);
|
|
16420
|
+
}, [isWalletLinking, setIsWalletLinking, disconnect]);
|
|
16421
|
+
const isAuthFlow = !passportWalletAddress;
|
|
16375
16422
|
const { mutate: handleWalletSign, isPending: isWalletSigning } = useMutation16({
|
|
16376
16423
|
mutationFn: async (payload) => {
|
|
16377
16424
|
const { chainId, signingWalletAddress } = payload;
|
|
@@ -16390,24 +16437,45 @@ function WalletConnectHandler() {
|
|
|
16390
16437
|
}
|
|
16391
16438
|
setLinkIsLoading(true);
|
|
16392
16439
|
const projectName = projectId ? await fetchProjectName(projectId) : "EmbarkAI";
|
|
16393
|
-
const message = createSignatureMessage(signingWalletAddress, projectName);
|
|
16394
|
-
const signature = await
|
|
16440
|
+
const message = isAuthFlow ? createLoginMessage(signingWalletAddress, projectName) : createSignatureMessage(signingWalletAddress, projectName);
|
|
16441
|
+
const signature = await Promise.race([
|
|
16442
|
+
signMessageAsync({ message, account: signingWalletAddress }),
|
|
16443
|
+
new Promise(
|
|
16444
|
+
(_, reject) => setTimeout(() => reject(new Error("Signature request timed out. Please try again.")), 6e4)
|
|
16445
|
+
)
|
|
16446
|
+
]);
|
|
16395
16447
|
if (!signature) {
|
|
16396
16448
|
throw new Error("Failed to get signature");
|
|
16397
16449
|
}
|
|
16398
16450
|
const walletName = connector?.name || "Unknown Wallet";
|
|
16399
16451
|
const walletType = connector?.id || "unknown";
|
|
16400
|
-
|
|
16401
|
-
// chainId: chain.id,
|
|
16452
|
+
const walletData = {
|
|
16402
16453
|
chainId,
|
|
16403
16454
|
address: signingWalletAddress,
|
|
16404
16455
|
signature,
|
|
16405
16456
|
message,
|
|
16406
16457
|
walletName,
|
|
16407
16458
|
walletType
|
|
16408
|
-
}
|
|
16459
|
+
};
|
|
16460
|
+
if (isAuthFlow) {
|
|
16461
|
+
const loginResponse = await walletLogin(walletData);
|
|
16462
|
+
return loginResponse;
|
|
16463
|
+
} else {
|
|
16464
|
+
await linkWallet(walletData);
|
|
16465
|
+
return void 0;
|
|
16466
|
+
}
|
|
16409
16467
|
},
|
|
16410
|
-
onSuccess: () => {
|
|
16468
|
+
onSuccess: (data) => {
|
|
16469
|
+
if (isAuthFlow && data) {
|
|
16470
|
+
console.log("[WalletConnectHandler] Wallet login successful, passing to AuthMenu");
|
|
16471
|
+
disconnect();
|
|
16472
|
+
setPendingWalletLogin(data);
|
|
16473
|
+
setIsWalletLinking(false);
|
|
16474
|
+
setHasStartedLinking(false);
|
|
16475
|
+
setLinkIsLoading(false);
|
|
16476
|
+
setPage("auth" /* AUTH */);
|
|
16477
|
+
return;
|
|
16478
|
+
}
|
|
16411
16479
|
const shouldKeepConnected = walletMode === "direct" || walletMode === "both";
|
|
16412
16480
|
if (shouldKeepConnected && walletAddress && chain?.id && connector) {
|
|
16413
16481
|
setExternalWallet({
|
|
@@ -16428,7 +16496,7 @@ function WalletConnectHandler() {
|
|
|
16428
16496
|
onLinkingComplete(false);
|
|
16429
16497
|
setHasStartedLinking(false);
|
|
16430
16498
|
setLinkIsLoading(false);
|
|
16431
|
-
const errorMsg = err?.message || "Failed to link wallet";
|
|
16499
|
+
const errorMsg = err?.message || (isAuthFlow ? "Wallet login failed" : "Failed to link wallet");
|
|
16432
16500
|
if (errorMsg.includes("User rejected") || errorMsg.includes("User denied")) {
|
|
16433
16501
|
if (passportWalletAddress) {
|
|
16434
16502
|
setManageWalletLinkError("Signature request was cancelled");
|
|
@@ -17651,6 +17719,7 @@ __export(auth_exports, {
|
|
|
17651
17719
|
configureJwtModule: () => configureJwtModule,
|
|
17652
17720
|
createInitialAuthState: () => createInitialAuthState,
|
|
17653
17721
|
createJwtTokenManager: () => createJwtTokenManager,
|
|
17722
|
+
createLoginMessage: () => createLoginMessage,
|
|
17654
17723
|
createPasskeyHelpers: () => createPasskeyHelpers,
|
|
17655
17724
|
createSignatureMessage: () => createSignatureMessage,
|
|
17656
17725
|
deriveDemoPrivateKey: () => deriveDemoPrivateKey,
|
|
@@ -17687,7 +17756,8 @@ __export(auth_exports, {
|
|
|
17687
17756
|
unlinkWallet: () => unlinkWallet,
|
|
17688
17757
|
unlinkX: () => unlinkX,
|
|
17689
17758
|
verifyEmailLinkCode: () => verifyEmailLinkCode,
|
|
17690
|
-
verifyToken: () => verifyToken
|
|
17759
|
+
verifyToken: () => verifyToken,
|
|
17760
|
+
walletLogin: () => walletLogin
|
|
17691
17761
|
});
|
|
17692
17762
|
import {
|
|
17693
17763
|
JwtTokenManager,
|
|
@@ -18964,7 +19034,6 @@ var init_iframe_manager = __esm({
|
|
|
18964
19034
|
});
|
|
18965
19035
|
|
|
18966
19036
|
// src/config/rainbowkit.ts
|
|
18967
|
-
import { lumiaMainnetChain as lumiaMainnetChain2, lumiaTestnetChain as lumiaTestnetChain2 } from "@embarkai/core/read";
|
|
18968
19037
|
import { getDefaultConfig } from "@rainbow-me/rainbowkit";
|
|
18969
19038
|
import {
|
|
18970
19039
|
coinbaseWallet,
|
|
@@ -18994,7 +19063,7 @@ var init_rainbowkit = __esm({
|
|
|
18994
19063
|
const config = {
|
|
18995
19064
|
appName: "EmbarkAI Wallet",
|
|
18996
19065
|
projectId: getProjectId(opts.projectId),
|
|
18997
|
-
chains: [
|
|
19066
|
+
chains: [mainnet, polygon, bsc, arbitrum, optimism, avalanche, base, zora],
|
|
18998
19067
|
ssr: false
|
|
18999
19068
|
};
|
|
19000
19069
|
if (opts.allowedWallets && opts.allowedWallets.length > 0) {
|
|
@@ -19254,7 +19323,7 @@ var init_utils8 = __esm({
|
|
|
19254
19323
|
});
|
|
19255
19324
|
|
|
19256
19325
|
// src/config/wagmi.ts
|
|
19257
|
-
import { lumiaMainnetChain as
|
|
19326
|
+
import { lumiaMainnetChain as lumiaMainnetChain2, lumiaTestnetChain as lumiaTestnetChain2 } from "@embarkai/core/read";
|
|
19258
19327
|
import { fallback } from "viem";
|
|
19259
19328
|
import { createConfig, http as http4 } from "wagmi";
|
|
19260
19329
|
function buildTransport(urls) {
|
|
@@ -19279,10 +19348,10 @@ var wagmiConfig;
|
|
|
19279
19348
|
var init_wagmi = __esm({
|
|
19280
19349
|
"src/config/wagmi.ts"() {
|
|
19281
19350
|
wagmiConfig = createConfig({
|
|
19282
|
-
chains: [
|
|
19351
|
+
chains: [lumiaMainnetChain2, lumiaTestnetChain2],
|
|
19283
19352
|
transports: {
|
|
19284
|
-
[
|
|
19285
|
-
[
|
|
19353
|
+
[lumiaTestnetChain2.id]: buildTransport(lumiaTestnetChain2.rpcUrls.default.http),
|
|
19354
|
+
[lumiaMainnetChain2.id]: buildTransport(lumiaMainnetChain2.rpcUrls.default.http)
|
|
19286
19355
|
}
|
|
19287
19356
|
});
|
|
19288
19357
|
}
|