@smart100/spu-web-plugin 1.0.0 → 1.0.4
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/README.md +1 -0
- package/dist/index.d.ts +13 -15
- package/dist/spu-web-plugin.mjs +19354 -19345
- package/package.json +2 -2
- package/src/apaasSpuTrack.ts +42 -72
- package/src/axios.ts +136 -132
- package/src/cloudServ.ts +4 -4
- package/src/components/expandexp/index.ts +260 -205
- package/src/core.js +120 -59
- package/src/globalConfig.ts +5 -7
- package/src/index.ts +48 -111
- package/src/location.ts +20 -23
- package/src/login.ts +534 -428
- package/src/nativeApi.ts +7 -10
- package/src/oss/OSSClient.ts +20 -0
- package/src/oss/downloadService.ts +73 -73
- package/src/oss/index.ts +1 -5
- package/src/oss/multiUpload.ts +7 -4
- package/src/oss/servtoken.ts +2 -52
- package/src/oss/uploadService.ts +64 -78
- package/src/spuConfig.ts +7 -10
- package/src/storageProxy.ts +11 -13
- package/src/test.ts +3 -17
- package/src/types/global.d.ts +1 -1
- package/src/types/index.d.ts +13 -15
- package/src/types/shims-lib.d.ts +4 -10
- package/src/urlquery.ts +37 -5
- package/src/utils.ts +15 -31
- package/src/wxworksuitePlugin.ts +25 -0
package/package.json
CHANGED
package/src/apaasSpuTrack.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { globalOptions
|
|
1
|
+
import { globalOptions } from './index'
|
|
2
|
+
import { Module } from './core'
|
|
2
3
|
import { cloneDeep, merge, set } from 'lodash-es'
|
|
3
|
-
import
|
|
4
|
+
import { getUser, checkLogin } from './login'
|
|
5
|
+
import core from './core'
|
|
4
6
|
|
|
5
7
|
// @ts-ignore
|
|
6
8
|
import ApaasSpuTrack from './package/apaas-track/apaas-spu/index.umd.js'
|
|
@@ -30,43 +32,54 @@ const getWebInitParams = async () => {
|
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
35
|
+
const apaasSpuTrackSendLog = (data: any, isnotretry: boolean = false) => {
|
|
36
|
+
if (window.apaasSpuTrack) {
|
|
37
|
+
const logtime = Date.now().toString()
|
|
38
|
+
const baselog = cloneDeep({
|
|
39
|
+
...window.apaasSpuTrack.baseLog,
|
|
40
|
+
logtime: logtime,
|
|
41
|
+
epochnanos: logtime + '000000',
|
|
42
|
+
types: '',
|
|
43
|
+
event: '',
|
|
44
|
+
url: location.href,
|
|
45
|
+
properties: {
|
|
46
|
+
// // 图片导出相关信息
|
|
47
|
+
// // formtype: apaas | litheform | spu
|
|
48
|
+
// formtype: 'spu',
|
|
49
|
+
// // exporttype: 1=普通导出 | 2=后端图片扩展导出 | 3=图片导出SPU
|
|
50
|
+
// exporttype: '3',
|
|
51
|
+
// // pagecode
|
|
52
|
+
// // 当 formtype = apaas 表示低码表单code
|
|
53
|
+
// // 当 formtype = litheform 表示超表表单code
|
|
54
|
+
// // 当 formtype = spu 表示配置的spu页面pagecode
|
|
55
|
+
// pagecode: ''
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
const mergedata = merge(baselog, data)
|
|
59
|
+
// console.log(mergedata)
|
|
60
|
+
// debugger
|
|
61
|
+
window.apaasSpuTrack.addLogToQueue(mergedata, true)
|
|
62
|
+
} else {
|
|
63
|
+
if (!isnotretry) {
|
|
64
|
+
console.warn('window.apaasSpuTrack 不存在,导出日志延迟3秒后再次发送。')
|
|
65
|
+
setTimeout(() => {
|
|
66
|
+
apaasSpuTrackSendLog(data, true)
|
|
67
|
+
}, 3000)
|
|
47
68
|
} else {
|
|
48
|
-
|
|
49
|
-
result.msg = '不存在该 url 的 indextag。'
|
|
69
|
+
console.error('window.apaasSpuTrack 不存在,导出日志发送失败。')
|
|
50
70
|
}
|
|
51
|
-
} else {
|
|
52
|
-
result.code = 404
|
|
53
|
-
result.msg = '传入 url 为空。'
|
|
54
71
|
}
|
|
55
|
-
// console.log(result)
|
|
56
|
-
// debugger
|
|
57
|
-
// params.complete && params.complete(result.code, result.indextag, result.msg)
|
|
58
|
-
return result
|
|
59
72
|
}
|
|
60
73
|
|
|
61
74
|
// 兼容开启SPU日志
|
|
62
|
-
const
|
|
75
|
+
const installApaasSpuTrack = () => {
|
|
63
76
|
setTimeout(() => {
|
|
64
|
-
if (ApaasSpuTrack && !window.apaasSpuTrack &&
|
|
77
|
+
if (ApaasSpuTrack && !window.apaasSpuTrack && checkLogin() && getUser()) {
|
|
65
78
|
if (!window?.aPaaS?.getWebInitParams) {
|
|
66
79
|
set(window, 'aPaaS.getWebInitParams', getWebInitParams)
|
|
67
80
|
}
|
|
68
81
|
if (!window?.Module?.getIndextagSync) {
|
|
69
|
-
set(window, 'Module.getIndextagSync', getIndextagSync)
|
|
82
|
+
set(window, 'Module.getIndextagSync', core.getIndextagSync.bind(core))
|
|
70
83
|
}
|
|
71
84
|
|
|
72
85
|
ApaasSpuTrack.getApaasSpuTrack({
|
|
@@ -146,47 +159,4 @@ const initApaasSpuTrack = () => {
|
|
|
146
159
|
}, 3000)
|
|
147
160
|
}
|
|
148
161
|
|
|
149
|
-
|
|
150
|
-
if (window.apaasSpuTrack) {
|
|
151
|
-
const logtime = Date.now().toString()
|
|
152
|
-
const baselog = cloneDeep({
|
|
153
|
-
...window.apaasSpuTrack.baseLog,
|
|
154
|
-
logtime: logtime,
|
|
155
|
-
epochnanos: logtime + '000000',
|
|
156
|
-
types: '',
|
|
157
|
-
event: '',
|
|
158
|
-
url: location.href,
|
|
159
|
-
properties: {
|
|
160
|
-
// // 图片导出相关信息
|
|
161
|
-
// // formtype: apaas | litheform | spu
|
|
162
|
-
// formtype: 'spu',
|
|
163
|
-
// // exporttype: 1=普通导出 | 2=后端图片扩展导出 | 3=图片导出SPU
|
|
164
|
-
// exporttype: '3',
|
|
165
|
-
// // pagecode
|
|
166
|
-
// // 当 formtype = apaas 表示低码表单code
|
|
167
|
-
// // 当 formtype = litheform 表示超表表单code
|
|
168
|
-
// // 当 formtype = spu 表示配置的spu页面pagecode
|
|
169
|
-
// pagecode: ''
|
|
170
|
-
}
|
|
171
|
-
})
|
|
172
|
-
const mergedata = merge(baselog, data)
|
|
173
|
-
// console.log(mergedata)
|
|
174
|
-
// debugger
|
|
175
|
-
window.apaasSpuTrack.addLogToQueue(mergedata, true)
|
|
176
|
-
} else {
|
|
177
|
-
if (!isnotretry) {
|
|
178
|
-
console.warn('window.apaasSpuTrack 不存在,导出日志延迟3秒后再次发送。')
|
|
179
|
-
setTimeout(() => {
|
|
180
|
-
apaasSpuTrackSendLog(data, true)
|
|
181
|
-
}, 3000)
|
|
182
|
-
} else {
|
|
183
|
-
console.error('window.apaasSpuTrack 不存在,导出日志发送失败。')
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
export {
|
|
189
|
-
getIndextagSync,
|
|
190
|
-
initApaasSpuTrack,
|
|
191
|
-
apaasSpuTrackSendLog
|
|
192
|
-
}
|
|
162
|
+
export { installApaasSpuTrack, apaasSpuTrackSendLog }
|
package/src/axios.ts
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import axios from 'axios'
|
|
2
|
-
import type {
|
|
3
|
-
AxiosInstance,
|
|
4
|
-
AxiosError,
|
|
5
|
-
AxiosResponse
|
|
6
|
-
} from 'axios'
|
|
2
|
+
import type { AxiosInstance, AxiosResponse } from 'axios'
|
|
7
3
|
import { get } from 'lodash-es'
|
|
8
|
-
// import { Message } from 'element-ui'
|
|
9
4
|
import { loadding } from './components/loadding'
|
|
10
|
-
import
|
|
5
|
+
import { getToken, updateToken, getLoginState } from './login'
|
|
11
6
|
import core from './core'
|
|
12
|
-
import urlquery from './urlquery'
|
|
7
|
+
import { urlquery } from './urlquery'
|
|
13
8
|
|
|
14
9
|
interface Response {
|
|
15
10
|
code: number | string
|
|
@@ -20,7 +15,7 @@ interface Response {
|
|
|
20
15
|
|
|
21
16
|
const createAxiosInstance = (type: 'spu' | 'normal' = 'spu', options: any) => {
|
|
22
17
|
const axiosInstance: AxiosInstance = axios.create({
|
|
23
|
-
baseURL: type === 'spu' ? `/api/${options.modulekey}/${options.moduleversion}` : ''
|
|
18
|
+
baseURL: type === 'spu' ? `/api/${options.modulekey}/${options.moduleversion}` : ''
|
|
24
19
|
// baseURL: '',
|
|
25
20
|
// timeout: 36000000
|
|
26
21
|
// withCredentials: true, // 不能开启 影响ali oss
|
|
@@ -30,151 +25,164 @@ const createAxiosInstance = (type: 'spu' | 'normal' = 'spu', options: any) => {
|
|
|
30
25
|
// }
|
|
31
26
|
})
|
|
32
27
|
|
|
33
|
-
axiosInstance.interceptors.request.use(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (
|
|
28
|
+
axiosInstance.interceptors.request.use(
|
|
29
|
+
async (config: any) => {
|
|
30
|
+
// const isShowLoading = typeof config?.isShowLoading !== 'undefined' ? config.isShowLoading : true
|
|
31
|
+
// console.error(444444)
|
|
32
|
+
// console.log(config)
|
|
33
|
+
|
|
34
|
+
const isShowLoading = get(config, 'isShowLoading', true)
|
|
35
|
+
isShowLoading && loadding.open()
|
|
36
|
+
|
|
37
|
+
const isSendToken = get(config, 'isSendToken', true)
|
|
38
|
+
if (isSendToken) {
|
|
39
|
+
// 请求接口前校验是否过期 如果过期先刷新token
|
|
40
|
+
const loginState = getLoginState()
|
|
41
|
+
if (
|
|
42
|
+
config.url !== '/api/auth/refreshtoken' &&
|
|
43
|
+
!loginState.islogin &&
|
|
44
|
+
loginState.type === 2 &&
|
|
45
|
+
loginState.role !== 'center'
|
|
46
|
+
) {
|
|
47
47
|
try {
|
|
48
|
-
await
|
|
48
|
+
await updateToken()
|
|
49
49
|
} catch (err) {
|
|
50
50
|
console.error(err)
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
-
}
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
const token = getToken()
|
|
55
|
+
if (config?.headers && token) {
|
|
56
|
+
config.headers.token = token
|
|
57
|
+
}
|
|
58
58
|
}
|
|
59
|
-
}
|
|
60
59
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
if (type === 'spu' && config.modulekey) {
|
|
61
|
+
const moduleData: any = await core.getModuleData(config.modulekey)
|
|
62
|
+
if (moduleData.data) {
|
|
63
|
+
config.baseURL = `/api/${config.modulekey}/${moduleData.data.moduleversion}`
|
|
64
|
+
} else {
|
|
65
|
+
console.error(moduleData.errorMsg)
|
|
66
|
+
config.baseURL = `/api/${config.modulekey}/v?.?`
|
|
67
|
+
}
|
|
68
68
|
}
|
|
69
|
-
}
|
|
70
69
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
// 平台的业务接口开了开发者模式后,header带上debug方便查看接口的ide日志
|
|
71
|
+
if (type !== 'spu' && urlquery.isdebugger && config.url.indexOf('api/teapi/dy-biz/') > -1) {
|
|
72
|
+
if (config?.headers) {
|
|
73
|
+
config.headers.debug = 'true'
|
|
74
|
+
}
|
|
75
75
|
}
|
|
76
|
-
}
|
|
77
76
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
return config
|
|
78
|
+
},
|
|
79
|
+
(error) => {
|
|
80
|
+
return Promise.reject(error)
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
axiosInstance.interceptors.response.use(
|
|
85
|
+
(res: AxiosResponse) => {
|
|
86
|
+
// debugger
|
|
87
|
+
const isShowLoading = get(res, 'config.isShowLoading', true)
|
|
88
|
+
isShowLoading && loadding.close()
|
|
89
|
+
|
|
90
|
+
let realRes: Response = {
|
|
91
|
+
code: 404,
|
|
92
|
+
data: '',
|
|
93
|
+
msg: '',
|
|
94
|
+
message: ''
|
|
95
|
+
}
|
|
82
96
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
97
|
+
if (type === 'spu') {
|
|
98
|
+
if (res.data.code === 200) {
|
|
99
|
+
// return res.data
|
|
100
|
+
realRes = {
|
|
101
|
+
code: res.data.code,
|
|
102
|
+
data: res.data.data,
|
|
103
|
+
msg: res.data.msg,
|
|
104
|
+
message: res.data.msg
|
|
105
|
+
}
|
|
106
|
+
return realRes
|
|
107
|
+
} else {
|
|
108
|
+
realRes = {
|
|
109
|
+
code: res.data.code,
|
|
110
|
+
data: res.data.data,
|
|
111
|
+
msg: res.data.msg || '网络异常,请稍后重试。',
|
|
112
|
+
message: res.data.msg || '网络异常,请稍后重试。'
|
|
113
|
+
}
|
|
87
114
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
data: '',
|
|
91
|
-
msg: '',
|
|
92
|
-
message: ''
|
|
93
|
-
}
|
|
115
|
+
// const isShowErrorMessage = get(res, 'config.isShowErrorMessage', true)
|
|
116
|
+
// isShowErrorMessage && Message.error(realRes.msg)
|
|
94
117
|
|
|
95
|
-
|
|
96
|
-
if (res.data.code === 200) {
|
|
97
|
-
// return res.data
|
|
98
|
-
realRes = {
|
|
99
|
-
code: res.data.code,
|
|
100
|
-
data: res.data.data,
|
|
101
|
-
msg: res.data.msg,
|
|
102
|
-
message: res.data.msg
|
|
118
|
+
return Promise.reject(realRes) as any
|
|
103
119
|
}
|
|
104
|
-
|
|
105
|
-
} else {
|
|
120
|
+
} else if (type === 'normal') {
|
|
106
121
|
realRes = {
|
|
107
|
-
code: res.
|
|
108
|
-
data: res.data.data,
|
|
109
|
-
msg: res.data
|
|
110
|
-
message: res.data
|
|
122
|
+
code: res.status || 200,
|
|
123
|
+
data: res.data?.resp_data || res.data,
|
|
124
|
+
msg: res.data?.error_code || '',
|
|
125
|
+
message: res.data?.error_code || ''
|
|
111
126
|
}
|
|
112
|
-
|
|
113
|
-
// const isShowErrorMessage = get(res, 'config.isShowErrorMessage', true)
|
|
114
|
-
// isShowErrorMessage && Message.error(realRes.msg)
|
|
115
|
-
|
|
116
|
-
return Promise.reject(realRes) as any
|
|
127
|
+
return realRes
|
|
117
128
|
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
129
|
+
},
|
|
130
|
+
(err: any) => {
|
|
131
|
+
// err: AxiosError
|
|
132
|
+
// console.log(err)
|
|
133
|
+
// debugger
|
|
134
|
+
const isShowLoading = get(err, 'config.isShowLoading', true)
|
|
135
|
+
isShowLoading && loadding.close()
|
|
136
|
+
|
|
137
|
+
// console.log(err)
|
|
138
|
+
// debugger
|
|
139
|
+
|
|
140
|
+
let msg = ''
|
|
141
|
+
if (type === 'spu') {
|
|
142
|
+
msg = get(err, 'response.data.msg', '')
|
|
143
|
+
} else {
|
|
144
|
+
msg = get(err, 'response.data.error_code', '')
|
|
124
145
|
}
|
|
125
|
-
return realRes
|
|
126
|
-
}
|
|
127
|
-
}, (err: any) => {
|
|
128
|
-
// err: AxiosError
|
|
129
|
-
// console.log(err)
|
|
130
|
-
// debugger
|
|
131
|
-
const isShowLoading = get(err, 'config.isShowLoading', true)
|
|
132
|
-
isShowLoading && loadding.close()
|
|
133
|
-
|
|
134
|
-
// console.log(err)
|
|
135
|
-
// debugger
|
|
136
|
-
|
|
137
|
-
let msg = ''
|
|
138
|
-
if (type === 'spu') {
|
|
139
|
-
msg = get(err, 'response.data.msg', '')
|
|
140
|
-
} else {
|
|
141
|
-
msg = get(err, 'response.data.error_code', '')
|
|
142
|
-
}
|
|
143
146
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
if (msg) {
|
|
148
|
+
err.message = msg
|
|
149
|
+
} else {
|
|
150
|
+
err.message = err.response?.statusText || err.message || '网络异常,请稍后重试。'
|
|
151
|
+
}
|
|
152
|
+
err.msg = err.message
|
|
150
153
|
|
|
151
|
-
|
|
152
|
-
|
|
154
|
+
// const isShowErrorMessage = get(err, 'config.isShowErrorMessage', true)
|
|
155
|
+
// isShowErrorMessage && Message.error(msg)
|
|
153
156
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
157
|
+
const isNoLogin = () => {
|
|
158
|
+
if (type === 'spu') {
|
|
159
|
+
if (err.message === '未授权' && get(err, 'response.data.code') === 401) {
|
|
160
|
+
return true
|
|
161
|
+
} else {
|
|
162
|
+
return false
|
|
163
|
+
}
|
|
164
|
+
} else if (type === 'normal') {
|
|
165
|
+
if (
|
|
166
|
+
err.message.indexOf('token is invalid(decode).') !== -1 ||
|
|
167
|
+
err.message.indexOf('token is invalid(null).') !== -1 ||
|
|
168
|
+
err.message === 'token无效,请重新登录' ||
|
|
169
|
+
err.message === 'jwt token无效'
|
|
170
|
+
) {
|
|
171
|
+
return true
|
|
172
|
+
} else {
|
|
173
|
+
return false
|
|
174
|
+
}
|
|
166
175
|
}
|
|
167
176
|
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const noLoginFn = () => {
|
|
171
|
-
if (isNoLogin()) {
|
|
172
177
|
|
|
178
|
+
const noLoginFn = () => {
|
|
179
|
+
if (isNoLogin()) {
|
|
180
|
+
}
|
|
173
181
|
}
|
|
174
|
-
}
|
|
175
182
|
|
|
176
|
-
|
|
177
|
-
|
|
183
|
+
return Promise.reject(err)
|
|
184
|
+
}
|
|
185
|
+
)
|
|
178
186
|
|
|
179
187
|
return axiosInstance
|
|
180
188
|
}
|
|
@@ -182,13 +190,9 @@ const createAxiosInstance = (type: 'spu' | 'normal' = 'spu', options: any) => {
|
|
|
182
190
|
let spuAxios: any = null
|
|
183
191
|
let normalAxios: any = null
|
|
184
192
|
|
|
185
|
-
function
|
|
193
|
+
function installAxios(options: any) {
|
|
186
194
|
spuAxios = createAxiosInstance('spu', options)
|
|
187
195
|
normalAxios = createAxiosInstance('normal', options)
|
|
188
196
|
}
|
|
189
197
|
|
|
190
|
-
export {
|
|
191
|
-
initAxios,
|
|
192
|
-
spuAxios,
|
|
193
|
-
normalAxios as axios
|
|
194
|
-
}
|
|
198
|
+
export { installAxios, spuAxios, normalAxios as axios }
|
package/src/cloudServ.ts
CHANGED
|
@@ -5,7 +5,7 @@ class CloudServ {
|
|
|
5
5
|
|
|
6
6
|
cacheStorage: NormalizedCloudServ | null = null
|
|
7
7
|
|
|
8
|
-
public get
|
|
8
|
+
public get(key: StorageType = 'storage'): NormalizedCloudServItem | null {
|
|
9
9
|
if (this.cacheStorage) {
|
|
10
10
|
return this.cacheStorage[key] || null
|
|
11
11
|
}
|
|
@@ -18,7 +18,7 @@ class CloudServ {
|
|
|
18
18
|
return storage[key]
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
public set
|
|
21
|
+
public set(storage: NormalizedCloudServ | string) {
|
|
22
22
|
if (typeof storage === 'object') {
|
|
23
23
|
this.cacheStorage = storage
|
|
24
24
|
storage = JSON.stringify(storage)
|
|
@@ -26,11 +26,11 @@ class CloudServ {
|
|
|
26
26
|
lsProxy.setItem(this.CLOUD_SERVE_KEY, storage)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
public remove
|
|
29
|
+
public remove() {
|
|
30
30
|
lsProxy.removeItem(this.CLOUD_SERVE_KEY)
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
public getProvider
|
|
33
|
+
public getProvider(sign: StorageType = 'storage'): IAny | null {
|
|
34
34
|
const storage: NormalizedCloudServItem | null = this.get(sign)
|
|
35
35
|
if (!storage) {
|
|
36
36
|
return null
|