@adaptabletools/adaptable 18.1.8 → 18.1.10
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/package.json +1 -1
- package/src/AdaptableInterfaces/IAdaptable.d.ts +3 -0
- package/src/AdaptableOptions/ContainerOptions.d.ts +7 -7
- package/src/AdaptableOptions/DataChangeHistoryOptions.d.ts +5 -0
- package/src/Api/DataChangeHistoryApi.d.ts +6 -0
- package/src/Api/GridApi.d.ts +2 -0
- package/src/Api/Implementation/DataChangeHistoryApiImpl.d.ts +2 -0
- package/src/Api/Implementation/DataChangeHistoryApiImpl.js +24 -3
- package/src/Api/Implementation/GridApiImpl.d.ts +2 -1
- package/src/Api/Implementation/GridApiImpl.js +3 -0
- package/src/Api/Internal/AdaptableInternalApi.d.ts +2 -0
- package/src/Api/Internal/AdaptableInternalApi.js +4 -0
- package/src/Api/Internal/GridInternalApi.js +12 -6
- package/src/PredefinedConfig/Common/AdaptableFormat.d.ts +9 -9
- package/src/Redux/ActionsReducers/SystemRedux.d.ts +9 -8
- package/src/Redux/ActionsReducers/SystemRedux.js +11 -11
- package/src/Strategy/DataChangeHistoryModule.js +1 -2
- package/src/Utilities/Constants/DocumentationLinkConstants.d.ts +1 -0
- package/src/Utilities/Constants/DocumentationLinkConstants.js +1 -0
- package/src/Utilities/Helpers/FormatContentHelper.d.ts +22 -0
- package/src/Utilities/Helpers/FormatContentHelper.js +34 -0
- package/src/Utilities/Helpers/FormatHelper.d.ts +0 -18
- package/src/Utilities/Helpers/FormatHelper.js +2 -34
- package/src/View/Alert/Wizard/AlertMessageWizardSection.js +4 -3
- package/src/View/Components/ExternalRenderer.js +3 -1
- package/src/View/Dashboard/CustomToolbar.js +3 -1
- package/src/View/FormatColumn/Wizard/FormatColumnFormatWizardSection.js +32 -13
- package/src/agGrid/AdaptableAgGrid.d.ts +3 -0
- package/src/agGrid/AdaptableAgGrid.js +35 -2
- package/src/agGrid/AgGridMenuAdapter.js +15 -1
- package/src/agGrid/defaultAdaptableOptions.js +1 -0
- package/src/env.js +2 -2
- package/src/metamodel/adaptable.metamodel.js +1 -1
- package/tsconfig.esm.tsbuildinfo +1 -1
|
@@ -63,6 +63,8 @@ export const CustomToolbarCmp = (props) => {
|
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
65
|
}, []);
|
|
66
|
+
const CustomReactFrameworkComponent = props.customToolbar
|
|
67
|
+
.frameworkComponent;
|
|
66
68
|
return (React.createElement(React.Fragment, null,
|
|
67
69
|
props.customToolbar.render && (React.createElement("div", { id: renderContentContainerId, ref: renderContentContainerRef, className: `ab-CustomToolbar__rendered-content ab-CustomToolbar--${props.customToolbar.name}`, style: { minHeight: 22 }, dangerouslySetInnerHTML: { __html: renderedContentHTML } })),
|
|
68
70
|
props.customToolbar.toolbarButtons && (React.createElement("div", { id: buttonsContainerId, className: `ab-CustomToolbar__buttons ab-CustomToolbar--${props.customToolbar.name}`, style: { minHeight: 22 } }, props.customToolbar.toolbarButtons.map((button, index) => {
|
|
@@ -91,7 +93,7 @@ export const CustomToolbarCmp = (props) => {
|
|
|
91
93
|
}, 16);
|
|
92
94
|
} }, buttonLabel));
|
|
93
95
|
}))),
|
|
94
|
-
|
|
96
|
+
CustomReactFrameworkComponent && (React.createElement("div", { id: componentContainerId, ref: componentContainerRef, style: { minHeight: 22 }, className: `ab-CustomToolbar__component ab-CustomToolbar--${props.customToolbar.name}` }, api.gridApi.getVariant() === 'react' ? (React.createElement(CustomReactFrameworkComponent, { adaptableApi: api })) : null))));
|
|
95
97
|
};
|
|
96
98
|
export const CustomToolbarWrapper = (props) => {
|
|
97
99
|
const { api } = useAdaptable();
|
|
@@ -18,6 +18,8 @@ import FormatHelper from '../../../Utilities/Helpers/FormatHelper';
|
|
|
18
18
|
import { Toggle, ToggleGroup } from '../../../components/Toggle';
|
|
19
19
|
import { DEFAULT_DOUBLE_DISPLAY_VALUE, DEFAULT_STRING_DISPLAY_VALUE, } from '../../../Utilities/Constants/GeneralConstants';
|
|
20
20
|
import Textarea from '../../../components/Textarea';
|
|
21
|
+
import { ButtonInfo } from '../../Components/Buttons/ButtonInfo';
|
|
22
|
+
import { FormatColumnPlaceholderDocsLink } from '../../../Utilities/Constants/DocumentationLinkConstants';
|
|
21
23
|
const DOLLAR_OPTIONS = {
|
|
22
24
|
FractionDigits: 2,
|
|
23
25
|
FractionSeparator: '.',
|
|
@@ -202,8 +204,8 @@ const renderDateFormat = (data, _onChange, setFormatOption, scopedCustomFormatte
|
|
|
202
204
|
},
|
|
203
205
|
] })))))));
|
|
204
206
|
};
|
|
205
|
-
const renderNumberFormat = (data, onChange, setFormatOption, scopedCustomFormatters,
|
|
206
|
-
var _a, _b, _c, _d, _e;
|
|
207
|
+
const renderNumberFormat = (data, onChange, setFormatOption, scopedCustomFormatters, api) => {
|
|
208
|
+
var _a, _b, _c, _d, _e, _f;
|
|
207
209
|
if (data.DisplayFormat.Formatter !== 'NumberFormatter') {
|
|
208
210
|
return null;
|
|
209
211
|
}
|
|
@@ -255,6 +257,7 @@ const renderNumberFormat = (data, onChange, setFormatOption, scopedCustomFormatt
|
|
|
255
257
|
data.DisplayFormat.Options.Multiplier === MILLION_OPTIONS.Multiplier; //isEqual(data.DisplayFormat.Options, MILLION_OPTIONS);
|
|
256
258
|
const IS_DOLLAR = data.DisplayFormat.Options.Prefix === '$'; //isEqual(data.DisplayFormat.Options, DOLLAR_OPTIONS);
|
|
257
259
|
const IS_STERLING = data.DisplayFormat.Options.Prefix === '£'; //isEqual(data.DisplayFormat, STERLING_OPTIONS);
|
|
260
|
+
const showDocumentationLinks = api.internalApi.isDocumentationLinksDisplayed();
|
|
258
261
|
return (React.createElement(Box, { "data-name": 'format-column-display-format', padding: 2 },
|
|
259
262
|
React.createElement(Tabs, null,
|
|
260
263
|
React.createElement(Tabs.Tab, null, "Format"),
|
|
@@ -262,7 +265,8 @@ const renderNumberFormat = (data, onChange, setFormatOption, scopedCustomFormatt
|
|
|
262
265
|
React.createElement(Flex, { flexDirection: "row" },
|
|
263
266
|
React.createElement(FormLayout, { mr: 3 },
|
|
264
267
|
React.createElement(FormRow, { label: "Fraction Separator" },
|
|
265
|
-
React.createElement(Input, { "data-name": "fraction-separator", value: (_a = data.DisplayFormat.Options.FractionSeparator) !== null && _a !== void 0 ? _a : '', onChange: (e) => setFormatOption('FractionSeparator', e.currentTarget.value) })
|
|
268
|
+
React.createElement(Input, { "data-name": "fraction-separator", value: (_a = data.DisplayFormat.Options.FractionSeparator) !== null && _a !== void 0 ? _a : '', onChange: (e) => setFormatOption('FractionSeparator', e.currentTarget.value) }),
|
|
269
|
+
' '),
|
|
266
270
|
React.createElement(FormRow, { label: "Integer Separator" },
|
|
267
271
|
React.createElement(Input, { "data-name": "integer-separator", value: (_b = data.DisplayFormat.Options.IntegerSeparator) !== null && _b !== void 0 ? _b : '', onChange: (e) => setFormatOption('IntegerSeparator', e.currentTarget.value) })),
|
|
268
272
|
React.createElement(FormRow, { label: "Prefix" },
|
|
@@ -292,9 +296,6 @@ const renderNumberFormat = (data, onChange, setFormatOption, scopedCustomFormatt
|
|
|
292
296
|
React.createElement(FormRow, { label: "Multiplier" },
|
|
293
297
|
React.createElement(Input, { "data-name": "multiplier", type: "number", value: data.DisplayFormat.Options.Multiplier, onChange: (e) => setFormatOption('Multiplier', Number(e.currentTarget.value)) })),
|
|
294
298
|
' ',
|
|
295
|
-
React.createElement(FormRow, { label: "Content" },
|
|
296
|
-
React.createElement(Input, { "data-name": "content", value: (_e = data.DisplayFormat.Options.Content) !== null && _e !== void 0 ? _e : '', onChange: (e) => setFormatOption('Content', e.currentTarget.value) })),
|
|
297
|
-
' ',
|
|
298
299
|
React.createElement(FormRow, { label: "Parentheses" },
|
|
299
300
|
React.createElement(CheckBox, { "data-name": "parentheses-checkbox", checked: data.DisplayFormat.Options.Parentheses, onChange: (checked) => setFormatOption('Parentheses', checked) })),
|
|
300
301
|
React.createElement(FormRow, { label: "Floor" },
|
|
@@ -318,6 +319,20 @@ const renderNumberFormat = (data, onChange, setFormatOption, scopedCustomFormatt
|
|
|
318
319
|
React.createElement(Radio, { "data-name": "preset-million", marginLeft: 3, checked: IS_MILLION, onChange: () => setDivideMillionPreset() }, "M (Million)"),
|
|
319
320
|
React.createElement(Radio, { "data-name": "preset-dollar", marginLeft: 3, checked: IS_DOLLAR, onChange: () => setDollarPreset() }, "Dollar"),
|
|
320
321
|
React.createElement(Radio, { "data-name": "preset-sterling", marginLeft: 3, checked: IS_STERLING, onChange: () => setSterlingPreset() }, "Sterling")))))),
|
|
322
|
+
React.createElement(Tabs, { marginTop: 2, autoFocus: false, keyboardNavigation: false },
|
|
323
|
+
React.createElement(Tabs.Tab, null, "Dynamic Content"),
|
|
324
|
+
React.createElement(Tabs.Content, null,
|
|
325
|
+
React.createElement(Text, { padding: 2, fontSize: 2 }, "Provide dynamic content through the use of Placeholders"),
|
|
326
|
+
React.createElement(FormLayout, { margin: 2 },
|
|
327
|
+
React.createElement(FormRow, { label: "" },
|
|
328
|
+
React.createElement(Textarea, { minWidth: 300, rows: 3, placeholder: "", marginTop: 2, type: 'text', autoFocus: false, value: (_f = (_e = data.DisplayFormat.Options.Content) === null || _e === void 0 ? void 0 : _e.toString()) !== null && _f !== void 0 ? _f : '', onChange: (e) => setFormatOption('Content', e.currentTarget.value) }),
|
|
329
|
+
showDocumentationLinks && (React.createElement(HelpBlock, { "data-name": "query-documentation", mt: 3, mb: 2, style: {
|
|
330
|
+
fontSize: 'var(--ab-font-size-3)',
|
|
331
|
+
padding: 0,
|
|
332
|
+
} },
|
|
333
|
+
React.createElement(ButtonInfo, { mr: 2, onClick: () => window.open(FormatColumnPlaceholderDocsLink, '_blank') }),
|
|
334
|
+
"Learn more about using placeholders"))),
|
|
335
|
+
' '))),
|
|
321
336
|
React.createElement(Tabs, { marginTop: 2, autoFocus: false, keyboardNavigation: false },
|
|
322
337
|
React.createElement(Tabs.Tab, null, "Examples"),
|
|
323
338
|
React.createElement(Tabs.Content, null,
|
|
@@ -347,11 +362,12 @@ const renderNumberFormat = (data, onChange, setFormatOption, scopedCustomFormatt
|
|
|
347
362
|
},
|
|
348
363
|
] })))));
|
|
349
364
|
};
|
|
350
|
-
const renderStringFormat = (data, _onChange, setFormatOption, scopedCustomFormatters,
|
|
365
|
+
const renderStringFormat = (data, _onChange, setFormatOption, scopedCustomFormatters, api) => {
|
|
351
366
|
var _a, _b, _c;
|
|
352
367
|
if (data.DisplayFormat.Formatter !== 'StringFormatter') {
|
|
353
368
|
return null;
|
|
354
369
|
}
|
|
370
|
+
const showDocumentationLinks = api.internalApi.isDocumentationLinksDisplayed();
|
|
355
371
|
return (React.createElement(Box, { "data-name": 'format-column-display-format', padding: 2 },
|
|
356
372
|
React.createElement(Tabs, null,
|
|
357
373
|
React.createElement(Tabs.Tab, null, "Format"),
|
|
@@ -370,10 +386,13 @@ const renderStringFormat = (data, _onChange, setFormatOption, scopedCustomFormat
|
|
|
370
386
|
React.createElement(FormRow, { label: "Suffix" },
|
|
371
387
|
React.createElement(Input, { "data-name": "suffix", value: (_b = data.DisplayFormat.Options.Suffix) !== null && _b !== void 0 ? _b : '', onChange: (e) => setFormatOption('Suffix', e.currentTarget.value) })),
|
|
372
388
|
React.createElement(FormRow, { label: "Content" },
|
|
373
|
-
React.createElement(Textarea, { minWidth: 300, rows: 3, placeholder: "
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
389
|
+
React.createElement(Textarea, { minWidth: 300, rows: 3, placeholder: "", marginTop: 2, type: 'text', autoFocus: false, value: (_c = data.DisplayFormat.Options.Content) !== null && _c !== void 0 ? _c : '', onChange: (e) => setFormatOption('Content', e.currentTarget.value) }),
|
|
390
|
+
showDocumentationLinks && (React.createElement(HelpBlock, { "data-name": "query-documentation", mt: 3, mb: 2, style: {
|
|
391
|
+
fontSize: 'var(--ab-font-size-3)',
|
|
392
|
+
padding: 0,
|
|
393
|
+
} },
|
|
394
|
+
React.createElement(ButtonInfo, { mr: 2, onClick: () => window.open(FormatColumnPlaceholderDocsLink, '_blank') }),
|
|
395
|
+
"See how to create dynamic Display Format using placeholders"))),
|
|
377
396
|
React.createElement(FormRow, { label: "Empty" },
|
|
378
397
|
React.createElement(CheckBox, { "data-name": "empty-checkbox", checked: data.DisplayFormat.Options.Empty, onChange: (checked) => setFormatOption('Empty', checked) })))))),
|
|
379
398
|
scopedCustomFormatters.length > 0 && (React.createElement(Tabs, { marginTop: 2, keyboardNavigation: false },
|
|
@@ -416,13 +435,13 @@ export const FormatColumnFormatWizardSection = (props) => {
|
|
|
416
435
|
const Type = data.DisplayFormat && data.DisplayFormat.Formatter;
|
|
417
436
|
const customScopedFormatters = customDisplayFormatters.filter((displayFormatter) => adaptable.api.columnScopeApi.isScopeInScope(data.Scope, displayFormatter.scope));
|
|
418
437
|
if (Type === 'NumberFormatter') {
|
|
419
|
-
return renderNumberFormat(data, update, setFormatOption, customScopedFormatters,
|
|
438
|
+
return renderNumberFormat(data, update, setFormatOption, customScopedFormatters, adaptable.api);
|
|
420
439
|
}
|
|
421
440
|
if (Type === 'DateFormatter') {
|
|
422
441
|
return renderDateFormat(data, update, setFormatOption, customScopedFormatters);
|
|
423
442
|
}
|
|
424
443
|
if (Type === 'StringFormatter') {
|
|
425
|
-
return renderStringFormat(data, update, setFormatOption, customScopedFormatters,
|
|
444
|
+
return renderStringFormat(data, update, setFormatOption, customScopedFormatters, adaptable.api);
|
|
426
445
|
}
|
|
427
446
|
return (React.createElement(HelpBlock, { margin: 3 },
|
|
428
447
|
"Setting a Display Format is only possible if ",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
1
2
|
import { AdaptableOptions } from '../AdaptableOptions/AdaptableOptions';
|
|
2
3
|
import { ChartRef, Column, GridApi, GridOptions, IRowNode, Module, RowModelType } from '@ag-grid-community/core';
|
|
3
4
|
import { AdaptableLogger } from './AdaptableLogger';
|
|
@@ -122,6 +123,7 @@ export declare class AdaptableAgGrid implements IAdaptable {
|
|
|
122
123
|
* Temporary, these are MIGRATION technical debts, and should be removed as soon as possible
|
|
123
124
|
*/
|
|
124
125
|
private adaptableStatusPanelKeys;
|
|
126
|
+
_PRIVATE_adaptableJSXElement: JSX.Element;
|
|
125
127
|
constructor();
|
|
126
128
|
static forEachAdaptable(fn: (adaptable: AdaptableAgGrid) => void): void;
|
|
127
129
|
private static collectInstance;
|
|
@@ -244,6 +246,7 @@ export declare class AdaptableAgGrid implements IAdaptable {
|
|
|
244
246
|
private addDistinctColumnValue;
|
|
245
247
|
private getUniqueGridCells;
|
|
246
248
|
getGridCellsForColumn(columnId: string, onlyVisibleRows?: boolean): GridCell[] | undefined;
|
|
249
|
+
getGridCellsForColumnTemp(columnId: string, onlyVisibleRows: boolean): GridCell[] | undefined;
|
|
247
250
|
getRowNodesForPrimaryKeys(primaryKeyValues: any[]): any[];
|
|
248
251
|
getRowNodeByIndex(index: number): IRowNode;
|
|
249
252
|
getAgGridStatusPanels(): import("@ag-grid-community/core").StatusPanelDef[];
|
|
@@ -397,7 +397,19 @@ export class AdaptableAgGrid {
|
|
|
397
397
|
const adaptableContainerElem = this.getAdaptableContainerElement();
|
|
398
398
|
if (adaptableContainerElem != null) {
|
|
399
399
|
adaptableContainerElem.innerHTML = '';
|
|
400
|
-
|
|
400
|
+
if (this.variant === 'react') {
|
|
401
|
+
/**
|
|
402
|
+
* #no_additional_react_root
|
|
403
|
+
* This is only used for the React variant
|
|
404
|
+
* Where we don't want to create a new React render tree here
|
|
405
|
+
* by rendering it as a React root, but instead we want to
|
|
406
|
+
* render it as is in the React tree of our AdaptableReact component
|
|
407
|
+
*/
|
|
408
|
+
this._PRIVATE_adaptableJSXElement = AdaptableApp({ Adaptable: this });
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
this.unmountReactRoot = this.renderReactRoot(AdaptableApp({ Adaptable: this }), adaptableContainerElem);
|
|
412
|
+
}
|
|
401
413
|
}
|
|
402
414
|
this.lifecycleState = 'ready';
|
|
403
415
|
this.forPlugins((plugin) => plugin.onAdaptableReady(this, this.adaptableOptions));
|
|
@@ -2379,6 +2391,27 @@ export class AdaptableAgGrid {
|
|
|
2379
2391
|
}
|
|
2380
2392
|
return returnValues;
|
|
2381
2393
|
}
|
|
2394
|
+
// This horrible method is temporary until we can get rid of having predicates inside values which is coming soon
|
|
2395
|
+
// We need it in case Blanks is requested
|
|
2396
|
+
// once we go to the new multi predicate screen then we wont show blanks any more - which we should never have done
|
|
2397
|
+
getGridCellsForColumnTemp(columnId, onlyVisibleRows) {
|
|
2398
|
+
let returnValues = [];
|
|
2399
|
+
const handler = (rowNode) => {
|
|
2400
|
+
if (!this.isGroupRowNode(rowNode)) {
|
|
2401
|
+
const gridCell = this.getGridCellFromRowNode(rowNode, columnId);
|
|
2402
|
+
if (gridCell) {
|
|
2403
|
+
returnValues.push(gridCell);
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
};
|
|
2407
|
+
if (onlyVisibleRows) {
|
|
2408
|
+
this.agGridAdapter.getAgGridApi().forEachNodeAfterFilter(handler);
|
|
2409
|
+
}
|
|
2410
|
+
else {
|
|
2411
|
+
this.agGridAdapter.getAgGridApi().forEachNode(handler);
|
|
2412
|
+
}
|
|
2413
|
+
return returnValues;
|
|
2414
|
+
}
|
|
2382
2415
|
getRowNodesForPrimaryKeys(primaryKeyValues) {
|
|
2383
2416
|
let rowNodes = [];
|
|
2384
2417
|
if (this.useRowNodeLookUp) {
|
|
@@ -3751,7 +3784,7 @@ export class AdaptableAgGrid {
|
|
|
3751
3784
|
// same grid column state as a previous,
|
|
3752
3785
|
// so no need to update, as the layout has already been updated
|
|
3753
3786
|
// for this grid column state
|
|
3754
|
-
console.log('same state as before');
|
|
3787
|
+
// console.log('same state as before');
|
|
3755
3788
|
return;
|
|
3756
3789
|
}
|
|
3757
3790
|
this.previousAgGridLayoutState = stringifiedLayoutState;
|
|
@@ -470,6 +470,20 @@ export class AgGridMenuAdapter {
|
|
|
470
470
|
...gridInfoMenuItems,
|
|
471
471
|
],
|
|
472
472
|
};
|
|
473
|
+
/*
|
|
474
|
+
const calculatedColumnMenuItem: AdaptableMenuItem = {
|
|
475
|
+
name: 'calculated-column-group',
|
|
476
|
+
label: 'Calculated Column',
|
|
477
|
+
module: 'CalculatedColumn',
|
|
478
|
+
isVisible: true,
|
|
479
|
+
icon: {
|
|
480
|
+
name: 'columns',
|
|
481
|
+
},
|
|
482
|
+
subItems: [
|
|
483
|
+
...calculatedColumnMenuItems,
|
|
484
|
+
],
|
|
485
|
+
};
|
|
486
|
+
*/
|
|
473
487
|
const columnMenuItem = {
|
|
474
488
|
name: 'column-group',
|
|
475
489
|
label: 'Column',
|
|
@@ -480,7 +494,6 @@ export class AgGridMenuAdapter {
|
|
|
480
494
|
},
|
|
481
495
|
subItems: [
|
|
482
496
|
...columnActionGroup,
|
|
483
|
-
...calculatedColumnMenuItems,
|
|
484
497
|
...freeTextColumnMenuItems,
|
|
485
498
|
...customSortMenuItems,
|
|
486
499
|
...plusMinusMenuItems,
|
|
@@ -499,6 +512,7 @@ export class AgGridMenuAdapter {
|
|
|
499
512
|
subItems: [...formatColumnMenuItems, ...styledColumnMenuItems, ...flashingCellMenuItems],
|
|
500
513
|
};
|
|
501
514
|
return this.removeConsecutiveSeparators([
|
|
515
|
+
...calculatedColumnMenuItems,
|
|
502
516
|
...settingsPanelMenuItems,
|
|
503
517
|
...dashboardMenuItems,
|
|
504
518
|
...columnFilterGroup,
|
package/src/env.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
INFINITE_TABLE_LICENSE_KEY: "StartDate=2021-06-29|EndDate=2030-01-01|Owner=Adaptable|Type=distribution|TS=1624971462479|C=137829811,1004007071,2756196225,1839832928,3994409405,636616862" || '',
|
|
3
|
-
PUBLISH_TIMESTAMP:
|
|
4
|
-
VERSION: "18.1.
|
|
3
|
+
PUBLISH_TIMESTAMP: 1721302170891 || Date.now(),
|
|
4
|
+
VERSION: "18.1.10" || '--current-version--',
|
|
5
5
|
};
|