@blocklet/pages-kit 0.4.99 → 0.4.101
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/cjs/components/CustomComponentRenderer/state.js +5 -2
- package/lib/cjs/contexts/color.js +153 -0
- package/lib/cjs/tsconfig.tsbuildinfo +1 -1
- package/lib/cjs/types/index.js +1 -0
- package/lib/cjs/types/style.js +2 -0
- package/lib/cjs/utils/common.js +8 -0
- package/lib/cjs/utils/property.js +43 -2
- package/lib/cjs/utils/style.js +172 -0
- package/lib/esm/components/CustomComponentRenderer/state.js +5 -2
- package/lib/esm/contexts/color.js +149 -0
- package/lib/esm/tsconfig.tsbuildinfo +1 -1
- package/lib/esm/types/index.js +1 -0
- package/lib/esm/types/style.js +1 -0
- package/lib/esm/utils/common.js +4 -0
- package/lib/esm/utils/property.js +38 -1
- package/lib/esm/utils/style.js +160 -0
- package/lib/types/contexts/color.d.ts +25 -0
- package/lib/types/tsconfig.tsbuildinfo +1 -1
- package/lib/types/types/index.d.ts +1 -0
- package/lib/types/types/state.d.ts +20 -6
- package/lib/types/types/style.d.ts +31 -0
- package/lib/types/utils/common.d.ts +2 -0
- package/lib/types/utils/property.d.ts +3 -1
- package/lib/types/utils/style.d.ts +23 -0
- package/package.json +16 -4
package/lib/cjs/types/index.js
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isBrowserEnv = exports.COLOR_CONVERT_FUNCTION_NAME = void 0;
|
|
4
|
+
exports.COLOR_CONVERT_FUNCTION_NAME = 'colorConvert';
|
|
5
|
+
const isBrowserEnv = () => {
|
|
6
|
+
return typeof globalThis.window !== 'undefined' && typeof globalThis.document !== 'undefined';
|
|
7
|
+
};
|
|
8
|
+
exports.isBrowserEnv = isBrowserEnv;
|
|
@@ -22,8 +22,11 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
25
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.RenderNestedComponent = void 0;
|
|
29
|
+
exports.initDynamicParsePropertyValueHandlers = exports.RenderNestedComponent = void 0;
|
|
27
30
|
exports.componentUMDName = componentUMDName;
|
|
28
31
|
exports.mergeComponent = mergeComponent;
|
|
29
32
|
exports.safeJSONParse = safeJSONParse;
|
|
@@ -31,7 +34,9 @@ exports.safeYamlParse = safeYamlParse;
|
|
|
31
34
|
exports.parsePropertyValue = parsePropertyValue;
|
|
32
35
|
exports.assignNullableFields = assignNullableFields;
|
|
33
36
|
exports.getComponentDependencies = getComponentDependencies;
|
|
37
|
+
const isNil_1 = __importDefault(require("lodash/isNil"));
|
|
34
38
|
const yaml = __importStar(require("yaml"));
|
|
39
|
+
const common_1 = require("./common");
|
|
35
40
|
function componentUMDName({ componentId }) {
|
|
36
41
|
return `PagesCustomComponent${componentId}`;
|
|
37
42
|
}
|
|
@@ -98,7 +103,43 @@ function safeYamlParse(value) {
|
|
|
98
103
|
}
|
|
99
104
|
return yaml.parse(value);
|
|
100
105
|
}
|
|
101
|
-
|
|
106
|
+
let dynamicPropertyHandlers = null;
|
|
107
|
+
let initDynamicPropertyHandlersPromise = null;
|
|
108
|
+
// 根据前后端环境初始化动态的属性处理函数
|
|
109
|
+
const initDynamicParsePropertyValueHandlers = () => {
|
|
110
|
+
if (dynamicPropertyHandlers)
|
|
111
|
+
return Promise.resolve(dynamicPropertyHandlers);
|
|
112
|
+
if (!initDynamicPropertyHandlersPromise) {
|
|
113
|
+
initDynamicPropertyHandlersPromise = (async () => {
|
|
114
|
+
dynamicPropertyHandlers = {};
|
|
115
|
+
if ((0, common_1.isBrowserEnv)()) {
|
|
116
|
+
// colorConvert 需要前端环境才能处理,依赖 mui theme
|
|
117
|
+
// @ts-ignore
|
|
118
|
+
const colorConvertFn = globalThis[common_1.COLOR_CONVERT_FUNCTION_NAME];
|
|
119
|
+
if (typeof colorConvertFn === 'function') {
|
|
120
|
+
dynamicPropertyHandlers.color = (value) => colorConvertFn(value);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return dynamicPropertyHandlers;
|
|
124
|
+
})();
|
|
125
|
+
}
|
|
126
|
+
return initDynamicPropertyHandlersPromise;
|
|
127
|
+
};
|
|
128
|
+
exports.initDynamicParsePropertyValueHandlers = initDynamicParsePropertyValueHandlers;
|
|
129
|
+
(0, exports.initDynamicParsePropertyValueHandlers)();
|
|
130
|
+
function parsePropertyValue(property, value, { locale, defaultLocale, propertyHandlers, }) {
|
|
131
|
+
// 混合动态和自定义的属性处理函数,这个需要放在最前面,因为有可能存在覆盖下面的处理
|
|
132
|
+
const mixedPropertyHandlers = {
|
|
133
|
+
...(dynamicPropertyHandlers ?? {}),
|
|
134
|
+
...(propertyHandlers ?? {}),
|
|
135
|
+
};
|
|
136
|
+
if (mixedPropertyHandlers && property.type && typeof mixedPropertyHandlers[property.type] === 'function') {
|
|
137
|
+
const handler = mixedPropertyHandlers[property.type];
|
|
138
|
+
const result = handler?.(value);
|
|
139
|
+
if (!(0, isNil_1.default)(result)) {
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
102
143
|
if (property.type === 'json') {
|
|
103
144
|
if (!value)
|
|
104
145
|
return undefined;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getBlockletTheme = getBlockletTheme;
|
|
7
|
+
exports.isGradient = isGradient;
|
|
8
|
+
exports.isColorString = isColorString;
|
|
9
|
+
exports.isMuiColorKey = isMuiColorKey;
|
|
10
|
+
exports.getSafeGradient = getSafeGradient;
|
|
11
|
+
exports.parseColor = parseColor;
|
|
12
|
+
exports.colorConvert = colorConvert;
|
|
13
|
+
const Theme_1 = require("@arcblock/ux/lib/Theme");
|
|
14
|
+
const gradient_parser_1 = __importDefault(require("gradient-parser"));
|
|
15
|
+
const get_1 = __importDefault(require("lodash/get"));
|
|
16
|
+
const tinycolor2_1 = __importDefault(require("tinycolor2"));
|
|
17
|
+
const common_1 = require("./common");
|
|
18
|
+
const GRADIENT_START = 0;
|
|
19
|
+
const GRADIENT_END = 100;
|
|
20
|
+
const baseTheme = (0, Theme_1.createTheme)({});
|
|
21
|
+
const blockletTheme = (0, Theme_1.createTheme)({
|
|
22
|
+
breakpoints: {
|
|
23
|
+
values: {
|
|
24
|
+
xs: 0,
|
|
25
|
+
sm: baseTheme?.breakpoints?.values?.sm ?? 600,
|
|
26
|
+
md: baseTheme?.breakpoints?.values?.md ?? 900,
|
|
27
|
+
lg: baseTheme?.breakpoints?.values?.lg ?? 1200,
|
|
28
|
+
xl: baseTheme?.breakpoints?.values?.xl ?? 1536,
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
section: 1440,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
function getBlockletTheme() {
|
|
35
|
+
return blockletTheme;
|
|
36
|
+
}
|
|
37
|
+
function isGradient(color) {
|
|
38
|
+
if (color?.trim()) {
|
|
39
|
+
try {
|
|
40
|
+
gradient_parser_1.default.parse(color);
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
function isColorString(color) {
|
|
50
|
+
if (typeof color !== 'string') {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
if (isGradient(color)) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
const currentColor = (0, tinycolor2_1.default)(color);
|
|
57
|
+
if (currentColor.isValid()) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 检查字符串是否为有效的MUI颜色键
|
|
64
|
+
*/
|
|
65
|
+
function isMuiColorKey(value) {
|
|
66
|
+
// special case
|
|
67
|
+
if (value === 'transparent') {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
return /^(primary|secondary|error|warning|info|success|grey|background|text|action)\.[a-z0-9]+$/.test(value);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 处理渐变的解析,并转换为rgba格式
|
|
74
|
+
*/
|
|
75
|
+
function getSafeGradient(color) {
|
|
76
|
+
try {
|
|
77
|
+
const colorAst = gradient_parser_1.default.parse(color);
|
|
78
|
+
const safeAst = colorAst.map((astItem) => {
|
|
79
|
+
const colorStops = astItem.colorStops.map((colorStop, index) => {
|
|
80
|
+
let { value } = colorStop;
|
|
81
|
+
if (typeof value !== 'string' && !Array.isArray(value)) {
|
|
82
|
+
throw new Error('Invalid color stop value type');
|
|
83
|
+
}
|
|
84
|
+
let { type } = colorStop;
|
|
85
|
+
// 转换为 rgba 格式
|
|
86
|
+
if (type !== 'rgba') {
|
|
87
|
+
const rgbaValue = (0, tinycolor2_1.default)(value).toRgb();
|
|
88
|
+
value = [`${rgbaValue.r}`, `${rgbaValue.g}`, `${rgbaValue.b}`, `${rgbaValue.a}`];
|
|
89
|
+
type = 'rgba';
|
|
90
|
+
}
|
|
91
|
+
// 如果已有进度,保持原样
|
|
92
|
+
if (colorStop.length) {
|
|
93
|
+
return {
|
|
94
|
+
...colorStop,
|
|
95
|
+
value,
|
|
96
|
+
type,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
// 没有进度时,按 CSS 默认行为处理
|
|
100
|
+
const totalStops = astItem.colorStops.length;
|
|
101
|
+
let percentage;
|
|
102
|
+
if (index === 0) {
|
|
103
|
+
percentage = GRADIENT_START;
|
|
104
|
+
}
|
|
105
|
+
else if (index === totalStops - 1) {
|
|
106
|
+
percentage = GRADIENT_END;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// 中间的颜色均匀分布
|
|
110
|
+
percentage = (index / (totalStops - 1)) * 100;
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
...colorStop,
|
|
114
|
+
value,
|
|
115
|
+
type,
|
|
116
|
+
length: {
|
|
117
|
+
value: `${percentage}`,
|
|
118
|
+
type: '%',
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
...astItem,
|
|
124
|
+
colorStops,
|
|
125
|
+
};
|
|
126
|
+
});
|
|
127
|
+
const safeColor = gradient_parser_1.default.stringify(safeAst);
|
|
128
|
+
return safeColor.replace(/NaN/g, '100');
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
if (isColorString(color)) {
|
|
132
|
+
return `${color}`.replace(/NaN/g, '100');
|
|
133
|
+
}
|
|
134
|
+
return '';
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* 解析颜色字符串
|
|
139
|
+
*/
|
|
140
|
+
function parseColor(color = '') {
|
|
141
|
+
if (isGradient(color)) {
|
|
142
|
+
return color;
|
|
143
|
+
}
|
|
144
|
+
if (isColorString(color)) {
|
|
145
|
+
const currentColor = (0, tinycolor2_1.default)(color);
|
|
146
|
+
return currentColor.toRgbString();
|
|
147
|
+
}
|
|
148
|
+
return color;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* 转换颜色
|
|
152
|
+
* @param color - 颜色字符串
|
|
153
|
+
* @param _theme - 主题对象,默认为全局主题
|
|
154
|
+
* @returns 转换后的颜色字符串
|
|
155
|
+
*/
|
|
156
|
+
function colorConvert(color, _theme = blockletTheme) {
|
|
157
|
+
if (isMuiColorKey(color)) {
|
|
158
|
+
return (0, get_1.default)(_theme.palette, color);
|
|
159
|
+
}
|
|
160
|
+
// 处理渐变和普通颜色
|
|
161
|
+
if (isGradient(color)) {
|
|
162
|
+
return getSafeGradient(color);
|
|
163
|
+
}
|
|
164
|
+
if (isColorString(color)) {
|
|
165
|
+
return color;
|
|
166
|
+
}
|
|
167
|
+
return color || '';
|
|
168
|
+
}
|
|
169
|
+
if ((0, common_1.isBrowserEnv)()) {
|
|
170
|
+
// @ts-ignore inject colorConvert to globalThis
|
|
171
|
+
globalThis[common_1.COLOR_CONVERT_FUNCTION_NAME] = colorConvert;
|
|
172
|
+
}
|
|
@@ -76,7 +76,7 @@ function importCustomComponent(m, { componentId }) {
|
|
|
76
76
|
}
|
|
77
77
|
return null;
|
|
78
78
|
}, [loading, error, ResolvedComponent, props]);
|
|
79
|
-
return (_jsx(Fade, { in: !loading, timeout: 500, children: _jsx(Box, { children: content }) }));
|
|
79
|
+
return (_jsx(Fade, { in: !loading, timeout: 500, children: _jsx(Box, { className: "CustomComponent-root", children: content }) }));
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
82
|
// non-Promise case
|
|
@@ -249,7 +249,10 @@ export function useComponent({ instanceId, componentId, properties, locale, dev
|
|
|
249
249
|
if (!property)
|
|
250
250
|
return undefined;
|
|
251
251
|
// keep preload props
|
|
252
|
-
let v = parsePropertyValue(property, value, {
|
|
252
|
+
let v = parsePropertyValue(property, value, {
|
|
253
|
+
locale,
|
|
254
|
+
defaultLocale: dev?.defaultLocale,
|
|
255
|
+
});
|
|
253
256
|
if (dev?.mode === 'production' &&
|
|
254
257
|
property.type === 'component' &&
|
|
255
258
|
property.key &&
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { useTheme } from '@mui/material/styles';
|
|
2
|
+
import { useCallback, useMemo } from 'react';
|
|
3
|
+
import { isMuiColorKey, colorConvert } from '../utils/style';
|
|
4
|
+
/**
|
|
5
|
+
* Hook 用于获取和操作 MUI 主题色
|
|
6
|
+
*/
|
|
7
|
+
export function useMuiColorPalette() {
|
|
8
|
+
const theme = useTheme();
|
|
9
|
+
// 创建 MUI 色板预设及映射关系
|
|
10
|
+
const muiPaletteColors = useMemo(() => {
|
|
11
|
+
const colors = [];
|
|
12
|
+
// 定义调色板配置
|
|
13
|
+
const paletteConfig = [
|
|
14
|
+
// 特殊颜色组
|
|
15
|
+
{
|
|
16
|
+
type: 'special',
|
|
17
|
+
keys: ['transparent'],
|
|
18
|
+
variants: null,
|
|
19
|
+
format: () => 'transparent',
|
|
20
|
+
accessor: () => ({ transparent: 'transparent' }),
|
|
21
|
+
},
|
|
22
|
+
// mapper all colors
|
|
23
|
+
...['primary', 'secondary', 'error', 'warning', 'info', 'success'].map((key) => ({
|
|
24
|
+
type: key,
|
|
25
|
+
keys: [key],
|
|
26
|
+
variants: ['main', 'light', 'dark'],
|
|
27
|
+
format: (key, variant) => `${key}.${variant}`,
|
|
28
|
+
accessor: (key) => theme.palette[key],
|
|
29
|
+
})),
|
|
30
|
+
{
|
|
31
|
+
type: 'background',
|
|
32
|
+
keys: ['default', 'paper'],
|
|
33
|
+
variants: null,
|
|
34
|
+
format: (key) => `background.${key}`,
|
|
35
|
+
accessor: () => theme.palette.background,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
type: 'text',
|
|
39
|
+
keys: ['primary', 'secondary', 'disabled'],
|
|
40
|
+
variants: null,
|
|
41
|
+
format: (key) => `text.${key}`,
|
|
42
|
+
accessor: () => theme.palette.text,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
type: 'action',
|
|
46
|
+
keys: ['active', 'hover', 'selected', 'disabled', 'disabledBackground', 'focus'],
|
|
47
|
+
variants: null,
|
|
48
|
+
format: (key) => `action.${key}`,
|
|
49
|
+
accessor: () => theme.palette.action,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
type: 'grey',
|
|
53
|
+
keys: ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900'],
|
|
54
|
+
variants: null,
|
|
55
|
+
format: (key) => `grey.${key}`,
|
|
56
|
+
accessor: () => theme.palette.grey,
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
// 统一处理各种调色板颜色
|
|
60
|
+
paletteConfig.forEach((config) => {
|
|
61
|
+
const { keys, variants, format, accessor } = config;
|
|
62
|
+
if (variants) {
|
|
63
|
+
// 处理带变体的调色板(如primary.main)
|
|
64
|
+
keys.forEach((key) => {
|
|
65
|
+
variants.forEach((variant) => {
|
|
66
|
+
try {
|
|
67
|
+
const paletteObj = accessor(key);
|
|
68
|
+
if (paletteObj && typeof paletteObj === 'object') {
|
|
69
|
+
const colorValue = String(paletteObj[variant] || '');
|
|
70
|
+
if (colorValue) {
|
|
71
|
+
colors.push({ colorKey: format(key, variant), colorValue, group: config.type });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
// 忽略错误
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// 处理不带变体的调色板(如grey.500)
|
|
83
|
+
keys.forEach((key) => {
|
|
84
|
+
try {
|
|
85
|
+
const paletteObj = accessor();
|
|
86
|
+
if (paletteObj && typeof paletteObj === 'object') {
|
|
87
|
+
const colorValue = String(paletteObj[key] || '');
|
|
88
|
+
if (colorValue) {
|
|
89
|
+
colors.push({ colorKey: format(key), colorValue, group: config.type });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
// 忽略错误
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
return colors;
|
|
100
|
+
}, [theme]);
|
|
101
|
+
// 提取预设颜色数组 (仅颜色值)
|
|
102
|
+
const presetColors = useMemo(() => muiPaletteColors.map((color) => color.colorValue), [muiPaletteColors]);
|
|
103
|
+
// 根据颜色值获取 MUI 键名
|
|
104
|
+
const getMuiKeyByColor = useCallback((colorValue) => {
|
|
105
|
+
const found = muiPaletteColors.find((item) => item.colorValue === colorValue);
|
|
106
|
+
return found ? found.colorKey : null;
|
|
107
|
+
}, [muiPaletteColors]);
|
|
108
|
+
// 根据 MUI 键名获取颜色值
|
|
109
|
+
const getColorByMuiKey = useCallback((muiKey) => {
|
|
110
|
+
const found = muiPaletteColors.find((item) => item.colorKey === muiKey);
|
|
111
|
+
return found ? found.colorValue : null;
|
|
112
|
+
}, [muiPaletteColors]);
|
|
113
|
+
// 检查是否为有效的 MUI 颜色键
|
|
114
|
+
const isMuiColorKeyHook = useCallback((value) => {
|
|
115
|
+
return isMuiColorKey(value);
|
|
116
|
+
}, [isMuiColorKey]);
|
|
117
|
+
// 颜色分组逻辑
|
|
118
|
+
const groupedMuiColors = useMemo(() => {
|
|
119
|
+
const groups = {};
|
|
120
|
+
muiPaletteColors.forEach(({ colorKey, colorValue, group }) => {
|
|
121
|
+
if (group) {
|
|
122
|
+
if (!groups[group]) {
|
|
123
|
+
groups[group] = [];
|
|
124
|
+
}
|
|
125
|
+
groups[group].push({ colorKey, colorValue });
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
return groups;
|
|
129
|
+
}, [muiPaletteColors]);
|
|
130
|
+
return {
|
|
131
|
+
muiPaletteColors,
|
|
132
|
+
groupedMuiColors,
|
|
133
|
+
presetColors,
|
|
134
|
+
getMuiKeyByColor,
|
|
135
|
+
getColorByMuiKey,
|
|
136
|
+
isMuiColorKey: isMuiColorKeyHook,
|
|
137
|
+
theme,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* React Hook,用于实时转换颜色值(包括MUI主题色键)
|
|
142
|
+
*/
|
|
143
|
+
export function useColorConvert() {
|
|
144
|
+
const muiPalette = useMuiColorPalette();
|
|
145
|
+
const { theme } = muiPalette;
|
|
146
|
+
return useCallback((color = '') => {
|
|
147
|
+
return colorConvert(color, theme);
|
|
148
|
+
}, [theme, colorConvert]);
|
|
149
|
+
}
|