@blocklet/meta 1.16.11-next-a232f5fb → 1.16.11-next-3d2b39f7
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/lib/util.d.ts +52 -25
- package/lib/util.js +98 -1
- package/package.json +5 -5
package/lib/util.d.ts
CHANGED
|
@@ -4,8 +4,9 @@ import type { TBlockletMeta, TEnvironment } from './types';
|
|
|
4
4
|
type TConfig = TEnvironment & {
|
|
5
5
|
key: string;
|
|
6
6
|
};
|
|
7
|
-
type
|
|
8
|
-
type
|
|
7
|
+
type TApp = BlockletState;
|
|
8
|
+
type TComponent = BlockletState | ComponentState;
|
|
9
|
+
type TComponentPro = TComponent & {
|
|
9
10
|
configObj?: Record<string, string>;
|
|
10
11
|
environmentObj?: Record<string, string>;
|
|
11
12
|
};
|
|
@@ -44,7 +45,7 @@ declare const getComponentBundleId: (component: {
|
|
|
44
45
|
* @a/b/@c/d/@e/f => @a/b/@c/d
|
|
45
46
|
*/
|
|
46
47
|
declare const getParentComponentName: (name?: string) => string;
|
|
47
|
-
declare const forEachBlocklet: (blocklet:
|
|
48
|
+
declare const forEachBlocklet: (blocklet: TComponentPro, cb: Function, { parallel, concurrencyLimit, sync, params: inputParams, _parent, _root, _level, _tasks: inputTasks, _ancestors, _limit, }?: {
|
|
48
49
|
parallel?: boolean;
|
|
49
50
|
concurrencyLimit?: number;
|
|
50
51
|
sync?: boolean;
|
|
@@ -57,23 +58,31 @@ declare const forEachBlocklet: (blocklet: ComponentPro, cb: Function, { parallel
|
|
|
57
58
|
_limit?: (fn: () => void) => void;
|
|
58
59
|
}) => Promise<unknown>;
|
|
59
60
|
declare const forEachBlockletSync: (blocklet: any, cb: Function) => Promise<unknown>;
|
|
61
|
+
declare const forEachComponentV2: (blocklet: TApp, cb: Function, { parallel, concurrencyLimit, sync, }?: {
|
|
62
|
+
parallel?: boolean;
|
|
63
|
+
concurrencyLimit?: number;
|
|
64
|
+
sync?: boolean;
|
|
65
|
+
}) => Promise<unknown>;
|
|
66
|
+
declare const forEachComponentV2Sync: (blocklet: any, cb: Function) => Promise<unknown>;
|
|
60
67
|
declare const forEachChild: (blocklet: any, cb: Function, params?: any) => Promise<any>;
|
|
61
68
|
declare const forEachChildSync: (blocklet: BlockletState, cb: Function) => Promise<any>;
|
|
62
|
-
declare const findComponent: (blocklet:
|
|
63
|
-
ancestors: Array<
|
|
69
|
+
declare const findComponent: (blocklet: TComponent, isEqualFn: (component: TComponent, context: {
|
|
70
|
+
ancestors: Array<TComponent>;
|
|
64
71
|
}) => boolean, { _ancestors, returnAncestors, }?: {
|
|
65
|
-
_ancestors?: Array<
|
|
72
|
+
_ancestors?: Array<TComponent>;
|
|
66
73
|
returnAncestors?: boolean;
|
|
67
|
-
}) =>
|
|
68
|
-
component:
|
|
69
|
-
ancestors: Array<
|
|
74
|
+
}) => TComponent | {
|
|
75
|
+
component: TComponent;
|
|
76
|
+
ancestors: Array<TComponent>;
|
|
70
77
|
};
|
|
71
78
|
declare const findComponentById: (blocklet: BlockletState | ComponentState, componentId: string | Array<string>, { returnAncestors, }?: {
|
|
72
79
|
returnAncestors?: boolean;
|
|
73
|
-
}) =>
|
|
74
|
-
component:
|
|
75
|
-
ancestors: Array<
|
|
80
|
+
}) => TComponent | {
|
|
81
|
+
component: TComponent;
|
|
82
|
+
ancestors: Array<TComponent>;
|
|
76
83
|
};
|
|
84
|
+
declare const findComponentV2: (app: TApp, isEqualFn: (component: TComponent, app: TApp) => boolean) => ComponentState;
|
|
85
|
+
declare const findComponentByIdV2: (app: TApp, componentId: string | Array<string>) => ComponentState;
|
|
77
86
|
declare const isEnvShareable: (env?: TConfig) => boolean;
|
|
78
87
|
declare const getSharedConfigObj: (component: BlockletState, ancestors?: any[]) => any;
|
|
79
88
|
declare const isPreferenceKey: (x: TConfig) => Boolean;
|
|
@@ -115,7 +124,7 @@ type ChainInfo = {
|
|
|
115
124
|
host: string;
|
|
116
125
|
};
|
|
117
126
|
declare const getChainInfo: (env: Record<string, string>) => ChainInfo;
|
|
118
|
-
declare const getBlockletChainInfo: (blocklet?:
|
|
127
|
+
declare const getBlockletChainInfo: (blocklet?: TComponentPro) => ChainInfo;
|
|
119
128
|
declare const isExternalBlocklet: (blocklet?: BlockletState) => boolean;
|
|
120
129
|
declare const getRolesFromAuthConfig: (config: {
|
|
121
130
|
whoCanAccess: string;
|
|
@@ -130,12 +139,21 @@ declare const getBlockletServices: (blocklet: Partial<BlockletState>) => Array<{
|
|
|
130
139
|
declare const isInProgress: (status: string | number) => boolean;
|
|
131
140
|
declare const isBeforeInstalled: (status: string | number) => boolean;
|
|
132
141
|
declare const isRunning: (status: string | number) => boolean;
|
|
133
|
-
|
|
142
|
+
type TComponentInternalInfo = {
|
|
143
|
+
title: string;
|
|
144
|
+
did: string;
|
|
145
|
+
name: string;
|
|
146
|
+
mountPoint: string;
|
|
147
|
+
status: number;
|
|
148
|
+
port: number;
|
|
149
|
+
};
|
|
150
|
+
declare const getComponentsInternalInfo: (app: TApp) => Array<TComponentInternalInfo>;
|
|
151
|
+
export { isFreeBlocklet, isFreeComponent, isComponentBlocklet, forEachBlocklet, forEachBlockletSync, forEachChild, forEachChildSync, forEachComponentV2, forEachComponentV2Sync, isDeletableBlocklet, getSharedConfigObj, getAppMissingConfigs, getComponentMissingConfigs, isEnvShareable, wipeSensitiveData, hasRunnableComponent, getAppName, getAppName as getDisplayName, getAppDescription, fixBlockletStatus, findWebInterface, findWebInterfacePort, findServiceFromMeta, getWhoCanAccess, replaceSlotToIp, getComponentId, getComponentName, getComponentBundleId, findComponent, findComponentById, findComponentV2, findComponentByIdV2, getParentComponentName, getConnectAppUrl, getChainInfo, getBlockletChainInfo, isExternalBlocklet, isPreferenceKey, getRolesFromAuthConfig, getBlockletAppIdList, getBlockletServices, isInProgress, isBeforeInstalled, isRunning, getComponentsInternalInfo, TComponentInternalInfo, };
|
|
134
152
|
declare const _default: {
|
|
135
153
|
isFreeBlocklet: (meta: TBlockletMeta) => boolean;
|
|
136
154
|
isFreeComponent: (meta: TBlockletMeta) => boolean;
|
|
137
155
|
isComponentBlocklet: (meta?: TBlockletMeta) => boolean;
|
|
138
|
-
forEachBlocklet: (blocklet:
|
|
156
|
+
forEachBlocklet: (blocklet: TComponentPro, cb: Function, { parallel, concurrencyLimit, sync, params: inputParams, _parent, _root, _level, _tasks: inputTasks, _ancestors, _limit, }?: {
|
|
139
157
|
parallel?: boolean;
|
|
140
158
|
concurrencyLimit?: number;
|
|
141
159
|
sync?: boolean;
|
|
@@ -150,6 +168,12 @@ declare const _default: {
|
|
|
150
168
|
forEachBlockletSync: (blocklet: any, cb: Function) => Promise<unknown>;
|
|
151
169
|
forEachChild: (blocklet: any, cb: Function, params?: any) => Promise<any>;
|
|
152
170
|
forEachChildSync: (blocklet: BlockletState, cb: Function) => Promise<any>;
|
|
171
|
+
forEachComponentV2: (blocklet: BlockletState, cb: Function, { parallel, concurrencyLimit, sync, }?: {
|
|
172
|
+
parallel?: boolean;
|
|
173
|
+
concurrencyLimit?: number;
|
|
174
|
+
sync?: boolean;
|
|
175
|
+
}) => Promise<unknown>;
|
|
176
|
+
forEachComponentV2Sync: (blocklet: any, cb: Function) => Promise<unknown>;
|
|
153
177
|
isDeletableBlocklet: (blocklet?: BlockletState) => boolean;
|
|
154
178
|
getSharedConfigObj: (component: BlockletState, ancestors?: any[]) => any;
|
|
155
179
|
getAppMissingConfigs: (blocklet?: any) => any[];
|
|
@@ -190,28 +214,30 @@ declare const _default: {
|
|
|
190
214
|
version: string;
|
|
191
215
|
};
|
|
192
216
|
}) => string;
|
|
193
|
-
findComponent: (blocklet:
|
|
194
|
-
ancestors:
|
|
217
|
+
findComponent: (blocklet: TComponent, isEqualFn: (component: TComponent, context: {
|
|
218
|
+
ancestors: TComponent[];
|
|
195
219
|
}) => boolean, { _ancestors, returnAncestors, }?: {
|
|
196
|
-
_ancestors?:
|
|
220
|
+
_ancestors?: TComponent[];
|
|
197
221
|
returnAncestors?: boolean;
|
|
198
|
-
}) =>
|
|
199
|
-
component:
|
|
200
|
-
ancestors:
|
|
222
|
+
}) => TComponent | {
|
|
223
|
+
component: TComponent;
|
|
224
|
+
ancestors: TComponent[];
|
|
201
225
|
};
|
|
202
226
|
findComponentById: (blocklet: BlockletState | ComponentState, componentId: string | string[], { returnAncestors, }?: {
|
|
203
227
|
returnAncestors?: boolean;
|
|
204
|
-
}) =>
|
|
205
|
-
component:
|
|
206
|
-
ancestors:
|
|
228
|
+
}) => TComponent | {
|
|
229
|
+
component: TComponent;
|
|
230
|
+
ancestors: TComponent[];
|
|
207
231
|
};
|
|
232
|
+
findComponentV2: (app: BlockletState, isEqualFn: (component: TComponent, app: BlockletState) => boolean) => ComponentState;
|
|
233
|
+
findComponentByIdV2: (app: BlockletState, componentId: string | string[]) => ComponentState;
|
|
208
234
|
getParentComponentName: (name?: string) => string;
|
|
209
235
|
getConnectAppUrl: ({ request, baseUrl }: {
|
|
210
236
|
request: Partial<Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>>;
|
|
211
237
|
baseUrl: string;
|
|
212
238
|
}) => string;
|
|
213
239
|
getChainInfo: (env: Record<string, string>) => ChainInfo;
|
|
214
|
-
getBlockletChainInfo: (blocklet?:
|
|
240
|
+
getBlockletChainInfo: (blocklet?: TComponentPro) => ChainInfo;
|
|
215
241
|
isExternalBlocklet: (blocklet?: BlockletState) => boolean;
|
|
216
242
|
isPreferenceKey: (x: TConfig) => Boolean;
|
|
217
243
|
getRolesFromAuthConfig: (config: {
|
|
@@ -226,5 +252,6 @@ declare const _default: {
|
|
|
226
252
|
isInProgress: (status: string | number) => boolean;
|
|
227
253
|
isBeforeInstalled: (status: string | number) => boolean;
|
|
228
254
|
isRunning: (status: string | number) => boolean;
|
|
255
|
+
getComponentsInternalInfo: (app: BlockletState) => TComponentInternalInfo[];
|
|
229
256
|
};
|
|
230
257
|
export default _default;
|
package/lib/util.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.isRunning = exports.isBeforeInstalled = exports.isInProgress = exports.getBlockletServices = exports.getBlockletAppIdList = exports.getRolesFromAuthConfig = exports.isPreferenceKey = exports.isExternalBlocklet = exports.getBlockletChainInfo = exports.getChainInfo = exports.getConnectAppUrl = exports.getParentComponentName = exports.findComponentById = exports.findComponent = exports.getComponentBundleId = exports.getComponentName = exports.getComponentId = exports.replaceSlotToIp = exports.getWhoCanAccess = exports.findServiceFromMeta = exports.findWebInterfacePort = exports.findWebInterface = exports.fixBlockletStatus = exports.getAppDescription = exports.getDisplayName = exports.getAppName = exports.hasRunnableComponent = exports.wipeSensitiveData = exports.isEnvShareable = exports.getComponentMissingConfigs = exports.getAppMissingConfigs = exports.getSharedConfigObj = exports.isDeletableBlocklet = exports.forEachChildSync = exports.forEachChild = exports.forEachBlockletSync = exports.forEachBlocklet = exports.isComponentBlocklet = exports.isFreeComponent = exports.isFreeBlocklet = void 0;
|
|
6
|
+
exports.getComponentsInternalInfo = exports.isRunning = exports.isBeforeInstalled = exports.isInProgress = exports.getBlockletServices = exports.getBlockletAppIdList = exports.getRolesFromAuthConfig = exports.isPreferenceKey = exports.isExternalBlocklet = exports.getBlockletChainInfo = exports.getChainInfo = exports.getConnectAppUrl = exports.getParentComponentName = exports.findComponentByIdV2 = exports.findComponentV2 = exports.findComponentById = exports.findComponent = exports.getComponentBundleId = exports.getComponentName = exports.getComponentId = exports.replaceSlotToIp = exports.getWhoCanAccess = exports.findServiceFromMeta = exports.findWebInterfacePort = exports.findWebInterface = exports.fixBlockletStatus = exports.getAppDescription = exports.getDisplayName = exports.getAppName = exports.hasRunnableComponent = exports.wipeSensitiveData = exports.isEnvShareable = exports.getComponentMissingConfigs = exports.getAppMissingConfigs = exports.getSharedConfigObj = exports.isDeletableBlocklet = exports.forEachComponentV2Sync = exports.forEachComponentV2 = exports.forEachChildSync = exports.forEachChild = exports.forEachBlockletSync = exports.forEachBlocklet = exports.isComponentBlocklet = exports.isFreeComponent = exports.isFreeBlocklet = void 0;
|
|
7
7
|
/* eslint-disable no-await-in-loop */
|
|
8
8
|
const get_1 = __importDefault(require("lodash/get"));
|
|
9
9
|
const uniq_1 = __importDefault(require("lodash/uniq"));
|
|
@@ -131,6 +131,46 @@ const forEachBlocklet = (blocklet, cb, { parallel = false, concurrencyLimit = 5,
|
|
|
131
131
|
exports.forEachBlocklet = forEachBlocklet;
|
|
132
132
|
const forEachBlockletSync = (blocklet, cb) => forEachBlocklet(blocklet, cb, { sync: true });
|
|
133
133
|
exports.forEachBlockletSync = forEachBlockletSync;
|
|
134
|
+
const forEachComponentV2 = (blocklet, cb, { parallel = false, concurrencyLimit = 5, sync, } = {}) => {
|
|
135
|
+
// sync
|
|
136
|
+
if (sync) {
|
|
137
|
+
if (blocklet.children) {
|
|
138
|
+
for (const child of blocklet.children) {
|
|
139
|
+
cb(child);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
// serial
|
|
145
|
+
if (!parallel) {
|
|
146
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
147
|
+
return new Promise(async (resolve, reject) => {
|
|
148
|
+
try {
|
|
149
|
+
if (blocklet.children) {
|
|
150
|
+
for (const child of blocklet.children) {
|
|
151
|
+
await cb(child);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
resolve(null);
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
reject(err);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
// parallel
|
|
162
|
+
const limit = (0, p_limit_1.default)(concurrencyLimit);
|
|
163
|
+
const tasks = [];
|
|
164
|
+
if (blocklet.children) {
|
|
165
|
+
for (const child of blocklet.children) {
|
|
166
|
+
tasks.push(limit(() => cb(child)));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return Promise.all(tasks);
|
|
170
|
+
};
|
|
171
|
+
exports.forEachComponentV2 = forEachComponentV2;
|
|
172
|
+
const forEachComponentV2Sync = (blocklet, cb) => forEachComponentV2(blocklet, cb, { sync: true });
|
|
173
|
+
exports.forEachComponentV2Sync = forEachComponentV2Sync;
|
|
134
174
|
const forEachChild = (blocklet, cb, params) => {
|
|
135
175
|
return forEachBlocklet(blocklet, (b, opt) => {
|
|
136
176
|
if (opt.level === 0) {
|
|
@@ -177,6 +217,35 @@ const findComponentById = (blocklet, componentId, { returnAncestors = false, } =
|
|
|
177
217
|
}, { returnAncestors });
|
|
178
218
|
};
|
|
179
219
|
exports.findComponentById = findComponentById;
|
|
220
|
+
const findComponentV2 = (app, isEqualFn) => {
|
|
221
|
+
if (!isEqualFn) {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
for (const child of app.children || []) {
|
|
225
|
+
if (isEqualFn(child, app)) {
|
|
226
|
+
return child;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return null;
|
|
230
|
+
};
|
|
231
|
+
exports.findComponentV2 = findComponentV2;
|
|
232
|
+
const findComponentByIdV2 = (app, componentId) => {
|
|
233
|
+
if (!componentId) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
if (Array.isArray(componentId)) {
|
|
237
|
+
// eslint-disable-next-line no-param-reassign
|
|
238
|
+
componentId = componentId.join('/');
|
|
239
|
+
}
|
|
240
|
+
return findComponentV2(app, (component, _app) => {
|
|
241
|
+
if (componentId.includes('/')) {
|
|
242
|
+
const id = getComponentId(component, [_app]);
|
|
243
|
+
return componentId === id;
|
|
244
|
+
}
|
|
245
|
+
return componentId === component.meta.did;
|
|
246
|
+
});
|
|
247
|
+
};
|
|
248
|
+
exports.findComponentByIdV2 = findComponentByIdV2;
|
|
180
249
|
const isEnvShareable = (env) => {
|
|
181
250
|
return (!!env &&
|
|
182
251
|
!!(env.key || env.name) &&
|
|
@@ -572,6 +641,29 @@ const isBeforeInstalled = (status) => [
|
|
|
572
641
|
exports.isBeforeInstalled = isBeforeInstalled;
|
|
573
642
|
const isRunning = (status) => [constant_2.BlockletStatus.running, 'running'].includes(status);
|
|
574
643
|
exports.isRunning = isRunning;
|
|
644
|
+
const getComponentsInternalInfo = (app) => {
|
|
645
|
+
const components = [];
|
|
646
|
+
if (!app) {
|
|
647
|
+
return components;
|
|
648
|
+
}
|
|
649
|
+
forEachComponentV2Sync(app, (x) => {
|
|
650
|
+
const component = {
|
|
651
|
+
title: x.meta.title,
|
|
652
|
+
did: x.meta.did,
|
|
653
|
+
name: x.meta.name,
|
|
654
|
+
mountPoint: x.mountPoint || '',
|
|
655
|
+
status: x.status,
|
|
656
|
+
port: 0,
|
|
657
|
+
};
|
|
658
|
+
const webInterface = findWebInterface(x);
|
|
659
|
+
if (webInterface && (x.environments || []).find((y) => y.key === webInterface.port)) {
|
|
660
|
+
component.port = x.environments.find((y) => y.key === webInterface.port).value;
|
|
661
|
+
}
|
|
662
|
+
components.push(component);
|
|
663
|
+
});
|
|
664
|
+
return components;
|
|
665
|
+
};
|
|
666
|
+
exports.getComponentsInternalInfo = getComponentsInternalInfo;
|
|
575
667
|
exports.default = {
|
|
576
668
|
isFreeBlocklet,
|
|
577
669
|
isFreeComponent,
|
|
@@ -580,6 +672,8 @@ exports.default = {
|
|
|
580
672
|
forEachBlockletSync,
|
|
581
673
|
forEachChild,
|
|
582
674
|
forEachChildSync,
|
|
675
|
+
forEachComponentV2,
|
|
676
|
+
forEachComponentV2Sync,
|
|
583
677
|
isDeletableBlocklet,
|
|
584
678
|
getSharedConfigObj,
|
|
585
679
|
getAppMissingConfigs,
|
|
@@ -601,6 +695,8 @@ exports.default = {
|
|
|
601
695
|
getComponentBundleId,
|
|
602
696
|
findComponent,
|
|
603
697
|
findComponentById,
|
|
698
|
+
findComponentV2,
|
|
699
|
+
findComponentByIdV2,
|
|
604
700
|
getParentComponentName,
|
|
605
701
|
getConnectAppUrl,
|
|
606
702
|
getChainInfo,
|
|
@@ -612,4 +708,5 @@ exports.default = {
|
|
|
612
708
|
isInProgress,
|
|
613
709
|
isBeforeInstalled,
|
|
614
710
|
isRunning,
|
|
711
|
+
getComponentsInternalInfo,
|
|
615
712
|
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.16.11-next-
|
|
6
|
+
"version": "1.16.11-next-3d2b39f7",
|
|
7
7
|
"description": "Library to parse/validate/fix blocklet meta",
|
|
8
8
|
"main": "./lib/index.js",
|
|
9
9
|
"typings": "./lib/index.d.ts",
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
"author": "wangshijun <wangshijun2020@gmail.com> (http://github.com/wangshijun)",
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@abtnode/constant": "1.16.11-next-
|
|
28
|
-
"@abtnode/util": "1.16.11-next-
|
|
27
|
+
"@abtnode/constant": "1.16.11-next-3d2b39f7",
|
|
28
|
+
"@abtnode/util": "1.16.11-next-3d2b39f7",
|
|
29
29
|
"@arcblock/did": "1.18.80",
|
|
30
30
|
"@arcblock/did-ext": "1.18.80",
|
|
31
31
|
"@arcblock/did-util": "1.18.80",
|
|
32
32
|
"@arcblock/jwt": "1.18.80",
|
|
33
|
-
"@blocklet/constant": "1.16.11-next-
|
|
33
|
+
"@blocklet/constant": "1.16.11-next-3d2b39f7",
|
|
34
34
|
"@ocap/asset": "1.18.80",
|
|
35
35
|
"@ocap/mcrypto": "1.18.80",
|
|
36
36
|
"@ocap/types": "1.18.80",
|
|
@@ -79,5 +79,5 @@
|
|
|
79
79
|
"ts-node": "^10.9.1",
|
|
80
80
|
"typescript": "^5.0.4"
|
|
81
81
|
},
|
|
82
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "d0142bd2d1e49b94dcb5542d78e294a7b2258faa"
|
|
83
83
|
}
|