@wordpress/block-editor 12.16.1-next.79a6196f.0 → 12.17.0
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/CHANGELOG.md +2 -0
- package/build/components/block-lock/toolbar.js +2 -8
- package/build/components/block-lock/toolbar.js.map +1 -1
- package/build/components/global-styles/hooks.js +2 -3
- package/build/components/global-styles/hooks.js.map +1 -1
- package/build/components/global-styles/typography-panel.js +14 -31
- package/build/components/global-styles/typography-panel.js.map +1 -1
- package/build/hooks/custom-fields.js +106 -0
- package/build/hooks/custom-fields.js.map +1 -0
- package/build/hooks/index.js +2 -1
- package/build/hooks/index.js.map +1 -1
- package/build/hooks/utils.js +3 -6
- package/build/hooks/utils.js.map +1 -1
- package/build/utils/object.js +0 -17
- package/build/utils/object.js.map +1 -1
- package/build-module/components/block-lock/toolbar.js +2 -8
- package/build-module/components/block-lock/toolbar.js.map +1 -1
- package/build-module/components/global-styles/hooks.js +2 -3
- package/build-module/components/global-styles/hooks.js.map +1 -1
- package/build-module/components/global-styles/typography-panel.js +15 -32
- package/build-module/components/global-styles/typography-panel.js.map +1 -1
- package/build-module/hooks/custom-fields.js +99 -0
- package/build-module/hooks/custom-fields.js.map +1 -0
- package/build-module/hooks/index.js +2 -1
- package/build-module/hooks/index.js.map +1 -1
- package/build-module/hooks/utils.js +3 -6
- package/build-module/hooks/utils.js.map +1 -1
- package/build-module/utils/object.js +0 -16
- package/build-module/utils/object.js.map +1 -1
- package/package.json +31 -31
- package/src/components/block-lock/toolbar.js +2 -10
- package/src/components/global-styles/hooks.js +0 -2
- package/src/components/global-styles/typography-panel.js +13 -45
- package/src/hooks/custom-fields.js +115 -0
- package/src/hooks/index.js +2 -0
- package/src/hooks/utils.js +4 -16
- package/src/utils/object.js +0 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/block-editor",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.17.0",
|
|
4
4
|
"description": "Generic block editor.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -35,35 +35,35 @@
|
|
|
35
35
|
"@emotion/react": "^11.7.1",
|
|
36
36
|
"@emotion/styled": "^11.6.0",
|
|
37
37
|
"@react-spring/web": "^9.4.5",
|
|
38
|
-
"@wordpress/a11y": "^3.
|
|
39
|
-
"@wordpress/api-fetch": "^6.
|
|
40
|
-
"@wordpress/blob": "^3.
|
|
41
|
-
"@wordpress/blocks": "^12.
|
|
42
|
-
"@wordpress/commands": "^0.
|
|
43
|
-
"@wordpress/components": "^25.15.
|
|
44
|
-
"@wordpress/compose": "^6.
|
|
45
|
-
"@wordpress/data": "^9.
|
|
46
|
-
"@wordpress/date": "^4.
|
|
47
|
-
"@wordpress/deprecated": "^3.
|
|
48
|
-
"@wordpress/dom": "^3.
|
|
49
|
-
"@wordpress/element": "^5.
|
|
50
|
-
"@wordpress/escape-html": "^2.
|
|
51
|
-
"@wordpress/hooks": "^3.
|
|
52
|
-
"@wordpress/html-entities": "^3.
|
|
53
|
-
"@wordpress/i18n": "^4.
|
|
54
|
-
"@wordpress/icons": "^9.
|
|
55
|
-
"@wordpress/is-shallow-equal": "^4.
|
|
56
|
-
"@wordpress/keyboard-shortcuts": "^4.
|
|
57
|
-
"@wordpress/keycodes": "^3.
|
|
58
|
-
"@wordpress/notices": "^4.
|
|
59
|
-
"@wordpress/preferences": "^3.
|
|
60
|
-
"@wordpress/private-apis": "^0.
|
|
61
|
-
"@wordpress/rich-text": "^6.
|
|
62
|
-
"@wordpress/style-engine": "^1.
|
|
63
|
-
"@wordpress/token-list": "^2.
|
|
64
|
-
"@wordpress/url": "^3.
|
|
65
|
-
"@wordpress/warning": "^2.
|
|
66
|
-
"@wordpress/wordcount": "^3.
|
|
38
|
+
"@wordpress/a11y": "^3.49.0",
|
|
39
|
+
"@wordpress/api-fetch": "^6.46.0",
|
|
40
|
+
"@wordpress/blob": "^3.49.0",
|
|
41
|
+
"@wordpress/blocks": "^12.26.0",
|
|
42
|
+
"@wordpress/commands": "^0.20.0",
|
|
43
|
+
"@wordpress/components": "^25.15.0",
|
|
44
|
+
"@wordpress/compose": "^6.26.0",
|
|
45
|
+
"@wordpress/data": "^9.19.0",
|
|
46
|
+
"@wordpress/date": "^4.49.0",
|
|
47
|
+
"@wordpress/deprecated": "^3.49.0",
|
|
48
|
+
"@wordpress/dom": "^3.49.0",
|
|
49
|
+
"@wordpress/element": "^5.26.0",
|
|
50
|
+
"@wordpress/escape-html": "^2.49.0",
|
|
51
|
+
"@wordpress/hooks": "^3.49.0",
|
|
52
|
+
"@wordpress/html-entities": "^3.49.0",
|
|
53
|
+
"@wordpress/i18n": "^4.49.0",
|
|
54
|
+
"@wordpress/icons": "^9.40.0",
|
|
55
|
+
"@wordpress/is-shallow-equal": "^4.49.0",
|
|
56
|
+
"@wordpress/keyboard-shortcuts": "^4.26.0",
|
|
57
|
+
"@wordpress/keycodes": "^3.49.0",
|
|
58
|
+
"@wordpress/notices": "^4.17.0",
|
|
59
|
+
"@wordpress/preferences": "^3.26.0",
|
|
60
|
+
"@wordpress/private-apis": "^0.31.0",
|
|
61
|
+
"@wordpress/rich-text": "^6.26.0",
|
|
62
|
+
"@wordpress/style-engine": "^1.32.0",
|
|
63
|
+
"@wordpress/token-list": "^2.49.0",
|
|
64
|
+
"@wordpress/url": "^3.50.0",
|
|
65
|
+
"@wordpress/warning": "^2.49.0",
|
|
66
|
+
"@wordpress/wordcount": "^3.49.0",
|
|
67
67
|
"change-case": "^4.1.2",
|
|
68
68
|
"classnames": "^2.3.1",
|
|
69
69
|
"colord": "^2.7.0",
|
|
@@ -87,5 +87,5 @@
|
|
|
87
87
|
"publishConfig": {
|
|
88
88
|
"access": "public"
|
|
89
89
|
},
|
|
90
|
-
"gitHead": "
|
|
90
|
+
"gitHead": "5e6f9caa205d3bfdbac131952b7bf9c6ec60569b"
|
|
91
91
|
}
|
|
@@ -33,24 +33,16 @@ export default function BlockLockToolbar( { clientId } ) {
|
|
|
33
33
|
}
|
|
34
34
|
}, [ isLocked ] );
|
|
35
35
|
|
|
36
|
-
if ( ! isLocked && ! hasLockButtonShown.current ) {
|
|
36
|
+
if ( ! canLock || ( ! isLocked && ! hasLockButtonShown.current ) ) {
|
|
37
37
|
return null;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
let label = isLocked ? __( 'Unlock' ) : __( 'Lock' );
|
|
41
|
-
|
|
42
|
-
if ( ! canLock && isLocked ) {
|
|
43
|
-
label = __( 'Locked' );
|
|
44
|
-
}
|
|
45
|
-
|
|
46
40
|
return (
|
|
47
41
|
<>
|
|
48
42
|
<ToolbarGroup className="block-editor-block-lock-toolbar">
|
|
49
43
|
<ToolbarButton
|
|
50
|
-
accessibleWhenDisabled
|
|
51
|
-
disabled={ ! canLock }
|
|
52
44
|
icon={ isLocked ? lock : unlock }
|
|
53
|
-
label={
|
|
45
|
+
label={ isLocked ? __( 'Unlock' ) : __( 'Lock' ) }
|
|
54
46
|
onClick={ toggleModal }
|
|
55
47
|
aria-expanded={ isModalOpen }
|
|
56
48
|
aria-haspopup="dialog"
|
|
@@ -66,7 +66,6 @@ const VALID_SETTINGS = [
|
|
|
66
66
|
'spacing.units',
|
|
67
67
|
'typography.fluid',
|
|
68
68
|
'typography.customFontSize',
|
|
69
|
-
'typography.defaultFontSizes',
|
|
70
69
|
'typography.dropCap',
|
|
71
70
|
'typography.fontFamilies',
|
|
72
71
|
'typography.fontSizes',
|
|
@@ -239,7 +238,6 @@ export function useSettingsForBlockElement(
|
|
|
239
238
|
...updatedSettings.typography,
|
|
240
239
|
fontSizes: {},
|
|
241
240
|
customFontSize: false,
|
|
242
|
-
defaultFontSizes: false,
|
|
243
241
|
};
|
|
244
242
|
}
|
|
245
243
|
|
|
@@ -22,7 +22,7 @@ import TextTransformControl from '../text-transform-control';
|
|
|
22
22
|
import TextDecorationControl from '../text-decoration-control';
|
|
23
23
|
import WritingModeControl from '../writing-mode-control';
|
|
24
24
|
import { getValueFromVariable, TOOLSPANEL_DROPDOWNMENU_PROPS } from './utils';
|
|
25
|
-
import { setImmutably
|
|
25
|
+
import { setImmutably } from '../../utils/object';
|
|
26
26
|
|
|
27
27
|
const MIN_TEXT_COLUMNS = 1;
|
|
28
28
|
const MAX_TEXT_COLUMNS = 6;
|
|
@@ -53,10 +53,7 @@ export function useHasTypographyPanel( settings ) {
|
|
|
53
53
|
|
|
54
54
|
function useHasFontSizeControl( settings ) {
|
|
55
55
|
return (
|
|
56
|
-
( settings?.typography?.
|
|
57
|
-
settings?.typography?.fontSizes?.default?.length ) ||
|
|
58
|
-
settings?.typography?.fontSizes?.theme?.length ||
|
|
59
|
-
settings?.typography?.fontSizes?.custom?.length ||
|
|
56
|
+
hasMergedOrigins( settings?.typography?.fontSizes ) ||
|
|
60
57
|
settings?.typography?.customFontSize
|
|
61
58
|
);
|
|
62
59
|
}
|
|
@@ -103,45 +100,16 @@ function useHasTextColumnsControl( settings ) {
|
|
|
103
100
|
return settings?.typography?.textColumns;
|
|
104
101
|
}
|
|
105
102
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
* @param {Object} settings The global styles settings.
|
|
117
|
-
*
|
|
118
|
-
* @return {Array} The merged font sizes.
|
|
119
|
-
*/
|
|
120
|
-
function getMergedFontSizes( settings ) {
|
|
121
|
-
// The font size presets are merged in reverse order so that the duplicates
|
|
122
|
-
// that may defined later in the array have higher priority to match the CSS.
|
|
123
|
-
const mergedFontSizesAll = uniqByProperty(
|
|
124
|
-
[
|
|
125
|
-
settings?.typography?.fontSizes?.custom,
|
|
126
|
-
settings?.typography?.fontSizes?.theme,
|
|
127
|
-
settings?.typography?.fontSizes?.default,
|
|
128
|
-
].flatMap( ( presets ) => presets?.toReversed() ?? [] ),
|
|
129
|
-
'slug'
|
|
130
|
-
).reverse();
|
|
131
|
-
|
|
132
|
-
// Default presets exist in the global styles CSS no matter the setting, so
|
|
133
|
-
// filtering them out in the UI has to be done after merging.
|
|
134
|
-
const mergedFontSizes =
|
|
135
|
-
settings?.typography?.defaultFontSizes === false
|
|
136
|
-
? mergedFontSizesAll.filter(
|
|
137
|
-
( { slug } ) =>
|
|
138
|
-
! [ 'small', 'medium', 'large', 'x-large' ].includes(
|
|
139
|
-
slug
|
|
140
|
-
)
|
|
141
|
-
)
|
|
142
|
-
: mergedFontSizesAll;
|
|
143
|
-
|
|
144
|
-
return mergedFontSizes;
|
|
103
|
+
function getUniqueFontSizesBySlug( settings ) {
|
|
104
|
+
const fontSizes = settings?.typography?.fontSizes;
|
|
105
|
+
const mergedFontSizes = fontSizes ? mergeOrigins( fontSizes ) : [];
|
|
106
|
+
const uniqueSizes = [];
|
|
107
|
+
for ( const currentSize of mergedFontSizes ) {
|
|
108
|
+
if ( ! uniqueSizes.some( ( { slug } ) => slug === currentSize.slug ) ) {
|
|
109
|
+
uniqueSizes.push( currentSize );
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return uniqueSizes;
|
|
145
113
|
}
|
|
146
114
|
|
|
147
115
|
function TypographyToolsPanel( {
|
|
@@ -217,7 +185,7 @@ export default function TypographyPanel( {
|
|
|
217
185
|
// Font Size
|
|
218
186
|
const hasFontSizeEnabled = useHasFontSizeControl( settings );
|
|
219
187
|
const disableCustomFontSizes = ! settings?.typography?.customFontSize;
|
|
220
|
-
const mergedFontSizes =
|
|
188
|
+
const mergedFontSizes = getUniqueFontSizesBySlug( settings );
|
|
221
189
|
|
|
222
190
|
const fontSize = decodeValue( inheritedValue?.typography?.fontSize );
|
|
223
191
|
const setFontSize = ( newValue, metadata ) => {
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { addFilter } from '@wordpress/hooks';
|
|
5
|
+
import { PanelBody, TextControl } from '@wordpress/components';
|
|
6
|
+
import { __, sprintf } from '@wordpress/i18n';
|
|
7
|
+
import { hasBlockSupport } from '@wordpress/blocks';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Internal dependencies
|
|
11
|
+
*/
|
|
12
|
+
import { InspectorControls } from '../components';
|
|
13
|
+
import { useBlockEditingMode } from '../components/block-editing-mode';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Filters registered block settings, extending attributes to include `connections`.
|
|
17
|
+
*
|
|
18
|
+
* @param {Object} settings Original block settings.
|
|
19
|
+
*
|
|
20
|
+
* @return {Object} Filtered block settings.
|
|
21
|
+
*/
|
|
22
|
+
function addAttribute( settings ) {
|
|
23
|
+
if ( hasBlockSupport( settings, '__experimentalConnections', true ) ) {
|
|
24
|
+
// Gracefully handle if settings.attributes.connections is undefined.
|
|
25
|
+
settings.attributes = {
|
|
26
|
+
...settings.attributes,
|
|
27
|
+
connections: {
|
|
28
|
+
type: 'object',
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return settings;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function CustomFieldsControlPure( { name, connections, setAttributes } ) {
|
|
37
|
+
const blockEditingMode = useBlockEditingMode();
|
|
38
|
+
if ( blockEditingMode !== 'default' ) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// If the block is a paragraph or image block, we need to know which
|
|
43
|
+
// attribute to use for the connection. Only the `content` attribute
|
|
44
|
+
// of the paragraph block and the `url` attribute of the image block are supported.
|
|
45
|
+
let attributeName;
|
|
46
|
+
if ( name === 'core/paragraph' ) attributeName = 'content';
|
|
47
|
+
if ( name === 'core/image' ) attributeName = 'url';
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<InspectorControls>
|
|
51
|
+
<PanelBody title={ __( 'Connections' ) } initialOpen={ true }>
|
|
52
|
+
<TextControl
|
|
53
|
+
__nextHasNoMarginBottom
|
|
54
|
+
autoComplete="off"
|
|
55
|
+
label={ __( 'Custom field meta_key' ) }
|
|
56
|
+
value={
|
|
57
|
+
connections?.attributes?.[ attributeName ]?.value || ''
|
|
58
|
+
}
|
|
59
|
+
onChange={ ( nextValue ) => {
|
|
60
|
+
if ( nextValue === '' ) {
|
|
61
|
+
setAttributes( {
|
|
62
|
+
connections: undefined,
|
|
63
|
+
[ attributeName ]: undefined,
|
|
64
|
+
placeholder: undefined,
|
|
65
|
+
} );
|
|
66
|
+
} else {
|
|
67
|
+
setAttributes( {
|
|
68
|
+
connections: {
|
|
69
|
+
attributes: {
|
|
70
|
+
// The attributeName will be either `content` or `url`.
|
|
71
|
+
[ attributeName ]: {
|
|
72
|
+
// Source will be variable, could be post_meta, user_meta, term_meta, etc.
|
|
73
|
+
// Could even be a custom source like a social media attribute.
|
|
74
|
+
source: 'meta_fields',
|
|
75
|
+
value: nextValue,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
[ attributeName ]: undefined,
|
|
80
|
+
placeholder: sprintf(
|
|
81
|
+
'This content will be replaced on the frontend by the value of "%s" custom field.',
|
|
82
|
+
nextValue
|
|
83
|
+
),
|
|
84
|
+
} );
|
|
85
|
+
}
|
|
86
|
+
} }
|
|
87
|
+
/>
|
|
88
|
+
</PanelBody>
|
|
89
|
+
</InspectorControls>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export default {
|
|
94
|
+
edit: CustomFieldsControlPure,
|
|
95
|
+
attributeKeys: [ 'connections' ],
|
|
96
|
+
hasSupport( name ) {
|
|
97
|
+
return (
|
|
98
|
+
hasBlockSupport( name, '__experimentalConnections', false ) &&
|
|
99
|
+
// Check if the current block is a paragraph or image block.
|
|
100
|
+
// Currently, only these two blocks are supported.
|
|
101
|
+
[ 'core/paragraph', 'core/image' ].includes( name )
|
|
102
|
+
);
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
if (
|
|
107
|
+
window.__experimentalConnections ||
|
|
108
|
+
window.__experimentalPatternPartialSyncing
|
|
109
|
+
) {
|
|
110
|
+
addFilter(
|
|
111
|
+
'blocks.registerBlockType',
|
|
112
|
+
'core/editor/connections/attribute',
|
|
113
|
+
addAttribute
|
|
114
|
+
);
|
|
115
|
+
}
|
package/src/hooks/index.js
CHANGED
|
@@ -25,6 +25,7 @@ import layout from './layout';
|
|
|
25
25
|
import childLayout from './layout-child';
|
|
26
26
|
import contentLockUI from './content-lock-ui';
|
|
27
27
|
import './metadata';
|
|
28
|
+
import customFields from './custom-fields';
|
|
28
29
|
import blockHooks from './block-hooks';
|
|
29
30
|
import blockRenaming from './block-renaming';
|
|
30
31
|
|
|
@@ -38,6 +39,7 @@ createBlockEditFilter(
|
|
|
38
39
|
position,
|
|
39
40
|
layout,
|
|
40
41
|
contentLockUI,
|
|
42
|
+
window.__experimentalConnections ? customFields : null,
|
|
41
43
|
blockHooks,
|
|
42
44
|
blockRenaming,
|
|
43
45
|
].filter( Boolean )
|
package/src/hooks/utils.js
CHANGED
|
@@ -177,10 +177,7 @@ export function useBlockSettings( name, parentLayout ) {
|
|
|
177
177
|
backgroundImage,
|
|
178
178
|
backgroundSize,
|
|
179
179
|
fontFamilies,
|
|
180
|
-
|
|
181
|
-
themeFontSizes,
|
|
182
|
-
defaultFontSizes,
|
|
183
|
-
defaultFontSizesEnabled,
|
|
180
|
+
fontSizes,
|
|
184
181
|
customFontSize,
|
|
185
182
|
fontStyle,
|
|
186
183
|
fontWeight,
|
|
@@ -225,10 +222,7 @@ export function useBlockSettings( name, parentLayout ) {
|
|
|
225
222
|
'background.backgroundImage',
|
|
226
223
|
'background.backgroundSize',
|
|
227
224
|
'typography.fontFamilies',
|
|
228
|
-
'typography.fontSizes
|
|
229
|
-
'typography.fontSizes.theme',
|
|
230
|
-
'typography.fontSizes.default',
|
|
231
|
-
'typography.defaultFontSizes',
|
|
225
|
+
'typography.fontSizes',
|
|
232
226
|
'typography.customFontSize',
|
|
233
227
|
'typography.fontStyle',
|
|
234
228
|
'typography.fontWeight',
|
|
@@ -310,12 +304,9 @@ export function useBlockSettings( name, parentLayout ) {
|
|
|
310
304
|
custom: fontFamilies,
|
|
311
305
|
},
|
|
312
306
|
fontSizes: {
|
|
313
|
-
custom:
|
|
314
|
-
theme: themeFontSizes,
|
|
315
|
-
default: defaultFontSizes,
|
|
307
|
+
custom: fontSizes,
|
|
316
308
|
},
|
|
317
309
|
customFontSize,
|
|
318
|
-
defaultFontSizes: defaultFontSizesEnabled,
|
|
319
310
|
fontStyle,
|
|
320
311
|
fontWeight,
|
|
321
312
|
lineHeight,
|
|
@@ -350,10 +341,7 @@ export function useBlockSettings( name, parentLayout ) {
|
|
|
350
341
|
backgroundImage,
|
|
351
342
|
backgroundSize,
|
|
352
343
|
fontFamilies,
|
|
353
|
-
|
|
354
|
-
themeFontSizes,
|
|
355
|
-
defaultFontSizes,
|
|
356
|
-
defaultFontSizesEnabled,
|
|
344
|
+
fontSizes,
|
|
357
345
|
customFontSize,
|
|
358
346
|
fontStyle,
|
|
359
347
|
fontWeight,
|
package/src/utils/object.js
CHANGED
|
@@ -49,19 +49,3 @@ export const getValueFromObjectPath = ( object, path, defaultValue ) => {
|
|
|
49
49
|
} );
|
|
50
50
|
return value ?? defaultValue;
|
|
51
51
|
};
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Helper util to filter out objects with duplicate values for a given property.
|
|
55
|
-
*
|
|
56
|
-
* @param {Object[]} array Array of objects to filter.
|
|
57
|
-
* @param {string} property Property to filter unique values by.
|
|
58
|
-
*
|
|
59
|
-
* @return {Object[]} Array of objects with unique values for the specified property.
|
|
60
|
-
*/
|
|
61
|
-
export function uniqByProperty( array, property ) {
|
|
62
|
-
const seen = new Set();
|
|
63
|
-
return array.filter( ( item ) => {
|
|
64
|
-
const value = item[ property ];
|
|
65
|
-
return seen.has( value ) ? false : seen.add( value );
|
|
66
|
-
} );
|
|
67
|
-
}
|