@flowgram.ai/renderer 0.5.0 → 0.5.2
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/dist/esm/index.js +46 -28
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +23 -10
- package/dist/index.d.ts +23 -10
- package/dist/index.js +46 -28
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as _flowgram_ai_utils from '@flowgram.ai/utils';
|
|
2
|
-
import { Rectangle, Disposable, CacheOriginItem, ScrollSchema } from '@flowgram.ai/utils';
|
|
3
|
-
import { LABEL_SIDE_TYPE, FlowNodeTransitionData, FlowNodeEntity, FlowNodeTransformData, FlowDocument, FlowDocumentTransformerEntity, FlowNodeRenderData, FlowDragService, FlowRendererStateEntity } from '@flowgram.ai/document';
|
|
2
|
+
import { Rectangle, Disposable, CacheOriginItem, Xor, ScrollSchema } from '@flowgram.ai/utils';
|
|
3
|
+
import { LABEL_SIDE_TYPE, FlowNodeTransitionData, FlowNodeEntity, FlowNodeTransformData, FlowDocument, FlowDocumentTransformerEntity, FlowNodeRenderData, FlowDragService, FlowRendererStateEntity, FlowNodeJSON } from '@flowgram.ai/document';
|
|
4
4
|
import { ConfigEntity, EntityOpts, PlaygroundDragEvent, PositionSchema, SizeSchema, Layer, PipelineRegistry, LayerRegistry, PlaygroundConfigEntity, PlaygroundDrag, EditorStateConfigEntity, LayerOptions, ContextMenuService, SelectionService, PlaygroundConfig, CommandRegistry } from '@flowgram.ai/core';
|
|
5
5
|
import React from 'react';
|
|
6
6
|
import { throttle } from 'lodash-es';
|
|
@@ -455,23 +455,35 @@ declare class FlowScrollBarLayer extends Layer<ScrollBarOptions> {
|
|
|
455
455
|
* SPDX-License-Identifier: MIT
|
|
456
456
|
*/
|
|
457
457
|
|
|
458
|
+
type StartDragProps = {
|
|
459
|
+
dragEntities?: FlowNodeEntity[];
|
|
460
|
+
} & Xor<{
|
|
461
|
+
dragStartEntity: FlowNodeEntity;
|
|
462
|
+
}, {
|
|
463
|
+
dragJSON: FlowNodeJSON;
|
|
464
|
+
isBranch?: boolean;
|
|
465
|
+
onCreateNode: (json: FlowNodeJSON, dropEntity: FlowNodeEntity) => Promise<FlowNodeEntity>;
|
|
466
|
+
}>;
|
|
458
467
|
interface FlowDragOptions {
|
|
459
468
|
onDrop?: (opts: {
|
|
460
469
|
dragNodes: FlowNodeEntity[];
|
|
461
470
|
dropNode: FlowNodeEntity;
|
|
462
471
|
}) => void;
|
|
463
472
|
canDrop?: (opts: {
|
|
464
|
-
dragNodes: FlowNodeEntity[];
|
|
465
473
|
dropNode: FlowNodeEntity;
|
|
466
474
|
isBranch?: boolean;
|
|
467
|
-
}
|
|
475
|
+
} & Xor<{
|
|
476
|
+
dragNodes: FlowNodeEntity[];
|
|
477
|
+
}, {
|
|
478
|
+
dragJSON: FlowNodeJSON;
|
|
479
|
+
}>) => boolean;
|
|
468
480
|
}
|
|
469
481
|
/**
|
|
470
482
|
* 监听节点的激活状态
|
|
471
483
|
*/
|
|
472
484
|
declare class FlowDragLayer extends Layer<FlowDragOptions> {
|
|
473
485
|
readonly document: FlowDocument;
|
|
474
|
-
readonly
|
|
486
|
+
readonly flowDragService: FlowDragService;
|
|
475
487
|
transforms: FlowNodeTransformData[];
|
|
476
488
|
protected editorStateConfig: EditorStateConfigEntity;
|
|
477
489
|
protected playgroundConfigEntity: PlaygroundConfigEntity;
|
|
@@ -479,6 +491,9 @@ declare class FlowDragLayer extends Layer<FlowDragOptions> {
|
|
|
479
491
|
protected flowRenderStateEntity: FlowRendererStateEntity;
|
|
480
492
|
protected selectConfigEntity: FlowSelectConfigEntity;
|
|
481
493
|
private initialPosition;
|
|
494
|
+
private disableDragScroll;
|
|
495
|
+
private dragJSON?;
|
|
496
|
+
private onCreateNode?;
|
|
482
497
|
private dragOffset;
|
|
483
498
|
get transitions(): FlowNodeTransitionData[];
|
|
484
499
|
readonly rendererRegistry: FlowRendererRegistry;
|
|
@@ -493,7 +508,7 @@ declare class FlowDragLayer extends Layer<FlowDragOptions> {
|
|
|
493
508
|
setDraggingStatus(status: boolean): void;
|
|
494
509
|
dragEnable(e: MouseEvent): boolean;
|
|
495
510
|
handleMouseMove(event: MouseEvent): void;
|
|
496
|
-
handleMouseUp(): void
|
|
511
|
+
handleMouseUp(): Promise<void>;
|
|
497
512
|
protected _dragger: PlaygroundDrag<undefined>;
|
|
498
513
|
/**
|
|
499
514
|
* 开始拖拽事件
|
|
@@ -502,12 +517,10 @@ declare class FlowDragLayer extends Layer<FlowDragOptions> {
|
|
|
502
517
|
startDrag(e: {
|
|
503
518
|
clientX: number;
|
|
504
519
|
clientY: number;
|
|
505
|
-
}, { dragStartEntity: startEntityFromProps, dragEntities, }: {
|
|
506
|
-
dragStartEntity: FlowNodeEntity;
|
|
507
|
-
dragEntities?: FlowNodeEntity[];
|
|
508
|
-
}, options?: {
|
|
520
|
+
}, { dragStartEntity: startEntityFromProps, dragEntities, dragJSON, onCreateNode }: StartDragProps, options?: {
|
|
509
521
|
dragOffsetX?: number;
|
|
510
522
|
dragOffsetY?: number;
|
|
523
|
+
disableDragScroll?: boolean;
|
|
511
524
|
}): Promise<void>;
|
|
512
525
|
onReady(): void;
|
|
513
526
|
render(): React.JSX.Element;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as _flowgram_ai_utils from '@flowgram.ai/utils';
|
|
2
|
-
import { Rectangle, Disposable, CacheOriginItem, ScrollSchema } from '@flowgram.ai/utils';
|
|
3
|
-
import { LABEL_SIDE_TYPE, FlowNodeTransitionData, FlowNodeEntity, FlowNodeTransformData, FlowDocument, FlowDocumentTransformerEntity, FlowNodeRenderData, FlowDragService, FlowRendererStateEntity } from '@flowgram.ai/document';
|
|
2
|
+
import { Rectangle, Disposable, CacheOriginItem, Xor, ScrollSchema } from '@flowgram.ai/utils';
|
|
3
|
+
import { LABEL_SIDE_TYPE, FlowNodeTransitionData, FlowNodeEntity, FlowNodeTransformData, FlowDocument, FlowDocumentTransformerEntity, FlowNodeRenderData, FlowDragService, FlowRendererStateEntity, FlowNodeJSON } from '@flowgram.ai/document';
|
|
4
4
|
import { ConfigEntity, EntityOpts, PlaygroundDragEvent, PositionSchema, SizeSchema, Layer, PipelineRegistry, LayerRegistry, PlaygroundConfigEntity, PlaygroundDrag, EditorStateConfigEntity, LayerOptions, ContextMenuService, SelectionService, PlaygroundConfig, CommandRegistry } from '@flowgram.ai/core';
|
|
5
5
|
import React from 'react';
|
|
6
6
|
import { throttle } from 'lodash-es';
|
|
@@ -455,23 +455,35 @@ declare class FlowScrollBarLayer extends Layer<ScrollBarOptions> {
|
|
|
455
455
|
* SPDX-License-Identifier: MIT
|
|
456
456
|
*/
|
|
457
457
|
|
|
458
|
+
type StartDragProps = {
|
|
459
|
+
dragEntities?: FlowNodeEntity[];
|
|
460
|
+
} & Xor<{
|
|
461
|
+
dragStartEntity: FlowNodeEntity;
|
|
462
|
+
}, {
|
|
463
|
+
dragJSON: FlowNodeJSON;
|
|
464
|
+
isBranch?: boolean;
|
|
465
|
+
onCreateNode: (json: FlowNodeJSON, dropEntity: FlowNodeEntity) => Promise<FlowNodeEntity>;
|
|
466
|
+
}>;
|
|
458
467
|
interface FlowDragOptions {
|
|
459
468
|
onDrop?: (opts: {
|
|
460
469
|
dragNodes: FlowNodeEntity[];
|
|
461
470
|
dropNode: FlowNodeEntity;
|
|
462
471
|
}) => void;
|
|
463
472
|
canDrop?: (opts: {
|
|
464
|
-
dragNodes: FlowNodeEntity[];
|
|
465
473
|
dropNode: FlowNodeEntity;
|
|
466
474
|
isBranch?: boolean;
|
|
467
|
-
}
|
|
475
|
+
} & Xor<{
|
|
476
|
+
dragNodes: FlowNodeEntity[];
|
|
477
|
+
}, {
|
|
478
|
+
dragJSON: FlowNodeJSON;
|
|
479
|
+
}>) => boolean;
|
|
468
480
|
}
|
|
469
481
|
/**
|
|
470
482
|
* 监听节点的激活状态
|
|
471
483
|
*/
|
|
472
484
|
declare class FlowDragLayer extends Layer<FlowDragOptions> {
|
|
473
485
|
readonly document: FlowDocument;
|
|
474
|
-
readonly
|
|
486
|
+
readonly flowDragService: FlowDragService;
|
|
475
487
|
transforms: FlowNodeTransformData[];
|
|
476
488
|
protected editorStateConfig: EditorStateConfigEntity;
|
|
477
489
|
protected playgroundConfigEntity: PlaygroundConfigEntity;
|
|
@@ -479,6 +491,9 @@ declare class FlowDragLayer extends Layer<FlowDragOptions> {
|
|
|
479
491
|
protected flowRenderStateEntity: FlowRendererStateEntity;
|
|
480
492
|
protected selectConfigEntity: FlowSelectConfigEntity;
|
|
481
493
|
private initialPosition;
|
|
494
|
+
private disableDragScroll;
|
|
495
|
+
private dragJSON?;
|
|
496
|
+
private onCreateNode?;
|
|
482
497
|
private dragOffset;
|
|
483
498
|
get transitions(): FlowNodeTransitionData[];
|
|
484
499
|
readonly rendererRegistry: FlowRendererRegistry;
|
|
@@ -493,7 +508,7 @@ declare class FlowDragLayer extends Layer<FlowDragOptions> {
|
|
|
493
508
|
setDraggingStatus(status: boolean): void;
|
|
494
509
|
dragEnable(e: MouseEvent): boolean;
|
|
495
510
|
handleMouseMove(event: MouseEvent): void;
|
|
496
|
-
handleMouseUp(): void
|
|
511
|
+
handleMouseUp(): Promise<void>;
|
|
497
512
|
protected _dragger: PlaygroundDrag<undefined>;
|
|
498
513
|
/**
|
|
499
514
|
* 开始拖拽事件
|
|
@@ -502,12 +517,10 @@ declare class FlowDragLayer extends Layer<FlowDragOptions> {
|
|
|
502
517
|
startDrag(e: {
|
|
503
518
|
clientX: number;
|
|
504
519
|
clientY: number;
|
|
505
|
-
}, { dragStartEntity: startEntityFromProps, dragEntities, }: {
|
|
506
|
-
dragStartEntity: FlowNodeEntity;
|
|
507
|
-
dragEntities?: FlowNodeEntity[];
|
|
508
|
-
}, options?: {
|
|
520
|
+
}, { dragStartEntity: startEntityFromProps, dragEntities, dragJSON, onCreateNode }: StartDragProps, options?: {
|
|
509
521
|
dragOffsetX?: number;
|
|
510
522
|
dragOffsetY?: number;
|
|
523
|
+
disableDragScroll?: boolean;
|
|
511
524
|
}): Promise<void>;
|
|
512
525
|
onReady(): void;
|
|
513
526
|
render(): React.JSX.Element;
|
package/dist/index.js
CHANGED
|
@@ -2337,6 +2337,7 @@ var DEFAULT_DRAG_OFFSET_Y = 8;
|
|
|
2337
2337
|
var FlowDragLayer = class extends import_core15.Layer {
|
|
2338
2338
|
constructor() {
|
|
2339
2339
|
super(...arguments);
|
|
2340
|
+
this.disableDragScroll = false;
|
|
2340
2341
|
this.dragOffset = {
|
|
2341
2342
|
x: DEFAULT_DRAG_OFFSET_X,
|
|
2342
2343
|
y: DEFAULT_DRAG_OFFSET_Y
|
|
@@ -2377,19 +2378,20 @@ var FlowDragLayer = class extends import_core15.Layer {
|
|
|
2377
2378
|
return currentState === import_core15.EditorState.STATE_GRAB;
|
|
2378
2379
|
}
|
|
2379
2380
|
setDraggingStatus(status) {
|
|
2380
|
-
if (this.
|
|
2381
|
-
this.
|
|
2381
|
+
if (this.flowDragService.nodeDragIdsWithChildren.length) {
|
|
2382
|
+
this.flowDragService.nodeDragIdsWithChildren.forEach((_id) => {
|
|
2382
2383
|
const node = this.entityManager.getEntityById(_id);
|
|
2383
2384
|
const data = node?.getData(import_document18.FlowNodeRenderData);
|
|
2384
2385
|
data.dragging = status;
|
|
2385
2386
|
});
|
|
2386
2387
|
}
|
|
2388
|
+
this.flowRenderStateEntity.setDragging(status);
|
|
2387
2389
|
}
|
|
2388
2390
|
dragEnable(e) {
|
|
2389
2391
|
return Math.abs(e.clientX - this.initialPosition.x) > DRAG_OFFSET || Math.abs(e.clientY - this.initialPosition.y) > DRAG_OFFSET;
|
|
2390
2392
|
}
|
|
2391
2393
|
handleMouseMove(event) {
|
|
2392
|
-
if (this.dragStartEntity && this.dragEnable(event)) {
|
|
2394
|
+
if ((this.dragJSON || this.dragStartEntity) && this.dragEnable(event)) {
|
|
2393
2395
|
this.setDraggingStatus(true);
|
|
2394
2396
|
const scale = this.playgroundConfigEntity.finalScale;
|
|
2395
2397
|
if (this.containerRef.current) {
|
|
@@ -2397,7 +2399,7 @@ var FlowDragLayer = class extends import_core15.Layer {
|
|
|
2397
2399
|
const clientBounds = this.playgroundConfigEntity.getClientBounds();
|
|
2398
2400
|
const dragBlockX = event.clientX - (this.pipelineNode.offsetLeft || 0) - clientBounds.x - (dragNode.clientWidth - this.dragOffset.x) * scale;
|
|
2399
2401
|
const dragBlockY = event.clientY - (this.pipelineNode.offsetTop || 0) - clientBounds.y - (dragNode.clientHeight - this.dragOffset.y) * scale;
|
|
2400
|
-
const isBranch = this.
|
|
2402
|
+
const isBranch = this.flowDragService.isDragBranch;
|
|
2401
2403
|
const draggingRect = new import_utils22.Rectangle(
|
|
2402
2404
|
dragBlockX,
|
|
2403
2405
|
dragBlockY,
|
|
@@ -2417,7 +2419,7 @@ var FlowDragLayer = class extends import_core15.Layer {
|
|
|
2417
2419
|
side = labelOffsetType;
|
|
2418
2420
|
return hasCollision;
|
|
2419
2421
|
});
|
|
2420
|
-
if (collisionTransition && (isBranch ? this.
|
|
2422
|
+
if (collisionTransition && (isBranch ? this.flowDragService.isDroppableBranch(collisionTransition.entity, side) : this.flowDragService.isDroppableNode(collisionTransition.entity)) && (!this.options.canDrop || this.options.canDrop({
|
|
2421
2423
|
dragNodes: this.dragEntities,
|
|
2422
2424
|
dropNode: collisionTransition.entity,
|
|
2423
2425
|
isBranch
|
|
@@ -2433,24 +2435,30 @@ var FlowDragLayer = class extends import_core15.Layer {
|
|
|
2433
2435
|
this.containerRef.current.style.top = `${dragBlockY}px`;
|
|
2434
2436
|
this.containerRef.current.style.transformOrigin = "top left";
|
|
2435
2437
|
this.containerRef.current.style.transform = `scale(${scale})`;
|
|
2436
|
-
this.
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2438
|
+
if (!this.disableDragScroll) {
|
|
2439
|
+
this.flowDragConfigEntity.scrollDirection(
|
|
2440
|
+
event,
|
|
2441
|
+
this.containerRef.current,
|
|
2442
|
+
dragBlockX,
|
|
2443
|
+
dragBlockY
|
|
2444
|
+
);
|
|
2445
|
+
}
|
|
2442
2446
|
}
|
|
2443
2447
|
}
|
|
2444
2448
|
}
|
|
2445
|
-
handleMouseUp() {
|
|
2449
|
+
async handleMouseUp() {
|
|
2446
2450
|
this.setDraggingStatus(false);
|
|
2447
|
-
if (this.dragStartEntity) {
|
|
2448
|
-
const activatedNodeId = this.
|
|
2451
|
+
if (this.dragStartEntity || this.dragJSON) {
|
|
2452
|
+
const activatedNodeId = this.flowDragService.dropNodeId;
|
|
2449
2453
|
if (activatedNodeId) {
|
|
2450
|
-
if (this.
|
|
2451
|
-
this.
|
|
2454
|
+
if (this.flowDragService.isDragBranch) {
|
|
2455
|
+
this.flowDragService.dropBranch();
|
|
2452
2456
|
} else {
|
|
2453
|
-
this.
|
|
2457
|
+
if (this.dragJSON) {
|
|
2458
|
+
await this.flowDragService.dropCreateNode(this.dragJSON, this.onCreateNode);
|
|
2459
|
+
} else {
|
|
2460
|
+
this.flowDragService.dropNode();
|
|
2461
|
+
}
|
|
2454
2462
|
this.selectConfigEntity.clearSelectedNodes();
|
|
2455
2463
|
}
|
|
2456
2464
|
}
|
|
@@ -2460,6 +2468,8 @@ var FlowDragLayer = class extends import_core15.Layer {
|
|
|
2460
2468
|
this.dragEntities = [];
|
|
2461
2469
|
this.flowDragConfigEntity.stopAllScroll();
|
|
2462
2470
|
}
|
|
2471
|
+
this.disableDragScroll = false;
|
|
2472
|
+
this.dragJSON = void 0;
|
|
2463
2473
|
if (this.containerRef.current) {
|
|
2464
2474
|
this.containerRef.current.style.visibility = "hidden";
|
|
2465
2475
|
if (this.pipelineNode.parentElement.contains(this.draggingNodeMask)) {
|
|
@@ -2471,19 +2481,20 @@ var FlowDragLayer = class extends import_core15.Layer {
|
|
|
2471
2481
|
* 开始拖拽事件
|
|
2472
2482
|
* @param e
|
|
2473
2483
|
*/
|
|
2474
|
-
async startDrag(e, {
|
|
2475
|
-
dragStartEntity: startEntityFromProps,
|
|
2476
|
-
dragEntities
|
|
2477
|
-
}, options) {
|
|
2484
|
+
async startDrag(e, { dragStartEntity: startEntityFromProps, dragEntities, dragJSON, onCreateNode }, options) {
|
|
2478
2485
|
if (this.isGrab() || this.config.disabled || this.config.readonly) {
|
|
2479
2486
|
return;
|
|
2480
2487
|
}
|
|
2488
|
+
this.disableDragScroll = Boolean(options?.disableDragScroll);
|
|
2489
|
+
this.dragJSON = dragJSON;
|
|
2490
|
+
this.onCreateNode = onCreateNode;
|
|
2481
2491
|
this.dragOffset.x = options?.dragOffsetX || DEFAULT_DRAG_OFFSET_X;
|
|
2482
2492
|
this.dragOffset.y = options?.dragOffsetY || DEFAULT_DRAG_OFFSET_Y;
|
|
2483
|
-
const
|
|
2484
|
-
const
|
|
2493
|
+
const type = startEntityFromProps?.flowNodeType || dragJSON?.type;
|
|
2494
|
+
const isIcon = type === import_document18.FlowNodeBaseType.BLOCK_ICON;
|
|
2495
|
+
const isOrderIcon = type === import_document18.FlowNodeBaseType.BLOCK_ORDER_ICON;
|
|
2485
2496
|
const dragStartEntity = isIcon || isOrderIcon ? startEntityFromProps.parent : startEntityFromProps;
|
|
2486
|
-
if (!dragStartEntity.getData(import_document18.FlowNodeRenderData).draggable) {
|
|
2497
|
+
if (dragStartEntity && !dragStartEntity.getData(import_document18.FlowNodeRenderData).draggable) {
|
|
2487
2498
|
return;
|
|
2488
2499
|
}
|
|
2489
2500
|
this.initialPosition = {
|
|
@@ -2491,7 +2502,7 @@ var FlowDragLayer = class extends import_core15.Layer {
|
|
|
2491
2502
|
y: e.clientY
|
|
2492
2503
|
};
|
|
2493
2504
|
this.dragStartEntity = dragStartEntity;
|
|
2494
|
-
this.dragEntities = dragEntities || [this.dragStartEntity];
|
|
2505
|
+
this.dragEntities = dragEntities || (this.dragStartEntity ? [this.dragStartEntity] : []);
|
|
2495
2506
|
return this._dragger.start(e.clientX, e.clientY);
|
|
2496
2507
|
}
|
|
2497
2508
|
onReady() {
|
|
@@ -2503,7 +2514,7 @@ var FlowDragLayer = class extends import_core15.Layer {
|
|
|
2503
2514
|
this.draggingNodeMask.style.cursor = "pointer";
|
|
2504
2515
|
this.dragNodeComp = this.rendererRegistry.getRendererComponent("drag-node" /* DRAG_NODE */);
|
|
2505
2516
|
if (this.options.onDrop) {
|
|
2506
|
-
this.toDispose.push(this.
|
|
2517
|
+
this.toDispose.push(this.flowDragService.onDrop(this.options.onDrop));
|
|
2507
2518
|
}
|
|
2508
2519
|
}
|
|
2509
2520
|
render() {
|
|
@@ -2515,7 +2526,14 @@ var FlowDragLayer = class extends import_core15.Layer {
|
|
|
2515
2526
|
style: { position: "absolute", zIndex: 99999, visibility: "hidden" },
|
|
2516
2527
|
onMouseEnter: (e) => e.stopPropagation()
|
|
2517
2528
|
},
|
|
2518
|
-
/* @__PURE__ */ import_react15.default.createElement(
|
|
2529
|
+
/* @__PURE__ */ import_react15.default.createElement(
|
|
2530
|
+
DragComp,
|
|
2531
|
+
{
|
|
2532
|
+
dragJSON: this.dragJSON,
|
|
2533
|
+
dragStart: this.dragStartEntity,
|
|
2534
|
+
dragNodes: this.dragEntities
|
|
2535
|
+
}
|
|
2536
|
+
)
|
|
2519
2537
|
);
|
|
2520
2538
|
}
|
|
2521
2539
|
};
|
|
@@ -2524,7 +2542,7 @@ __decorateClass([
|
|
|
2524
2542
|
], FlowDragLayer.prototype, "document", 2);
|
|
2525
2543
|
__decorateClass([
|
|
2526
2544
|
(0, import_inversify9.inject)(import_document18.FlowDragService)
|
|
2527
|
-
], FlowDragLayer.prototype, "
|
|
2545
|
+
], FlowDragLayer.prototype, "flowDragService", 2);
|
|
2528
2546
|
__decorateClass([
|
|
2529
2547
|
(0, import_core15.observeEntityDatas)(import_document18.FlowNodeEntity, import_document18.FlowNodeTransformData)
|
|
2530
2548
|
], FlowDragLayer.prototype, "transforms", 2);
|