@portabletext/editor 2.21.2 → 3.0.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.
Files changed (79) hide show
  1. package/lib/_chunks-dts/index.d.ts +50 -210
  2. package/lib/_chunks-es/selector.is-at-the-start-of-block.js +103 -20
  3. package/lib/_chunks-es/selector.is-at-the-start-of-block.js.map +1 -1
  4. package/lib/_chunks-es/{util.get-text-block-text.js → util.slice-blocks.js} +29 -5
  5. package/lib/_chunks-es/util.slice-blocks.js.map +1 -0
  6. package/lib/_chunks-es/util.slice-text-block.js +13 -2
  7. package/lib/_chunks-es/util.slice-text-block.js.map +1 -1
  8. package/lib/behaviors/index.d.ts +1 -1
  9. package/lib/index.d.ts +2 -2
  10. package/lib/index.js +323 -320
  11. package/lib/index.js.map +1 -1
  12. package/lib/plugins/index.d.ts +2 -133
  13. package/lib/plugins/index.js +2 -796
  14. package/lib/plugins/index.js.map +1 -1
  15. package/lib/selectors/index.d.ts +2 -24
  16. package/lib/selectors/index.js +28 -130
  17. package/lib/selectors/index.js.map +1 -1
  18. package/lib/utils/index.d.ts +3 -3
  19. package/lib/utils/index.js +97 -9
  20. package/lib/utils/index.js.map +1 -1
  21. package/package.json +7 -9
  22. package/src/behaviors/behavior.perform-event.ts +7 -7
  23. package/src/editor/PortableTextEditor.tsx +0 -19
  24. package/src/editor/create-editor.ts +0 -3
  25. package/src/editor/editor-machine.ts +0 -10
  26. package/src/editor/event-to-change.tsx +5 -1
  27. package/src/editor/plugins/create-with-event-listeners.ts +0 -4
  28. package/src/editor/plugins/createWithObjectKeys.ts +2 -1
  29. package/src/editor/plugins/createWithPatches.ts +3 -3
  30. package/src/editor/plugins/createWithPlaceholderBlock.ts +2 -1
  31. package/src/editor/plugins/createWithPortableTextMarkModel.ts +2 -1
  32. package/src/editor/plugins/with-plugins.ts +10 -14
  33. package/src/editor/relay-machine.ts +0 -4
  34. package/src/editor/sync-machine.ts +2 -2
  35. package/src/editor.ts +0 -4
  36. package/src/history/behavior.operation.history.redo.ts +67 -0
  37. package/src/history/behavior.operation.history.undo.ts +71 -0
  38. package/src/history/event.history.undo.test.tsx +672 -0
  39. package/src/history/history.preserving-keys.test.tsx +112 -0
  40. package/src/history/remote-patches.ts +20 -0
  41. package/src/history/slate-plugin.history.ts +146 -0
  42. package/src/history/slate-plugin.redoing.ts +21 -0
  43. package/src/history/slate-plugin.undoing.ts +21 -0
  44. package/src/history/slate-plugin.without-history.ts +23 -0
  45. package/src/history/transform-operation.ts +245 -0
  46. package/src/history/undo-redo-collaboration.test.tsx +541 -0
  47. package/src/history/undo-redo.feature +125 -0
  48. package/src/history/undo-redo.test.tsx +195 -0
  49. package/src/history/undo-step.ts +148 -0
  50. package/src/index.ts +0 -1
  51. package/src/internal-utils/applyPatch.ts +46 -1
  52. package/src/operations/behavior.operations.ts +2 -4
  53. package/src/plugins/index.ts +0 -3
  54. package/src/selectors/index.ts +0 -3
  55. package/src/test/vitest/step-definitions.tsx +88 -8
  56. package/src/test/vitest/test-editor.tsx +1 -1
  57. package/lib/_chunks-es/selector.get-selection-text.js +0 -92
  58. package/lib/_chunks-es/selector.get-selection-text.js.map +0 -1
  59. package/lib/_chunks-es/selector.get-text-before.js +0 -36
  60. package/lib/_chunks-es/selector.get-text-before.js.map +0 -1
  61. package/lib/_chunks-es/util.get-text-block-text.js.map +0 -1
  62. package/lib/_chunks-es/util.is-empty-text-block.js +0 -40
  63. package/lib/_chunks-es/util.is-empty-text-block.js.map +0 -1
  64. package/lib/_chunks-es/util.merge-text-blocks.js +0 -101
  65. package/lib/_chunks-es/util.merge-text-blocks.js.map +0 -1
  66. package/src/editor/plugins/createWithMaxBlocks.ts +0 -53
  67. package/src/editor/plugins/createWithUndoRedo.ts +0 -628
  68. package/src/editor/with-undo-step.ts +0 -37
  69. package/src/editor/withUndoRedo.ts +0 -34
  70. package/src/editor-event-listener.tsx +0 -28
  71. package/src/plugins/plugin.decorator-shortcut.ts +0 -238
  72. package/src/plugins/plugin.markdown.test.tsx +0 -42
  73. package/src/plugins/plugin.markdown.tsx +0 -131
  74. package/src/plugins/plugin.one-line.tsx +0 -123
  75. package/src/selectors/selector.get-list-state.test.ts +0 -189
  76. package/src/selectors/selector.get-list-state.ts +0 -96
  77. package/src/selectors/selector.get-selected-slice.ts +0 -13
  78. package/src/selectors/selector.get-trimmed-selection.test.ts +0 -657
  79. package/src/selectors/selector.get-trimmed-selection.ts +0 -189
@@ -1,657 +0,0 @@
1
- import {compileSchema, defineSchema} from '@portabletext/schema'
2
- import {createTestKeyGenerator} from '@portabletext/test'
3
- import type {PortableTextBlock} from '@sanity/types'
4
- import {describe, expect, test} from 'vitest'
5
- import {createTestSnapshot} from '../internal-utils/create-test-snapshot'
6
- import type {EditorSelection} from '../types/editor'
7
- import {parseBlock} from '../utils/parse-blocks'
8
- import {getTrimmedSelection} from './selector.get-trimmed-selection'
9
-
10
- const keyGenerator = createTestKeyGenerator()
11
-
12
- function snapshot(
13
- value: Array<Partial<PortableTextBlock>>,
14
- selection: EditorSelection,
15
- ) {
16
- const schema = compileSchema(
17
- defineSchema({
18
- blockObjects: [{name: 'image'}],
19
- inlineObjects: [{name: 'stock-ticker'}],
20
- }),
21
- )
22
-
23
- return createTestSnapshot({
24
- context: {
25
- keyGenerator,
26
- schema,
27
- selection,
28
- value: value.flatMap((block) => {
29
- const parsedBlock = parseBlock({
30
- context: {
31
- keyGenerator,
32
- schema,
33
- },
34
- block,
35
- options: {
36
- removeUnusedMarkDefs: true,
37
- validateFields: false,
38
- },
39
- })
40
-
41
- return parsedBlock ? [parsedBlock] : []
42
- }),
43
- },
44
- })
45
- }
46
-
47
- function createSpan(text: string, marks: Array<string> = []) {
48
- return {
49
- _key: keyGenerator(),
50
- _type: 'span',
51
- text,
52
- marks,
53
- }
54
- }
55
-
56
- function createBlock(children: PortableTextBlock['children']) {
57
- return {
58
- _key: keyGenerator(),
59
- _type: 'block',
60
- children,
61
- }
62
- }
63
-
64
- function createStockTicker(symbol: string) {
65
- return {
66
- _key: keyGenerator(),
67
- _type: 'stock-ticker',
68
- symbol,
69
- }
70
- }
71
-
72
- function createImage(src: string) {
73
- return {
74
- _key: keyGenerator(),
75
- _type: 'image',
76
- src,
77
- }
78
- }
79
-
80
- describe(getTrimmedSelection.name, () => {
81
- test('Sensible defaults', () => {
82
- expect(getTrimmedSelection(snapshot([], null))).toBe(null)
83
- expect(
84
- getTrimmedSelection(snapshot([createBlock([createSpan('foo')])], null)),
85
- ).toBe(null)
86
- })
87
-
88
- test('does not trim spans that have selected text', () => {
89
- const foo = createSpan('foo')
90
- const bar = createSpan('bar', ['strong'])
91
- const baz = createSpan('baz')
92
- const block = createBlock([foo, bar, baz])
93
-
94
- expect(
95
- getTrimmedSelection(
96
- snapshot([block], {
97
- anchor: {
98
- path: [{_key: block._key}, 'children', {_key: bar._key}],
99
- offset: 0,
100
- },
101
- focus: {
102
- path: [{_key: block._key}, 'children', {_key: bar._key}],
103
- offset: 3,
104
- },
105
- }),
106
- ),
107
- ).toEqual({
108
- anchor: {
109
- path: [{_key: block._key}, 'children', {_key: bar._key}],
110
- offset: 0,
111
- },
112
- focus: {
113
- path: [{_key: block._key}, 'children', {_key: bar._key}],
114
- offset: 3,
115
- },
116
- })
117
-
118
- expect(
119
- getTrimmedSelection(
120
- snapshot([block], {
121
- anchor: {
122
- path: [{_key: block._key}, 'children', {_key: foo._key}],
123
- offset: 2,
124
- },
125
- focus: {
126
- path: [{_key: block._key}, 'children', {_key: baz._key}],
127
- offset: 2,
128
- },
129
- }),
130
- ),
131
- ).toEqual({
132
- anchor: {
133
- path: [{_key: block._key}, 'children', {_key: foo._key}],
134
- offset: 2,
135
- },
136
- focus: {
137
- path: [{_key: block._key}, 'children', {_key: baz._key}],
138
- offset: 2,
139
- },
140
- })
141
- })
142
-
143
- test('trims spans that have no selected text', () => {
144
- const foo = createSpan('foo')
145
- const bar = createSpan('bar', ['strong'])
146
- const baz = createSpan('baz')
147
- const block = createBlock([foo, bar, baz])
148
-
149
- expect(
150
- getTrimmedSelection(
151
- snapshot([block], {
152
- anchor: {
153
- path: [{_key: block._key}, 'children', {_key: foo._key}],
154
- offset: 3,
155
- },
156
- focus: {
157
- path: [{_key: block._key}, 'children', {_key: baz._key}],
158
- offset: 0,
159
- },
160
- }),
161
- ),
162
- ).toEqual({
163
- anchor: {
164
- path: [{_key: block._key}, 'children', {_key: bar._key}],
165
- offset: 0,
166
- },
167
- focus: {
168
- path: [{_key: block._key}, 'children', {_key: bar._key}],
169
- offset: 3,
170
- },
171
- })
172
- })
173
-
174
- test('trims inline objects at the start edge', () => {
175
- const aapl = createStockTicker('AAPL')
176
- const foo = createSpan('foo')
177
- const block = createBlock([aapl, foo])
178
-
179
- expect(
180
- getTrimmedSelection(
181
- snapshot([block], {
182
- anchor: {
183
- path: [{_key: block._key}, 'children', {_key: aapl._key}],
184
- offset: 0,
185
- },
186
- focus: {
187
- path: [{_key: block._key}, 'children', {_key: foo._key}],
188
- offset: 3,
189
- },
190
- }),
191
- ),
192
- ).toEqual({
193
- anchor: {
194
- path: [{_key: block._key}, 'children', {_key: foo._key}],
195
- offset: 0,
196
- },
197
- focus: {
198
- path: [{_key: block._key}, 'children', {_key: foo._key}],
199
- offset: 3,
200
- },
201
- })
202
- })
203
-
204
- test('trims inline objects at the end edge', () => {
205
- const foo = createSpan('foo')
206
- const aapl = createStockTicker('AAPL')
207
- const block = createBlock([foo, aapl])
208
-
209
- expect(
210
- getTrimmedSelection(
211
- snapshot([block], {
212
- anchor: {
213
- path: [{_key: block._key}, 'children', {_key: foo._key}],
214
- offset: 0,
215
- },
216
- focus: {
217
- path: [{_key: block._key}, 'children', {_key: aapl._key}],
218
- offset: 0,
219
- },
220
- }),
221
- ),
222
- ).toEqual({
223
- anchor: {
224
- path: [{_key: block._key}, 'children', {_key: foo._key}],
225
- offset: 0,
226
- },
227
- focus: {
228
- path: [{_key: block._key}, 'children', {_key: foo._key}],
229
- offset: 3,
230
- },
231
- })
232
- })
233
-
234
- test('trims empty spans', () => {
235
- const empty1 = createSpan('')
236
- const aapl = createStockTicker('AAPL')
237
- const foo = createSpan('foo')
238
- const nvda = createStockTicker('NVDA')
239
- const empty2 = createSpan('')
240
- const block = createBlock([empty1, aapl, foo, nvda, empty2])
241
-
242
- expect(
243
- getTrimmedSelection(
244
- snapshot([block], {
245
- anchor: {
246
- path: [{_key: block._key}, 'children', {_key: empty1._key}],
247
- offset: 0,
248
- },
249
- focus: {
250
- path: [{_key: block._key}, 'children', {_key: empty2._key}],
251
- offset: 0,
252
- },
253
- }),
254
- ),
255
- ).toEqual({
256
- anchor: {
257
- path: [{_key: block._key}, 'children', {_key: foo._key}],
258
- offset: 0,
259
- },
260
- focus: {
261
- path: [{_key: block._key}, 'children', {_key: foo._key}],
262
- offset: 3,
263
- },
264
- })
265
- })
266
-
267
- test('trims off block at the start edge', () => {
268
- const empty1 = createSpan('')
269
- const aapl = createStockTicker('AAPL')
270
- const foo = createSpan('foo')
271
- const empty2 = createSpan('')
272
- const nvda = createStockTicker('NVDA')
273
- const bar = createSpan('bar')
274
- const block1 = createBlock([foo, aapl, empty1])
275
- const block2 = createBlock([empty2, nvda, bar])
276
-
277
- expect(
278
- getTrimmedSelection(
279
- snapshot([block1, block2], {
280
- anchor: {
281
- path: [{_key: block1._key}, 'children', {_key: foo._key}],
282
- offset: 3,
283
- },
284
- focus: {
285
- path: [{_key: block2._key}, 'children', {_key: bar._key}],
286
- offset: 3,
287
- },
288
- }),
289
- ),
290
- ).toEqual({
291
- anchor: {
292
- path: [{_key: block2._key}, 'children', {_key: bar._key}],
293
- offset: 0,
294
- },
295
- focus: {
296
- path: [{_key: block2._key}, 'children', {_key: bar._key}],
297
- offset: 3,
298
- },
299
- })
300
- })
301
-
302
- test('trims off block at the end edge', () => {
303
- const empty1 = createSpan('')
304
- const aapl = createStockTicker('AAPL')
305
- const foo = createSpan('foo')
306
- const empty2 = createSpan('')
307
- const nvda = createStockTicker('NVDA')
308
- const bar = createSpan('bar')
309
- const block1 = createBlock([foo, aapl, empty1])
310
- const block2 = createBlock([empty2, nvda, bar])
311
-
312
- expect(
313
- getTrimmedSelection(
314
- snapshot([block1, block2], {
315
- anchor: {
316
- path: [{_key: block1._key}, 'children', {_key: foo._key}],
317
- offset: 0,
318
- },
319
- focus: {
320
- path: [{_key: block2._key}, 'children', {_key: bar._key}],
321
- offset: 0,
322
- },
323
- }),
324
- ),
325
- ).toEqual({
326
- anchor: {
327
- path: [{_key: block1._key}, 'children', {_key: foo._key}],
328
- offset: 0,
329
- },
330
- focus: {
331
- path: [{_key: block1._key}, 'children', {_key: foo._key}],
332
- offset: 3,
333
- },
334
- })
335
- })
336
-
337
- test('ignores empty text block on start edge', () => {
338
- const empty = createSpan('')
339
- const block1 = createBlock([empty])
340
- const foo = createSpan('foo')
341
- const block2 = createBlock([foo])
342
-
343
- expect(
344
- getTrimmedSelection(
345
- snapshot([block1, block2], {
346
- anchor: {
347
- path: [{_key: block1._key}, 'children', {_key: empty._key}],
348
- offset: 0,
349
- },
350
- focus: {
351
- path: [{_key: block2._key}, 'children', {_key: foo._key}],
352
- offset: 3,
353
- },
354
- }),
355
- ),
356
- ).toEqual({
357
- anchor: {
358
- path: [{_key: block1._key}, 'children', {_key: empty._key}],
359
- offset: 0,
360
- },
361
- focus: {
362
- path: [{_key: block2._key}, 'children', {_key: foo._key}],
363
- offset: 3,
364
- },
365
- })
366
- })
367
-
368
- test('ignores empty text block on end edge', () => {
369
- const foo = createSpan('foo')
370
- const block1 = createBlock([foo])
371
- const empty = createSpan('')
372
- const block2 = createBlock([empty])
373
-
374
- expect(
375
- getTrimmedSelection(
376
- snapshot([block1, block2], {
377
- anchor: {
378
- path: [{_key: block1._key}, 'children', {_key: foo._key}],
379
- offset: 0,
380
- },
381
- focus: {
382
- path: [{_key: block2._key}, 'children', {_key: empty._key}],
383
- offset: 0,
384
- },
385
- }),
386
- ),
387
- ).toEqual({
388
- anchor: {
389
- path: [{_key: block1._key}, 'children', {_key: foo._key}],
390
- offset: 0,
391
- },
392
- focus: {
393
- path: [{_key: block2._key}, 'children', {_key: empty._key}],
394
- offset: 0,
395
- },
396
- })
397
- })
398
-
399
- test('ignores block object on start edge', () => {
400
- const image1 = createImage('image1')
401
- const empty1 = createSpan('')
402
- const aapl = createStockTicker('AAPL')
403
- const foo = createSpan('foo')
404
- const nvda = createStockTicker('NVDA')
405
- const empty2 = createSpan('')
406
- const block = createBlock([empty1, aapl, foo, nvda, empty2])
407
- const image2 = createImage('image2')
408
-
409
- expect(
410
- getTrimmedSelection(
411
- snapshot([image1, block, image2], {
412
- anchor: {
413
- path: [{_key: image1._key}],
414
- offset: 0,
415
- },
416
- focus: {
417
- path: [{_key: block._key}, 'children', {_key: empty2._key}],
418
- offset: 0,
419
- },
420
- }),
421
- ),
422
- ).toEqual({
423
- anchor: {
424
- path: [{_key: image1._key}],
425
- offset: 0,
426
- },
427
- focus: {
428
- path: [{_key: block._key}, 'children', {_key: foo._key}],
429
- offset: 3,
430
- },
431
- })
432
- })
433
-
434
- test('ignores block object on end edge', () => {
435
- const image1 = createImage('image1')
436
- const empty1 = createSpan('')
437
- const aapl = createStockTicker('AAPL')
438
- const foo = createSpan('foo')
439
- const nvda = createStockTicker('NVDA')
440
- const empty2 = createSpan('')
441
- const block = createBlock([empty1, aapl, foo, nvda, empty2])
442
- const image2 = createImage('image2')
443
-
444
- expect(
445
- getTrimmedSelection(
446
- snapshot([image1, block, image2], {
447
- anchor: {
448
- path: [{_key: block._key}, 'children', {_key: empty1._key}],
449
- offset: 0,
450
- },
451
- focus: {
452
- path: [{_key: image2._key}],
453
- offset: 0,
454
- },
455
- }),
456
- ),
457
- ).toEqual({
458
- anchor: {
459
- path: [{_key: block._key}, 'children', {_key: foo._key}],
460
- offset: 0,
461
- },
462
- focus: {
463
- path: [{_key: image2._key}],
464
- offset: 0,
465
- },
466
- })
467
- })
468
-
469
- test('ignores block objects on start and end edge', () => {
470
- const image1 = createImage('image1')
471
- const empty1 = createSpan('')
472
- const aapl = createStockTicker('AAPL')
473
- const foo = createSpan('foo')
474
- const nvda = createStockTicker('NVDA')
475
- const empty2 = createSpan('')
476
- const block = createBlock([empty1, aapl, foo, nvda, empty2])
477
- const image2 = createImage('image2')
478
-
479
- expect(
480
- getTrimmedSelection(
481
- snapshot([image1, block, image2], {
482
- anchor: {
483
- path: [{_key: image1._key}],
484
- offset: 0,
485
- },
486
- focus: {
487
- path: [{_key: image2._key}],
488
- offset: 0,
489
- },
490
- }),
491
- ),
492
- ).toEqual({
493
- anchor: {
494
- path: [{_key: image1._key}],
495
- offset: 0,
496
- },
497
- focus: {
498
- path: [{_key: image2._key}],
499
- offset: 0,
500
- },
501
- })
502
- })
503
-
504
- test('edge case', () => {
505
- expect(
506
- getTrimmedSelection(
507
- snapshot(
508
- [
509
- {
510
- _key: 'b0',
511
- _type: 'block',
512
- children: [
513
- {
514
- _key: 's0',
515
- _type: 'span',
516
- text: 'foo',
517
- },
518
- {
519
- _key: 's1',
520
- _type: 'span',
521
- text: '',
522
- },
523
- ],
524
- },
525
- {
526
- _key: 'b1',
527
- _type: 'block',
528
- children: [
529
- {
530
- _key: 's2',
531
- _type: 'span',
532
- text: '',
533
- },
534
- {
535
- _key: 's3',
536
- _type: 'span',
537
- text: 'bar',
538
- },
539
- ],
540
- },
541
- ],
542
- {
543
- anchor: {
544
- path: [{_key: 'b0'}, 'children', {_key: 's0'}],
545
- offset: 3,
546
- },
547
- focus: {
548
- path: [{_key: 'b1'}, 'children', {_key: 's2'}],
549
- offset: 0,
550
- },
551
- },
552
- ),
553
- ),
554
- ).toEqual(null)
555
- })
556
-
557
- test('edge case #2', () => {
558
- const foo = createSpan('foo')
559
- const block1 = createBlock([foo])
560
- const empty = createSpan('')
561
- const block2 = createBlock([empty])
562
- const bar = createSpan('bar')
563
- const block3 = createBlock([bar])
564
-
565
- expect(
566
- getTrimmedSelection(
567
- snapshot([block1, block2, block3], {
568
- anchor: {
569
- path: [{_key: block1._key}, 'children', {_key: foo._key}],
570
- offset: 3,
571
- },
572
- focus: {
573
- path: [{_key: block3._key}, 'children', {_key: bar._key}],
574
- offset: 0,
575
- },
576
- }),
577
- ),
578
- ).toEqual({
579
- anchor: {
580
- path: [{_key: block2._key}, 'children', {_key: empty._key}],
581
- offset: 0,
582
- },
583
- focus: {
584
- path: [{_key: block2._key}, 'children', {_key: empty._key}],
585
- offset: 0,
586
- },
587
- })
588
- })
589
-
590
- test('edge case #3', () => {
591
- const foo = createSpan('foo')
592
- const block1 = createBlock([foo])
593
- const empty = createSpan('')
594
- const block2 = createBlock([empty])
595
- const bar = createSpan('bar')
596
- const block3 = createBlock([bar])
597
-
598
- expect(
599
- getTrimmedSelection(
600
- snapshot([block1, block2, block3], {
601
- anchor: {
602
- path: [{_key: block3._key}, 'children', {_key: bar._key}],
603
- offset: 0,
604
- },
605
- focus: {
606
- path: [{_key: block1._key}, 'children', {_key: foo._key}],
607
- offset: 3,
608
- },
609
- backward: true,
610
- }),
611
- ),
612
- ).toEqual({
613
- anchor: {
614
- path: [{_key: block2._key}, 'children', {_key: empty._key}],
615
- offset: 0,
616
- },
617
- focus: {
618
- path: [{_key: block2._key}, 'children', {_key: empty._key}],
619
- offset: 0,
620
- },
621
- backward: true,
622
- })
623
- })
624
-
625
- test('backwards selection', () => {
626
- const foo = createSpan('foo')
627
- const block1 = createBlock([foo])
628
- const bar = createSpan('bar')
629
- const block2 = createBlock([bar])
630
-
631
- expect(
632
- getTrimmedSelection(
633
- snapshot([block1, block2], {
634
- anchor: {
635
- path: [{_key: block2._key}, 'children', {_key: bar._key}],
636
- offset: 3,
637
- },
638
- focus: {
639
- path: [{_key: block1._key}, 'children', {_key: foo._key}],
640
- offset: 3,
641
- },
642
- backward: true,
643
- }),
644
- ),
645
- ).toEqual({
646
- anchor: {
647
- path: [{_key: block2._key}, 'children', {_key: bar._key}],
648
- offset: 3,
649
- },
650
- focus: {
651
- path: [{_key: block2._key}, 'children', {_key: bar._key}],
652
- offset: 0,
653
- },
654
- backward: true,
655
- })
656
- })
657
- })