@mpxjs/webpack-plugin 2.10.20 → 2.10.21
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/index.js +13 -1
- package/lib/parser.js +1 -1
- package/lib/platform/style/wx/index.js +78 -30
- package/lib/platform/template/wx/component-config/block.js +2 -1
- package/lib/platform/template/wx/component-config/unsupported.js +1 -1
- package/lib/react/processTemplate.js +23 -10
- package/lib/react/style-helper.js +1 -1
- package/lib/react/template-loader.js +15 -2
- package/lib/runtime/components/react/context.ts +8 -1
- package/lib/runtime/components/react/dist/context.d.ts +6 -1
- package/lib/runtime/components/react/dist/context.js +1 -0
- package/lib/runtime/components/react/dist/getInnerListeners.js +1 -0
- package/lib/runtime/components/react/dist/mpx-button.d.ts +1 -1
- package/lib/runtime/components/react/dist/mpx-button.jsx +6 -5
- package/lib/runtime/components/react/dist/mpx-camera.jsx +1 -0
- package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +4 -1
- package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-checkbox.jsx +6 -4
- package/lib/runtime/components/react/dist/mpx-form.jsx +3 -3
- package/lib/runtime/components/react/dist/mpx-icon/index.jsx +5 -1
- package/lib/runtime/components/react/dist/mpx-image.d.ts +3 -2
- package/lib/runtime/components/react/dist/mpx-image.jsx +46 -12
- package/lib/runtime/components/react/dist/mpx-inline-text.jsx +10 -6
- package/lib/runtime/components/react/dist/mpx-input.jsx +17 -4
- package/lib/runtime/components/react/dist/mpx-label.jsx +6 -4
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +19 -4
- package/lib/runtime/components/react/dist/mpx-picker/index.jsx +12 -2
- package/lib/runtime/components/react/dist/mpx-picker-view/index.jsx +7 -4
- package/lib/runtime/components/react/dist/mpx-portal/index.jsx +5 -1
- package/lib/runtime/components/react/dist/mpx-radio-group.jsx +4 -1
- package/lib/runtime/components/react/dist/mpx-radio.jsx +5 -4
- package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +3 -1
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +13 -4
- package/lib/runtime/components/react/dist/mpx-simple-text.jsx +52 -6
- package/lib/runtime/components/react/dist/mpx-simple-view.jsx +36 -6
- package/lib/runtime/components/react/dist/mpx-slider.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +8 -4
- package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +6 -4
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +7 -4
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +15 -4
- package/lib/runtime/components/react/dist/mpx-switch.jsx +4 -1
- package/lib/runtime/components/react/dist/mpx-text.jsx +57 -12
- package/lib/runtime/components/react/dist/mpx-video.d.ts +2 -1
- package/lib/runtime/components/react/dist/mpx-video.jsx +10 -4
- package/lib/runtime/components/react/dist/mpx-view.jsx +42 -7
- package/lib/runtime/components/react/dist/utils.d.ts +21 -11
- package/lib/runtime/components/react/dist/utils.jsx +102 -33
- package/lib/runtime/components/react/getInnerListeners.ts +1 -0
- package/lib/runtime/components/react/mpx-button.tsx +6 -5
- package/lib/runtime/components/react/mpx-camera.tsx +1 -0
- package/lib/runtime/components/react/mpx-canvas/index.tsx +4 -1
- package/lib/runtime/components/react/mpx-checkbox-group.tsx +2 -1
- package/lib/runtime/components/react/mpx-checkbox.tsx +6 -4
- package/lib/runtime/components/react/mpx-form.tsx +3 -3
- package/lib/runtime/components/react/mpx-icon/index.tsx +5 -1
- package/lib/runtime/components/react/mpx-image.tsx +58 -19
- package/lib/runtime/components/react/mpx-inline-text.tsx +12 -7
- package/lib/runtime/components/react/mpx-input.tsx +17 -4
- package/lib/runtime/components/react/mpx-label.tsx +6 -4
- package/lib/runtime/components/react/mpx-movable-view.tsx +20 -4
- package/lib/runtime/components/react/mpx-picker/index.tsx +12 -2
- package/lib/runtime/components/react/mpx-picker-view/index.tsx +8 -4
- package/lib/runtime/components/react/mpx-portal/index.tsx +5 -1
- package/lib/runtime/components/react/mpx-radio-group.tsx +4 -1
- package/lib/runtime/components/react/mpx-radio.tsx +5 -4
- package/lib/runtime/components/react/mpx-rich-text/index.tsx +3 -1
- package/lib/runtime/components/react/mpx-scroll-view.tsx +13 -4
- package/lib/runtime/components/react/mpx-simple-text.tsx +55 -8
- package/lib/runtime/components/react/mpx-simple-view.tsx +30 -6
- package/lib/runtime/components/react/mpx-slider.tsx +2 -1
- package/lib/runtime/components/react/mpx-sticky-header.tsx +8 -4
- package/lib/runtime/components/react/mpx-sticky-section.tsx +6 -4
- package/lib/runtime/components/react/mpx-swiper-item.tsx +7 -4
- package/lib/runtime/components/react/mpx-swiper.tsx +16 -4
- package/lib/runtime/components/react/mpx-switch.tsx +4 -1
- package/lib/runtime/components/react/mpx-text.tsx +55 -15
- package/lib/runtime/components/react/mpx-video.tsx +11 -5
- package/lib/runtime/components/react/mpx-view.tsx +35 -7
- package/lib/runtime/components/react/types/global.d.ts +4 -0
- package/lib/runtime/components/react/utils.tsx +123 -43
- package/lib/runtime/optionProcessorReact.js +5 -0
- package/lib/script-setup-compiler/index.js +1 -1
- package/lib/style-compiler/plugins/trans-special.js +1 -1
- package/lib/template-compiler/compiler.js +37 -14
- package/lib/utils/gen-component-tag.js +1 -5
- package/lib/utils/normalize-perf-options.js +47 -0
- package/lib/web/index.js +1 -0
- package/lib/web/processMainScript.js +3 -7
- package/lib/web/processScript.js +3 -6
- package/lib/web/processStyles.js +12 -3
- package/lib/wxml/loader.js +1 -1
- package/package.json +5 -4
|
@@ -108,6 +108,8 @@ let isCustomText
|
|
|
108
108
|
let runtimeCompile
|
|
109
109
|
let rulesRunner
|
|
110
110
|
let customBuiltInComponentsOpt
|
|
111
|
+
let isUrlRequest
|
|
112
|
+
let templateAssetId
|
|
111
113
|
let currentEl
|
|
112
114
|
let injectNodes = []
|
|
113
115
|
let forScopes = []
|
|
@@ -602,15 +604,11 @@ function parseComponent (content, options) {
|
|
|
602
604
|
}
|
|
603
605
|
|
|
604
606
|
function padContent (block, pad) {
|
|
605
|
-
if (block.tag === 'style' && pad === 'line') {
|
|
606
|
-
const offset = content.slice(0, block.start).split(splitRE).length
|
|
607
|
-
return Array(offset).join(`/* ${STYLE_PAD_PLACEHOLDER} */\n`)
|
|
608
|
-
}
|
|
609
607
|
if (pad === 'space') {
|
|
610
608
|
return content.slice(0, block.start).replace(replaceRE, ' ')
|
|
611
609
|
} else {
|
|
612
610
|
const offset = content.slice(0, block.start).split(splitRE).length
|
|
613
|
-
const padChar = '\n'
|
|
611
|
+
const padChar = block.tag === 'style' ? `/* ${STYLE_PAD_PLACEHOLDER} */\n` : '\n'
|
|
614
612
|
return Array(offset).join(padChar)
|
|
615
613
|
}
|
|
616
614
|
}
|
|
@@ -654,6 +652,8 @@ function parse (template, options) {
|
|
|
654
652
|
usingComponentsInfo = options.usingComponentsInfo || {}
|
|
655
653
|
usingComponents = Object.keys(usingComponentsInfo)
|
|
656
654
|
customBuiltInComponentsOpt = options.customBuiltInComponents || null
|
|
655
|
+
isUrlRequest = options.isUrlRequest
|
|
656
|
+
templateAssetId = 0
|
|
657
657
|
|
|
658
658
|
// 初始化跨平台语法检测配置(每次解析时只初始化一次)
|
|
659
659
|
crossPlatformConfig = initCrossPlatformConfig()
|
|
@@ -2025,17 +2025,23 @@ const spreadREG = /\{\s*\.\.\.\s*([^,{]+?)\s*\}/g
|
|
|
2025
2025
|
|
|
2026
2026
|
function processAttrs (el, options) {
|
|
2027
2027
|
el.attrsList.forEach((attr) => {
|
|
2028
|
-
const isTemplateData = el.tag === 'template' && attr.name === 'data'
|
|
2028
|
+
const isTemplateData = el.tag === 'template' && attr.name === 'data' && attr.value
|
|
2029
2029
|
const needWrap = isTemplateData && mode !== 'swan'
|
|
2030
2030
|
let value = needWrap ? `{${attr.value}}` : attr.value
|
|
2031
2031
|
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2032
|
+
if (isReact(mode)) {
|
|
2033
|
+
// 修复React Native环境下属性值中插值表达式带空格的问题
|
|
2034
|
+
if (typeof value === 'string') {
|
|
2035
|
+
// 检查是否为带空格的插值表达式
|
|
2036
|
+
const trimmedValue = value.trim()
|
|
2037
|
+
if (trimmedValue.startsWith('{{') && trimmedValue.endsWith('}}')) {
|
|
2038
|
+
// 如果是纯插值表达式但带有前后空格,则使用去除空格后的值进行解析
|
|
2039
|
+
value = trimmedValue
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
if (value === undefined) {
|
|
2043
|
+
value = '{{true}}'
|
|
2044
|
+
modifyAttr(el, attr.name, value)
|
|
2039
2045
|
}
|
|
2040
2046
|
}
|
|
2041
2047
|
|
|
@@ -2605,6 +2611,21 @@ function processBuiltInComponents (el, meta) {
|
|
|
2605
2611
|
}
|
|
2606
2612
|
}
|
|
2607
2613
|
|
|
2614
|
+
const reactTemplateAssetTags = makeMap('mpx-image,mpx-video,mpx-audio', true)
|
|
2615
|
+
|
|
2616
|
+
function processTemplateAssetReact (el, meta) {
|
|
2617
|
+
if (!reactTemplateAssetTags(el.tag)) return
|
|
2618
|
+
const src = el.attrsMap.src
|
|
2619
|
+
if (!isUrlRequest(src)) return
|
|
2620
|
+
|
|
2621
|
+
const name = `__mpx_template_asset_${templateAssetId++}__`
|
|
2622
|
+
if (!meta.templateAssets) {
|
|
2623
|
+
meta.templateAssets = {}
|
|
2624
|
+
}
|
|
2625
|
+
meta.templateAssets[name] = src
|
|
2626
|
+
addExp(el, name, false, 'src')
|
|
2627
|
+
}
|
|
2628
|
+
|
|
2608
2629
|
/** Web / RN 共用:<import src> 收集并移除 */
|
|
2609
2630
|
function processTemplateImport (el, meta) {
|
|
2610
2631
|
if (el.tag !== 'import') return false
|
|
@@ -2629,7 +2650,7 @@ function processTemplateImport (el, meta) {
|
|
|
2629
2650
|
function processTemplateTranspile (el, meta) {
|
|
2630
2651
|
if (processTemplateImport(el, meta)) return
|
|
2631
2652
|
|
|
2632
|
-
if (el.tag !== 'template') return
|
|
2653
|
+
if (el.tag !== 'template' || el.isBlock) return
|
|
2633
2654
|
|
|
2634
2655
|
const is = getAndRemoveAttr(el, 'is').val
|
|
2635
2656
|
if (is) {
|
|
@@ -3133,6 +3154,8 @@ function processElement (el, root, options, meta) {
|
|
|
3133
3154
|
const isReactComponent$1 = isReactComponent(el, options)
|
|
3134
3155
|
// 收集内建组件
|
|
3135
3156
|
processBuiltInComponents(el, meta)
|
|
3157
|
+
// 处理模版内资源引用
|
|
3158
|
+
processTemplateAssetReact(el, meta)
|
|
3136
3159
|
// 预处理代码维度条件编译
|
|
3137
3160
|
processIf(el)
|
|
3138
3161
|
processFor(el)
|
|
@@ -20,10 +20,6 @@ function genComponentTag (part, processor = {}) {
|
|
|
20
20
|
content: processor
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
if (part.content) {
|
|
24
|
-
// unpad
|
|
25
|
-
part.content = '\n' + part.content.replace(/^\n*/m, '')
|
|
26
|
-
}
|
|
27
23
|
|
|
28
24
|
const tag = processor.tag ? processor.tag(part) : part.tag
|
|
29
25
|
const attrs = processor.attrs ? processor.attrs(part) : part.attrs
|
|
@@ -35,7 +31,7 @@ function genComponentTag (part, processor = {}) {
|
|
|
35
31
|
result += stringifyAttrs(attrs)
|
|
36
32
|
}
|
|
37
33
|
if (content) {
|
|
38
|
-
result +=
|
|
34
|
+
result += `>\n${content}\n</${tag}>`
|
|
39
35
|
} else {
|
|
40
36
|
result += '/>'
|
|
41
37
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// 当前已知分组列表,未来新增分组扩这个数组 + 同步加 declare 即可。
|
|
4
|
+
// @mpxjs/perf 包零感知分组——分组逻辑只存在于 webpack-plugin 这一侧。
|
|
5
|
+
const PERF_GROUPS = ['framework', 'user']
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 把用户配置 { enable, probes } 归一化成「总开关 + 各分组开关」。
|
|
9
|
+
*
|
|
10
|
+
* 输出形如:
|
|
11
|
+
* { enable: true, framework: true, user: false }
|
|
12
|
+
*
|
|
13
|
+
* - `enable: false` 或不传 perf → 全关。
|
|
14
|
+
* - `enable: true && probes: []` → 等价于 enable: false(没有分组要开就视为关闭)。
|
|
15
|
+
* - probes 中出现未知分组名 → 抛错(避免 typo 静默失效)。
|
|
16
|
+
*/
|
|
17
|
+
function normalizePerfOptions (raw) {
|
|
18
|
+
if (!raw || raw.enable !== true) {
|
|
19
|
+
const off = { enable: false }
|
|
20
|
+
for (let i = 0; i < PERF_GROUPS.length; i++) off[PERF_GROUPS[i]] = false
|
|
21
|
+
return off
|
|
22
|
+
}
|
|
23
|
+
const probes = Array.isArray(raw.probes) ? raw.probes : []
|
|
24
|
+
for (let i = 0; i < probes.length; i++) {
|
|
25
|
+
if (PERF_GROUPS.indexOf(probes[i]) === -1) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`[mpx perf] unknown probe "${probes[i]}"; known probes: ${PERF_GROUPS.join(', ')}`
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const result = {}
|
|
32
|
+
let anyOn = false
|
|
33
|
+
for (let i = 0; i < PERF_GROUPS.length; i++) {
|
|
34
|
+
const k = PERF_GROUPS[i]
|
|
35
|
+
const on = probes.indexOf(k) !== -1
|
|
36
|
+
result[k] = on
|
|
37
|
+
if (on) anyOn = true
|
|
38
|
+
}
|
|
39
|
+
// 派生总开关:任一分组打开 → enable 才真正有效。
|
|
40
|
+
result.enable = anyOn
|
|
41
|
+
return result
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = {
|
|
45
|
+
PERF_GROUPS,
|
|
46
|
+
normalizePerfOptions
|
|
47
|
+
}
|
package/lib/web/index.js
CHANGED
|
@@ -21,7 +21,7 @@ module.exports = function ({
|
|
|
21
21
|
tabBarStr,
|
|
22
22
|
localPagesMap
|
|
23
23
|
}, callback) {
|
|
24
|
-
const { i18n, webConfig
|
|
24
|
+
const { i18n, webConfig } = loaderContext.getMpx()
|
|
25
25
|
const { pagesMap, firstPage, globalTabBar } = buildPagesMap({
|
|
26
26
|
localPagesMap,
|
|
27
27
|
loaderContext,
|
|
@@ -37,12 +37,8 @@ module.exports = function ({
|
|
|
37
37
|
jsonConfig
|
|
38
38
|
})
|
|
39
39
|
|
|
40
|
-
let output =
|
|
41
|
-
|
|
42
|
-
if (hasUnoCSS) {
|
|
43
|
-
output += 'import \'uno.css\'\n'
|
|
44
|
-
}
|
|
45
|
-
output += `import Vue from 'vue'
|
|
40
|
+
let output = `import '@mpxjs/webpack-plugin/lib/runtime/base.styl'
|
|
41
|
+
import Vue from 'vue'
|
|
46
42
|
import VueRouter from 'vue-router'
|
|
47
43
|
import Mpx from '@mpxjs/core'
|
|
48
44
|
import { processAppOption, getComponent } from ${stringifyRequest(loaderContext, optionProcessorPath)}
|
package/lib/web/processScript.js
CHANGED
|
@@ -56,11 +56,8 @@ module.exports = function (script, {
|
|
|
56
56
|
(wxTemplateComponentsInfo.locals && wxTemplateComponentsInfo.locals.length)))
|
|
57
57
|
const optionProcessorImports = ['processComponentOption', 'getComponent', 'getWxsMixin']
|
|
58
58
|
if (hasWxTemplate) optionProcessorImports.push('createTemplateComponent')
|
|
59
|
-
let content =
|
|
60
|
-
|
|
61
|
-
if (!appInfo.name) {
|
|
62
|
-
hasApp = false
|
|
63
|
-
}
|
|
59
|
+
let content = ` import { ${optionProcessorImports.join(', ')} } from ${stringifyRequest(loaderContext, optionProcessorPath)}\n`
|
|
60
|
+
const hasApp = !!appInfo.name
|
|
64
61
|
// 注入wxs模块
|
|
65
62
|
content += ' var wxsModules = {}\n'
|
|
66
63
|
if (wxsModuleMap) {
|
|
@@ -128,7 +125,7 @@ module.exports = function (script, {
|
|
|
128
125
|
wxsMixin: getWxsMixin(wxsModules),
|
|
129
126
|
hasApp: ${hasApp},
|
|
130
127
|
disablePageTransition: ${JSON.stringify(disablePageTransition)},
|
|
131
|
-
})
|
|
128
|
+
})`
|
|
132
129
|
return content
|
|
133
130
|
}
|
|
134
131
|
})
|
package/lib/web/processStyles.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
const genComponentTag = require('../utils/gen-component-tag')
|
|
2
2
|
|
|
3
|
-
module.exports = function (styles,
|
|
3
|
+
module.exports = function (styles, { loaderContext, ctorType, autoScope, moduleId }, callback) {
|
|
4
4
|
let output = '/* styles */\n'
|
|
5
|
+
const { hasUnoCSS, appInfo } = loaderContext.getMpx()
|
|
6
|
+
const hasApp = !!appInfo.name
|
|
5
7
|
if (styles.length) {
|
|
6
8
|
styles.forEach((style) => {
|
|
7
9
|
output += genComponentTag(style, {
|
|
8
10
|
attrs (style) {
|
|
9
11
|
const attrs = Object.assign({}, style.attrs)
|
|
10
|
-
if (
|
|
12
|
+
if (autoScope) attrs.scoped = true
|
|
11
13
|
attrs.mpxStyleOptions = JSON.stringify({
|
|
12
14
|
scoped: attrs.scoped,
|
|
13
15
|
// query中包含module字符串会被新版vue-cli中的默认rules当做css-module处理
|
|
14
|
-
mid:
|
|
16
|
+
mid: moduleId
|
|
15
17
|
})
|
|
16
18
|
delete attrs.scoped
|
|
17
19
|
return attrs
|
|
@@ -19,6 +21,13 @@ module.exports = function (styles, options, callback) {
|
|
|
19
21
|
})
|
|
20
22
|
output += '\n'
|
|
21
23
|
})
|
|
24
|
+
}
|
|
25
|
+
if (hasUnoCSS && (ctorType === 'app' || !hasApp)) {
|
|
26
|
+
// 将unocss的引入放到App style之后,拉齐小程序中unocss覆盖全局样式的行为
|
|
27
|
+
output += genComponentTag({
|
|
28
|
+
tag: 'style',
|
|
29
|
+
content: '@import \'uno.css\';'
|
|
30
|
+
})
|
|
22
31
|
output += '\n'
|
|
23
32
|
}
|
|
24
33
|
callback(null, {
|
package/lib/wxml/loader.js
CHANGED
|
@@ -39,7 +39,7 @@ module.exports = function (content) {
|
|
|
39
39
|
|
|
40
40
|
const { getRequestString } = createHelpers(this)
|
|
41
41
|
|
|
42
|
-
const attributes = ['image:src', '
|
|
42
|
+
const attributes = ['image:src', 'video:src', 'cover-image:src', 'import:src', 'include:src', `${config[mode].wxs.tag}:${config[mode].wxs.src}`].concat(customAttributes)
|
|
43
43
|
|
|
44
44
|
const links = attrParse(content, function (tag, attr) {
|
|
45
45
|
const res = attributes.find(function (a) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mpxjs/webpack-plugin",
|
|
3
|
-
"version": "2.10.
|
|
3
|
+
"version": "2.10.21",
|
|
4
4
|
"description": "mpx compile core",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mpx"
|
|
@@ -28,8 +28,9 @@
|
|
|
28
28
|
"@better-scroll/slide": "^2.5.1",
|
|
29
29
|
"@better-scroll/wheel": "^2.5.1",
|
|
30
30
|
"@better-scroll/zoom": "^2.5.1",
|
|
31
|
+
"@mpxjs/perf": "^2.10.21",
|
|
31
32
|
"@mpxjs/template-engine": "^2.8.7",
|
|
32
|
-
"@mpxjs/utils": "^2.10.
|
|
33
|
+
"@mpxjs/utils": "^2.10.21",
|
|
33
34
|
"acorn": "^8.11.3",
|
|
34
35
|
"acorn-walk": "^7.2.0",
|
|
35
36
|
"async": "^2.6.0",
|
|
@@ -90,7 +91,7 @@
|
|
|
90
91
|
},
|
|
91
92
|
"devDependencies": {
|
|
92
93
|
"@d11/react-native-fast-image": "^8.6.12",
|
|
93
|
-
"@mpxjs/api-proxy": "^2.10.
|
|
94
|
+
"@mpxjs/api-proxy": "^2.10.21",
|
|
94
95
|
"@types/babel-traverse": "^6.25.4",
|
|
95
96
|
"@types/babel-types": "^7.0.4",
|
|
96
97
|
"@types/glob": "^8.1.0",
|
|
@@ -112,5 +113,5 @@
|
|
|
112
113
|
"engines": {
|
|
113
114
|
"node": ">=14.14.0"
|
|
114
115
|
},
|
|
115
|
-
"gitHead": "
|
|
116
|
+
"gitHead": "a2cbdad9f8dcc376f2098d217485525953b64cd9"
|
|
116
117
|
}
|