@explorins/pers-sdk 1.1.0-beta.0 → 1.1.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.
Files changed (76) hide show
  1. package/config/domains.js +22 -0
  2. package/package.json +100 -15
  3. package/rollup.config.js +44 -54
  4. package/scripts/copy-declarations.js +147 -0
  5. package/src/analytics/api/analytics-api.ts +24 -0
  6. package/src/analytics/index.ts +52 -0
  7. package/src/analytics/models/index.ts +74 -0
  8. package/src/analytics/services/analytics-service.ts +28 -0
  9. package/src/auth-admin/api/auth-admin-api.ts +42 -0
  10. package/src/auth-admin/index.ts +47 -0
  11. package/src/auth-admin/services/auth-admin-service.ts +36 -0
  12. package/src/business/api/business-api.ts +181 -19
  13. package/src/business/index.ts +4 -3
  14. package/src/business/models/index.ts +4 -4
  15. package/src/business/services/business-service.ts +1 -1
  16. package/src/campaign/api/campaign-api.ts +376 -0
  17. package/src/campaign/index.ts +67 -0
  18. package/src/campaign/services/campaign-service.ts +164 -0
  19. package/src/core/abstractions/http-client.ts +1 -0
  20. package/src/core/auth/auth-provider.interface.ts +2 -2
  21. package/src/core/auth/create-auth-provider.ts +6 -6
  22. package/src/core/index.ts +33 -0
  23. package/src/core/pers-api-client.ts +211 -19
  24. package/src/core/pers-config.ts +34 -7
  25. package/src/core/utils/jwt.function.ts +24 -0
  26. package/src/donation/api/donation-api.ts +24 -0
  27. package/src/donation/index.ts +47 -0
  28. package/src/donation/models/index.ts +11 -0
  29. package/src/donation/services/donation-service.ts +25 -0
  30. package/src/index.ts +40 -1
  31. package/src/payment/api/payment-api.ts +185 -0
  32. package/src/payment/index.ts +64 -0
  33. package/src/payment/models/index.ts +29 -0
  34. package/src/payment/services/payment-service.ts +70 -0
  35. package/src/redemption/api/redemption-api.ts +241 -0
  36. package/src/redemption/index.ts +60 -0
  37. package/src/redemption/models/index.ts +17 -0
  38. package/src/redemption/services/redemption-service.ts +103 -0
  39. package/src/shared/interfaces/pers-shared-lib.interfaces.ts +99 -0
  40. package/src/tenant/api/tenant-api.ts +92 -0
  41. package/src/tenant/index.ts +61 -0
  42. package/src/tenant/models/index.ts +20 -0
  43. package/src/tenant/services/tenant-service.ts +78 -0
  44. package/src/token/api/token-api.ts +129 -0
  45. package/src/token/base/base-token-service.ts +167 -0
  46. package/src/token/index.ts +38 -0
  47. package/src/token/models/index.ts +30 -0
  48. package/src/token/services/token-service.ts +125 -0
  49. package/src/token/token-sdk.ts +231 -0
  50. package/src/transaction/api/transaction-api.ts +296 -0
  51. package/src/transaction/index.ts +65 -0
  52. package/src/transaction/models/index.ts +60 -0
  53. package/src/transaction/services/transaction-service.ts +104 -0
  54. package/src/user/api/user-api.ts +98 -0
  55. package/src/user/index.ts +62 -0
  56. package/src/user/models/index.ts +10 -0
  57. package/src/user/services/user-service.ts +75 -0
  58. package/src/user-status/api/user-status-api.ts +78 -0
  59. package/src/user-status/index.ts +55 -0
  60. package/src/user-status/models/index.ts +11 -0
  61. package/src/user-status/services/user-status-service.ts +51 -0
  62. package/src/web3/api/web3-api.ts +68 -0
  63. package/src/web3/index.ts +38 -0
  64. package/src/web3/models/index.ts +150 -0
  65. package/src/web3/services/web3-service.ts +338 -0
  66. package/src/web3-chain/api/web3-chain-api.ts +42 -0
  67. package/src/web3-chain/index.ts +27 -0
  68. package/src/web3-chain/models/index.ts +45 -0
  69. package/src/web3-chain/services/getWeb3FCD.service.ts +47 -0
  70. package/src/web3-chain/services/provider.service.ts +123 -0
  71. package/src/web3-chain/services/public-http-provider.service.ts +26 -0
  72. package/src/web3-chain/services/web3-chain-service.ts +131 -0
  73. package/src/business/business/tsconfig.json +0 -18
  74. package/src/core/abstractions/core-interfaces.ts +0 -56
  75. package/src/core/core.ts +0 -30
  76. package/src/core.ts +0 -30
@@ -0,0 +1,75 @@
1
+ import { UserDTO, UserCreateRequestDTO } from '../../shared/interfaces/pers-shared-lib.interfaces';
2
+ import { UserApi } from '../api/user-api';
3
+ import { UserPublicProfileDTO } from '../models';
4
+
5
+ /**
6
+ * Platform-Agnostic User Service
7
+ *
8
+ * Contains user business logic and operations that work across platforms.
9
+ * No framework dependencies - pure TypeScript business logic.
10
+ * Matches framework UserApiService capabilities exactly.
11
+ */
12
+ export class UserService {
13
+ constructor(private userApi: UserApi) {}
14
+
15
+ // ==========================================
16
+ // PUBLIC OPERATIONS
17
+ // ==========================================
18
+
19
+ /**
20
+ * PUBLIC: Get all users public profiles with optional filtering
21
+ * ✅ FIXED: Uses framework-compatible inline filter type
22
+ */
23
+ async getAllUsersPublicProfiles(filter: {key: string, value: string} | null = null): Promise<UserPublicProfileDTO[]> {
24
+ return this.userApi.getAllUsersPublicProfiles(filter);
25
+ }
26
+
27
+ // ==========================================
28
+ // AUTHENTICATED OPERATIONS
29
+ // ==========================================
30
+
31
+ /**
32
+ * AUTH: Get current authenticated user
33
+ */
34
+ async getRemoteUser(): Promise<UserDTO> {
35
+ return this.userApi.getRemoteUser();
36
+ }
37
+
38
+ /**
39
+ * AUTH: Update current authenticated user
40
+ */
41
+ async updateRemoteUser(updateRequest: UserCreateRequestDTO): Promise<UserDTO> {
42
+ return this.userApi.updateRemoteUser(updateRequest);
43
+ }
44
+
45
+ // ==========================================
46
+ // ADMIN OPERATIONS
47
+ // ==========================================
48
+
49
+ /**
50
+ * ADMIN: Get all remote users
51
+ * ✅ FIXED: Matches API method signature (no parameters needed)
52
+ */
53
+ async getAllRemoteUsers(): Promise<UserDTO[]> {
54
+ return this.userApi.getAllRemoteUsers();
55
+ }
56
+
57
+ /**
58
+ * ADMIN: Update user as admin
59
+ */
60
+ async updateUserAsAdmin(id: string, userData: UserCreateRequestDTO): Promise<UserDTO> {
61
+ return this.userApi.updateUserAsAdmin(id, userData);
62
+ }
63
+
64
+ async getUserByUniqueIdentifier(id: string): Promise<UserDTO> {
65
+ return this.userApi.getUserByUniqueIdentifier(id);
66
+ }
67
+
68
+ /**
69
+ * ADMIN: Toggle user active status by user object
70
+ * ✅ FIXED: Matches API method signature exactly
71
+ */
72
+ async toggleUserActiveStatusByUser(user: UserDTO): Promise<UserDTO> {
73
+ return this.userApi.toggleUserActiveStatusByUser(user);
74
+ }
75
+ }
@@ -0,0 +1,78 @@
1
+ import { PersApiClient } from '../../core/pers-api-client';
2
+ import { UserStatusTypeDTO } from '../../shared/interfaces/pers-shared-lib.interfaces';
3
+
4
+ /**
5
+ * Platform-Agnostic User Status API Client
6
+ *
7
+ * Handles user status operations using the PERS backend.
8
+ * Matches framework UserStatusApiService methods exactly.
9
+ *
10
+ * ✅ UPDATED: All endpoints updated to new RESTful /users patterns
11
+ *
12
+ * Error handling patterns follow framework implementation:
13
+ * - getRemoteEarnedUserStatus() uses silent fallback (empty array)
14
+ * - Other operations throw errors for proper error handling
15
+ */
16
+ export class UserStatusApi {
17
+ constructor(private apiClient: PersApiClient) {}
18
+
19
+ private readonly basePath = '/users';
20
+
21
+ // ==========================================
22
+ // PUBLIC OPERATIONS
23
+ // ==========================================
24
+
25
+ /**
26
+ * PUBLIC: Get remote user status types
27
+ * ✅ UPDATED: /user/status-type → /users/status-types
28
+ */
29
+ async getRemoteUserStatusTypes(): Promise<UserStatusTypeDTO[]> {
30
+ try {
31
+ return await this.apiClient.get<UserStatusTypeDTO[]>(`${this.basePath}/status-types`);
32
+ } catch (error) {
33
+ console.error('Error getting user status types', error);
34
+ throw error;
35
+ }
36
+ }
37
+
38
+ // ==========================================
39
+ // AUTHENTICATED OPERATIONS
40
+ // ==========================================
41
+
42
+ /**
43
+ * AUTH: Get earned user status for authenticated user
44
+ * ✅ UPDATED: /user/auth/status → /users/me/status
45
+ * ✅ FIXED: Returns UserStatusTypeDTO[] to match framework exactly
46
+ * Note: Uses silent fallback pattern from framework - returns empty array on error
47
+ */
48
+ async getRemoteEarnedUserStatus(): Promise<UserStatusTypeDTO[]> {
49
+ try {
50
+ return await this.apiClient.get<UserStatusTypeDTO[]>(`${this.basePath}/me/status`);
51
+ } catch (error) {
52
+ console.error('Error getting user status', error);
53
+ // ✅ FIXED: Silent fallback pattern from framework implementation
54
+ return [];
55
+ }
56
+ }
57
+
58
+ // ==========================================
59
+ // ADMIN OPERATIONS
60
+ // ==========================================
61
+
62
+ /**
63
+ * ADMIN: Create user status type
64
+ * ✅ UPDATED: /user/admin/status-type → /users/status-types
65
+ */
66
+ async createUserStatusType(userStatusType: UserStatusTypeDTO): Promise<UserStatusTypeDTO> {
67
+ try {
68
+ return await this.apiClient.post<UserStatusTypeDTO>(`${this.basePath}/status-types`, userStatusType);
69
+ } catch (error) {
70
+ console.error('Error creating user status type', error);
71
+ throw error;
72
+ }
73
+ }
74
+
75
+ // ❌ REMOVED: Methods not present in framework
76
+ // - updateUserStatusType() - Framework doesn't have this operation
77
+ // - toggleUserStatusTypeActive() - Framework doesn't have this operation
78
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @explorins/pers-sdk-user-status
3
+ *
4
+ * Platform-agnostic User Status Domain SDK for PERS ecosystem
5
+ * Handles user status management and type operations
6
+ */
7
+
8
+ // API Layer
9
+ export { UserStatusApi } from './api/user-status-api';
10
+
11
+ // Service Layer
12
+ export { UserStatusService } from './services/user-status-service';
13
+
14
+ // Models & Types - re-export all centralized interfaces
15
+ export * from '../shared/interfaces/pers-shared-lib.interfaces';
16
+
17
+ // Models & Types - imported from centralized interfaces
18
+
19
+ // Factory function for creating user-status SDK instance
20
+ import { PersApiClient } from '../core/pers-api-client';
21
+ import { UserStatusApi } from './api/user-status-api';
22
+ import { UserStatusService } from './services/user-status-service';
23
+ import { UserStatusTypeDTO } from '../shared/interfaces/pers-shared-lib.interfaces';
24
+
25
+ /**
26
+ * Create a complete User Status SDK instance
27
+ *
28
+ * @param apiClient - Configured PERS API client
29
+ * @returns User Status SDK with flattened structure for better DX
30
+ */
31
+ export function createUserStatusSDK(apiClient: PersApiClient) {
32
+ const userStatusApi = new UserStatusApi(apiClient);
33
+ const userStatusService = new UserStatusService(userStatusApi);
34
+
35
+ return {
36
+ // Direct access to service methods (primary interface)
37
+ // ✅ FRAMEWORK ALIGNED: Only methods actually used by framework
38
+
39
+ // Public methods
40
+ getRemoteUserStatusTypes: () => userStatusService.getRemoteUserStatusTypes(),
41
+
42
+ // Auth methods
43
+ getRemoteEarnedUserStatus: () => userStatusService.getRemoteEarnedUserStatus(),
44
+
45
+ // Admin methods
46
+ createUserStatusType: (userStatusType: UserStatusTypeDTO) =>
47
+ userStatusService.createUserStatusType(userStatusType),
48
+
49
+ // Advanced access for edge cases
50
+ api: userStatusApi,
51
+ service: userStatusService
52
+ };
53
+ }
54
+
55
+ export type UserStatusSDK = ReturnType<typeof createUserStatusSDK>;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * User Status Domain Models
3
+ *
4
+ * Re-exports from centralized pers-shared interfaces for consistency with backend
5
+ * and to provide a single import source for user-status-related types.
6
+ */
7
+
8
+ // Core user status entities from centralized pers-shared interfaces
9
+ export type {
10
+ UserStatusTypeDTO
11
+ } from '../../shared/interfaces/pers-shared-lib.interfaces';
@@ -0,0 +1,51 @@
1
+ import { UserStatusApi } from '../api/user-status-api';
2
+ import { UserStatusTypeDTO } from '../../shared/interfaces/pers-shared-lib.interfaces';
3
+
4
+ /**
5
+ * Platform-Agnostic User Status Service
6
+ *
7
+ * Contains user status business logic and operations that work across platforms.
8
+ * No framework dependencies - pure TypeScript business logic.
9
+ * Matches framework UserStatusApiService capabilities exactly.
10
+ */
11
+ export class UserStatusService {
12
+ constructor(private userStatusApi: UserStatusApi) {}
13
+
14
+ // ==========================================
15
+ // PUBLIC OPERATIONS
16
+ // ==========================================
17
+
18
+ /**
19
+ * PUBLIC: Get remote user status types
20
+ */
21
+ async getRemoteUserStatusTypes(): Promise<UserStatusTypeDTO[]> {
22
+ return this.userStatusApi.getRemoteUserStatusTypes();
23
+ }
24
+
25
+ // ==========================================
26
+ // AUTHENTICATED OPERATIONS
27
+ // ==========================================
28
+
29
+ /**
30
+ * AUTH: Get earned user status for authenticated user
31
+ */
32
+ async getRemoteEarnedUserStatus(): Promise<UserStatusTypeDTO[]> {
33
+ return this.userStatusApi.getRemoteEarnedUserStatus();
34
+ }
35
+
36
+ // ==========================================
37
+ // ADMIN OPERATIONS
38
+ // ==========================================
39
+
40
+ /**
41
+ * ADMIN: Create user status type
42
+ */
43
+ async createUserStatusType(userStatusType: UserStatusTypeDTO): Promise<UserStatusTypeDTO> {
44
+ return this.userStatusApi.createUserStatusType(userStatusType);
45
+ }
46
+
47
+ // ❌ REMOVED: Business logic methods not present in framework
48
+ // - hasUserReachedStatusLevel() - Framework doesn't need this logic
49
+ // - getUserHighestStatusLevel() - Framework doesn't need this logic
50
+ // These can be added later if actually needed
51
+ }
@@ -0,0 +1,68 @@
1
+ import { Web3ChainService } from '../../web3-chain/services/web3-chain-service';
2
+ import type { ContractAbi } from 'web3';
3
+ import {
4
+ getAddressTokenBalanceByContract,
5
+ getSmartContractInstance,
6
+ getTokenOfOwnerByIndex,
7
+ getTokenUri
8
+ } from '@explorins/web3-ts';
9
+
10
+
11
+ export class Web3Api {
12
+
13
+ constructor(
14
+ private web3ChainService: Web3ChainService,
15
+ ) {}
16
+
17
+ async getTokenBalance(request: {
18
+ accountAddress: string;
19
+ contractAddress: string;
20
+ abi: ContractAbi;
21
+ tokenId: string | null;
22
+ chainId: number;
23
+ }): Promise<number> {
24
+ const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
25
+
26
+ const tokenContract = getSmartContractInstance(request.contractAddress, request.abi, web3);
27
+ const balance = await getAddressTokenBalanceByContract(
28
+ tokenContract,
29
+ request.accountAddress,
30
+ request.tokenId
31
+ );
32
+
33
+ return Number(balance);
34
+ }
35
+
36
+ async getTokenUri(request: {
37
+ contractAddress: string;
38
+ abi: ContractAbi;
39
+ tokenId: string;
40
+ chainId: number;
41
+ }): Promise<string> {
42
+ const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
43
+
44
+ // ✅ DIRECT: Use web3-ts functions directly
45
+ const tokenContract = getSmartContractInstance(request.contractAddress, request.abi, web3);
46
+ const tokenId = Number(request.tokenId);
47
+ const tokenUri = await getTokenUri(tokenContract, tokenId);
48
+
49
+ return String(tokenUri);
50
+ }
51
+
52
+
53
+ async getTokenOfOwnerByIndex(request: {
54
+ contractAddress: string;
55
+ abi: ContractAbi;
56
+ accountAddress: string;
57
+ tokenIndex: number;
58
+ chainId: number;
59
+ }): Promise<string> {
60
+ const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
61
+
62
+ // ✅ DIRECT: Use web3-ts functions directly
63
+ const tokenContract = getSmartContractInstance(request.contractAddress, request.abi, web3);
64
+ const tokenId = await getTokenOfOwnerByIndex(tokenContract, request.accountAddress, request.tokenIndex);
65
+
66
+ return String(tokenId);
67
+ }
68
+ }
@@ -0,0 +1,38 @@
1
+ import { PersApiClient } from '../core/pers-api-client';
2
+ import { Web3Api } from './api/web3-api';
3
+ import { Web3Service } from './services/web3-service';
4
+ import { createWeb3ChainSDK } from '../web3-chain';
5
+ import { ContractAbi, ERC1155CollectionRequest, ERC20BalanceRequest, ERC721CollectionRequest, ERC721CollectionResponse, Web3BalanceRequest, Web3BalanceResponse, Web3TokenListRequest, Web3TokenListResponse } from './models';
6
+ import { Web3ProviderService } from '../web3-chain/services/provider.service';
7
+
8
+ export function createWeb3SDK(
9
+ apiClient: PersApiClient,
10
+ web3ProviderService: Web3ProviderService,
11
+ ) {
12
+ const web3ChainSDK = createWeb3ChainSDK(apiClient, web3ProviderService);
13
+
14
+ const web3Api = new Web3Api(
15
+ web3ChainSDK.service,
16
+ );
17
+
18
+ const web3Service = new Web3Service(web3Api, web3ChainSDK.service);
19
+
20
+ return {
21
+
22
+ getCreditsBalance: (request: ERC20BalanceRequest): Promise<Web3BalanceResponse> =>
23
+ web3Service.getERC20Balance(request),
24
+
25
+ getRewardsCollection: (request: ERC1155CollectionRequest): Promise<Web3TokenListResponse> =>
26
+ web3Service.getERC1155Collection(request),
27
+
28
+ getStampsCollection: (request: ERC721CollectionRequest): Promise<ERC721CollectionResponse> =>
29
+ web3Service.getERC721Collection(request),
30
+
31
+ api: web3Api,
32
+ service: web3Service
33
+ };
34
+ }
35
+
36
+ export * from './models';
37
+ export type { ERC20BalanceRequest, ERC1155CollectionRequest, ERC721CollectionRequest, ERC721CollectionResponse, NFTItem } from './models';
38
+ export * from '../shared/interfaces/pers-shared-lib.interfaces';
@@ -0,0 +1,150 @@
1
+ import type { ContractAbi, Web3 } from 'web3';
2
+ import type { TokenDTO } from '../../shared/interfaces/pers-shared-lib.interfaces';
3
+
4
+ // ✅ REMOVE: Custom Web3ContractAbi type (no longer needed)
5
+ // export type Web3ContractAbi = readonly AbiFragment[] | AbiFragment[];
6
+
7
+ export interface Web3BalanceRequest {
8
+ accountAddress: string;
9
+ token: TokenDTO;
10
+ tokenId: string | null;
11
+ }
12
+
13
+ export interface Web3BalanceResponse {
14
+ rawBalance: number;
15
+ formattedBalance: string;
16
+ decimals: number;
17
+ symbol: string;
18
+ hasBalance: boolean;
19
+ }
20
+
21
+ export interface Web3TokenConfig {
22
+ token: TokenDTO;
23
+ tokenIds?: (string | null)[];
24
+ metadata?: any[];
25
+ }
26
+
27
+ export interface Web3TokenListRequest {
28
+ accountAddress: string;
29
+ tokens: Web3TokenConfig[];
30
+ }
31
+
32
+ export interface Web3TokenResult {
33
+ tokenId: string | null;
34
+ balance: number;
35
+ formattedBalance: string;
36
+ hasBalance: boolean;
37
+ metadata: any | null;
38
+ }
39
+
40
+ export interface Web3TokenListResponse {
41
+ accountAddress: string;
42
+ tokens: {
43
+ token: TokenDTO;
44
+ results: Web3TokenResult[];
45
+ }[];
46
+ }
47
+
48
+ export interface NFTItem {
49
+ tokenId: string;
50
+ name: string;
51
+ description: string;
52
+ imageUrl: string;
53
+ rawBalance: number;
54
+ formattedBalance: string;
55
+ hasBalance: boolean;
56
+ metadata: any;
57
+ tokenIndex: number;
58
+ }
59
+
60
+ export interface ERC721CollectionRequest {
61
+ accountAddress: string;
62
+ nftContracts: TokenDTO[];
63
+ maxNFTsPerContract?: number;
64
+ }
65
+
66
+ export interface ERC721CollectionResponse {
67
+ accountAddress: string;
68
+ contracts: {
69
+ token: TokenDTO;
70
+ totalNFTs: number;
71
+ nfts: NFTItem[];
72
+ hasMore: boolean;
73
+ }[];
74
+ summary: {
75
+ totalContracts: number;
76
+ totalNFTs: number;
77
+ loadingTime: number;
78
+ };
79
+ }
80
+
81
+ // ✅ NEW: ERC20 Balance types (simplified)
82
+ export interface ERC20BalanceRequest {
83
+ accountAddress: string;
84
+ token: TokenDTO;
85
+ }
86
+
87
+ // ✅ NEW: ERC1155 Collection types (clearer naming)
88
+ export interface ERC1155CollectionRequest {
89
+ accountAddress: string;
90
+ tokens: TokenDTO[];
91
+ }
92
+
93
+ // ✅ RE-EXPORT: Standard Web3.js types for consumers
94
+ export type { ContractAbi } from 'web3';
95
+
96
+ // ✅ CACHE: Simple cache interface with TTL
97
+ export interface CacheEntry<T> {
98
+ data: T;
99
+ timestamp: number;
100
+ ttl: number;
101
+ }
102
+
103
+ export interface CacheStorage {
104
+ [key: string]: CacheEntry<unknown>;
105
+ }
106
+
107
+ export class SimpleCache {
108
+ private storage: CacheStorage = {};
109
+ private readonly defaultTTL = 10 * 1000; // 10 seconds
110
+
111
+ set<T>(key: string, data: T, ttl?: number): void {
112
+ this.storage[key] = {
113
+ data,
114
+ timestamp: Date.now(),
115
+ ttl: ttl ?? this.defaultTTL
116
+ };
117
+ }
118
+
119
+ get<T>(key: string): T | null {
120
+ const entry = this.storage[key];
121
+
122
+ if (!entry) {
123
+ return null;
124
+ }
125
+
126
+ const now = Date.now();
127
+ const isExpired = (now - entry.timestamp) > entry.ttl;
128
+
129
+ if (isExpired) {
130
+ delete this.storage[key];
131
+ return null;
132
+ }
133
+
134
+ return entry.data as T;
135
+ }
136
+
137
+ clear(): void {
138
+ this.storage = {};
139
+ }
140
+
141
+ cleanup(): void {
142
+ const now = Date.now();
143
+ Object.keys(this.storage).forEach(key => {
144
+ const entry = this.storage[key];
145
+ if ((now - entry.timestamp) > entry.ttl) {
146
+ delete this.storage[key];
147
+ }
148
+ });
149
+ }
150
+ }