@atlaskit/editor-plugin-synced-block 5.0.0 → 5.1.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 CHANGED
@@ -1,5 +1,16 @@
1
1
  # @atlaskit/editor-plugin-synced-block
2
2
 
3
+ ## 5.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`bf49041938d1a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/bf49041938d1a) -
8
+ EDITOR-2257 editor synced blocks ssr part 1
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies
13
+
3
14
  ## 5.0.0
4
15
 
5
16
  ### Patch Changes
@@ -80,6 +80,9 @@
80
80
  {
81
81
  "path": "../../../design-system/modal-dialog/afm-cc/tsconfig.json"
82
82
  },
83
+ {
84
+ "path": "../../../platform/feature-flags/afm-cc/tsconfig.json"
85
+ },
83
86
  {
84
87
  "path": "../../../design-system/primitives/afm-cc/tsconfig.json"
85
88
  },
@@ -80,6 +80,9 @@
80
80
  {
81
81
  "path": "../../../design-system/modal-dialog/afm-jira/tsconfig.json"
82
82
  },
83
+ {
84
+ "path": "../../../platform/feature-flags/afm-jira/tsconfig.json"
85
+ },
83
86
  {
84
87
  "path": "../../../design-system/primitives/afm-jira/tsconfig.json"
85
88
  },
@@ -80,6 +80,9 @@
80
80
  {
81
81
  "path": "../../../design-system/modal-dialog/afm-products/tsconfig.json"
82
82
  },
83
+ {
84
+ "path": "../../../platform/feature-flags/afm-products/tsconfig.json"
85
+ },
83
86
  {
84
87
  "path": "../../../design-system/primitives/afm-products/tsconfig.json"
85
88
  },
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.syncBlockNodeView = void 0;
7
+ exports.syncBlockNodeView = exports.SyncBlock = void 0;
8
8
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
9
9
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
10
10
  var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
@@ -15,17 +15,19 @@ var _react = _interopRequireDefault(require("react"));
15
15
  var _reactNodeView = _interopRequireDefault(require("@atlaskit/editor-common/react-node-view"));
16
16
  var _syncBlock = require("@atlaskit/editor-common/sync-block");
17
17
  var _editorSyncedBlockProvider = require("@atlaskit/editor-synced-block-provider");
18
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
18
19
  var _SyncBlockRendererWrapper = require("../ui/SyncBlockRendererWrapper");
19
20
  function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
20
21
  function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
21
22
  function _superPropGet(t, o, e, r) { var p = (0, _get2.default)((0, _getPrototypeOf2.default)(1 & r ? t.prototype : t), o, e); return 2 & r && "function" == typeof p ? function (t) { return p.apply(e, t); } : p; }
22
- var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
23
+ var SyncBlock = exports.SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
23
24
  function SyncBlock(props) {
24
25
  var _this;
25
26
  (0, _classCallCheck2.default)(this, SyncBlock);
26
27
  _this = _callSuper(this, SyncBlock, [props.node, props.view, props.getPos, props.portalProviderAPI, props.eventDispatcher, props]);
27
28
  _this.options = props.options;
28
29
  _this.api = props.api;
30
+ _this.syncBlockStore = props.syncBlockStore;
29
31
  return _this;
30
32
  }
31
33
  (0, _inherits2.default)(SyncBlock, _ReactNodeView);
@@ -40,6 +42,7 @@ var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
40
42
  key: "render",
41
43
  value: function render() {
42
44
  var _this$options,
45
+ _this$api$syncedBlock,
43
46
  _this$api,
44
47
  _this$options2,
45
48
  _this2 = this;
@@ -52,7 +55,8 @@ var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
52
55
  if (!resourceId || !localId) {
53
56
  return null;
54
57
  }
55
- var syncBlockStore = (_this$api = this.api) === null || _this$api === void 0 || (_this$api = _this$api.syncedBlock) === null || _this$api === void 0 || (_this$api = _this$api.sharedState.currentState()) === null || _this$api === void 0 ? void 0 : _this$api.syncBlockStore;
58
+ var initialSyncBlockStore = (0, _platformFeatureFlags.fg)('platform_synced_block_dogfooding') ? this.syncBlockStore : undefined;
59
+ var syncBlockStore = (_this$api$syncedBlock = (_this$api = this.api) === null || _this$api === void 0 || (_this$api = _this$api.syncedBlock) === null || _this$api === void 0 || (_this$api = _this$api.sharedState.currentState()) === null || _this$api === void 0 ? void 0 : _this$api.syncBlockStore) !== null && _this$api$syncedBlock !== void 0 ? _this$api$syncedBlock : initialSyncBlockStore;
56
60
  if (!syncBlockStore) {
57
61
  return null;
58
62
  }
@@ -14,8 +14,10 @@ var _editorPluginConnectivity = require("@atlaskit/editor-plugin-connectivity");
14
14
  var _state = require("@atlaskit/editor-prosemirror/state");
15
15
  var _view = require("@atlaskit/editor-prosemirror/view");
16
16
  var _editorSyncedBlockProvider = require("@atlaskit/editor-synced-block-provider");
17
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
17
18
  var _bodiedLazySyncedBlock = require("../nodeviews/bodiedLazySyncedBlock");
18
19
  var _lazySyncedBlock = require("../nodeviews/lazySyncedBlock");
20
+ var _syncedBlock = require("../nodeviews/syncedBlock");
19
21
  var _types = require("../types");
20
22
  var _handleBodiedSyncBlockRemoval = require("./utils/handle-bodied-sync-block-removal");
21
23
  var _ignoreDomEvent = require("./utils/ignore-dom-event");
@@ -84,7 +86,22 @@ var createPlugin = exports.createPlugin = function createPlugin(options, pmPlugi
84
86
  },
85
87
  props: {
86
88
  nodeViews: {
87
- syncBlock: (0, _lazySyncedBlock.lazySyncBlockView)({
89
+ syncBlock: (0, _platformFeatureFlags.fg)('platform_synced_block_dogfooding') ? function (node, view, getPos, _decorations) {
90
+ // To support SSR, pass `syncBlockStore` here
91
+ // and do not use lazy loading.
92
+ // We cannot start rendering and then load `syncBlockStore` asynchronously,
93
+ // because obtaining it is asynchronous (sharedPluginState.currentState() is delayed).
94
+ return new _syncedBlock.SyncBlock({
95
+ api: api,
96
+ options: options,
97
+ node: node,
98
+ view: view,
99
+ getPos: getPos,
100
+ portalProviderAPI: pmPluginFactoryParams.portalProviderAPI,
101
+ eventDispatcher: pmPluginFactoryParams.eventDispatcher,
102
+ syncBlockStore: syncBlockStore
103
+ }).init();
104
+ } : (0, _lazySyncedBlock.lazySyncBlockView)({
88
105
  options: options,
89
106
  pmPluginFactoryParams: pmPluginFactoryParams,
90
107
  api: api
@@ -2,12 +2,14 @@ import React from 'react';
2
2
  import ReactNodeView from '@atlaskit/editor-common/react-node-view';
3
3
  import { SyncBlockSharedCssClassName } from '@atlaskit/editor-common/sync-block';
4
4
  import { useFetchSyncBlockData, useFetchSyncBlockTitle } from '@atlaskit/editor-synced-block-provider';
5
+ import { fg } from '@atlaskit/platform-feature-flags';
5
6
  import { SyncBlockRendererWrapper } from '../ui/SyncBlockRendererWrapper';
6
- class SyncBlock extends ReactNodeView {
7
+ export class SyncBlock extends ReactNodeView {
7
8
  constructor(props) {
8
9
  super(props.node, props.view, props.getPos, props.portalProviderAPI, props.eventDispatcher, props);
9
10
  this.options = props.options;
10
11
  this.api = props.api;
12
+ this.syncBlockStore = props.syncBlockStore;
11
13
  }
12
14
  createDomRef() {
13
15
  const domRef = document.createElement('div');
@@ -15,7 +17,7 @@ class SyncBlock extends ReactNodeView {
15
17
  return domRef;
16
18
  }
17
19
  render() {
18
- var _this$options, _this$api, _this$api$syncedBlock, _this$api$syncedBlock2, _this$options2;
20
+ var _this$options, _this$api$syncedBlock, _this$api, _this$api$syncedBlock2, _this$api$syncedBlock3, _this$options2;
19
21
  if (!((_this$options = this.options) !== null && _this$options !== void 0 && _this$options.syncedBlockRenderer)) {
20
22
  return null;
21
23
  }
@@ -26,7 +28,8 @@ class SyncBlock extends ReactNodeView {
26
28
  if (!resourceId || !localId) {
27
29
  return null;
28
30
  }
29
- const syncBlockStore = (_this$api = this.api) === null || _this$api === void 0 ? void 0 : (_this$api$syncedBlock = _this$api.syncedBlock) === null || _this$api$syncedBlock === void 0 ? void 0 : (_this$api$syncedBlock2 = _this$api$syncedBlock.sharedState.currentState()) === null || _this$api$syncedBlock2 === void 0 ? void 0 : _this$api$syncedBlock2.syncBlockStore;
31
+ const initialSyncBlockStore = fg('platform_synced_block_dogfooding') ? this.syncBlockStore : undefined;
32
+ const syncBlockStore = (_this$api$syncedBlock = (_this$api = this.api) === null || _this$api === void 0 ? void 0 : (_this$api$syncedBlock2 = _this$api.syncedBlock) === null || _this$api$syncedBlock2 === void 0 ? void 0 : (_this$api$syncedBlock3 = _this$api$syncedBlock2.sharedState.currentState()) === null || _this$api$syncedBlock3 === void 0 ? void 0 : _this$api$syncedBlock3.syncBlockStore) !== null && _this$api$syncedBlock !== void 0 ? _this$api$syncedBlock : initialSyncBlockStore;
30
33
  if (!syncBlockStore) {
31
34
  return null;
32
35
  }
@@ -6,8 +6,10 @@ import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity';
6
6
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
7
7
  import { DecorationSet, Decoration } from '@atlaskit/editor-prosemirror/view';
8
8
  import { convertPMNodesToSyncBlockNodes, rebaseTransaction } from '@atlaskit/editor-synced-block-provider';
9
+ import { fg } from '@atlaskit/platform-feature-flags';
9
10
  import { lazyBodiedSyncBlockView } from '../nodeviews/bodiedLazySyncedBlock';
10
11
  import { lazySyncBlockView } from '../nodeviews/lazySyncedBlock';
12
+ import { SyncBlock as SyncBlockView } from '../nodeviews/syncedBlock';
11
13
  import { FLAG_ID } from '../types';
12
14
  import { handleBodiedSyncBlockRemoval } from './utils/handle-bodied-sync-block-removal';
13
15
  import { shouldIgnoreDomEvent } from './utils/ignore-dom-event';
@@ -72,7 +74,22 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
72
74
  },
73
75
  props: {
74
76
  nodeViews: {
75
- syncBlock: lazySyncBlockView({
77
+ syncBlock: fg('platform_synced_block_dogfooding') ? (node, view, getPos, _decorations) => {
78
+ // To support SSR, pass `syncBlockStore` here
79
+ // and do not use lazy loading.
80
+ // We cannot start rendering and then load `syncBlockStore` asynchronously,
81
+ // because obtaining it is asynchronous (sharedPluginState.currentState() is delayed).
82
+ return new SyncBlockView({
83
+ api,
84
+ options,
85
+ node,
86
+ view,
87
+ getPos,
88
+ portalProviderAPI: pmPluginFactoryParams.portalProviderAPI,
89
+ eventDispatcher: pmPluginFactoryParams.eventDispatcher,
90
+ syncBlockStore: syncBlockStore
91
+ }).init();
92
+ } : lazySyncBlockView({
76
93
  options,
77
94
  pmPluginFactoryParams,
78
95
  api
@@ -11,14 +11,16 @@ import React from 'react';
11
11
  import ReactNodeView from '@atlaskit/editor-common/react-node-view';
12
12
  import { SyncBlockSharedCssClassName } from '@atlaskit/editor-common/sync-block';
13
13
  import { useFetchSyncBlockData as _useFetchSyncBlockData, useFetchSyncBlockTitle as _useFetchSyncBlockTitle } from '@atlaskit/editor-synced-block-provider';
14
+ import { fg } from '@atlaskit/platform-feature-flags';
14
15
  import { SyncBlockRendererWrapper } from '../ui/SyncBlockRendererWrapper';
15
- var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
16
+ export var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
16
17
  function SyncBlock(props) {
17
18
  var _this;
18
19
  _classCallCheck(this, SyncBlock);
19
20
  _this = _callSuper(this, SyncBlock, [props.node, props.view, props.getPos, props.portalProviderAPI, props.eventDispatcher, props]);
20
21
  _this.options = props.options;
21
22
  _this.api = props.api;
23
+ _this.syncBlockStore = props.syncBlockStore;
22
24
  return _this;
23
25
  }
24
26
  _inherits(SyncBlock, _ReactNodeView);
@@ -33,6 +35,7 @@ var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
33
35
  key: "render",
34
36
  value: function render() {
35
37
  var _this$options,
38
+ _this$api$syncedBlock,
36
39
  _this$api,
37
40
  _this$options2,
38
41
  _this2 = this;
@@ -45,7 +48,8 @@ var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
45
48
  if (!resourceId || !localId) {
46
49
  return null;
47
50
  }
48
- var syncBlockStore = (_this$api = this.api) === null || _this$api === void 0 || (_this$api = _this$api.syncedBlock) === null || _this$api === void 0 || (_this$api = _this$api.sharedState.currentState()) === null || _this$api === void 0 ? void 0 : _this$api.syncBlockStore;
51
+ var initialSyncBlockStore = fg('platform_synced_block_dogfooding') ? this.syncBlockStore : undefined;
52
+ var syncBlockStore = (_this$api$syncedBlock = (_this$api = this.api) === null || _this$api === void 0 || (_this$api = _this$api.syncedBlock) === null || _this$api === void 0 || (_this$api = _this$api.sharedState.currentState()) === null || _this$api === void 0 ? void 0 : _this$api.syncBlockStore) !== null && _this$api$syncedBlock !== void 0 ? _this$api$syncedBlock : initialSyncBlockStore;
49
53
  if (!syncBlockStore) {
50
54
  return null;
51
55
  }
@@ -12,8 +12,10 @@ import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity';
12
12
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
13
13
  import { DecorationSet, Decoration } from '@atlaskit/editor-prosemirror/view';
14
14
  import { convertPMNodesToSyncBlockNodes, rebaseTransaction } from '@atlaskit/editor-synced-block-provider';
15
+ import { fg } from '@atlaskit/platform-feature-flags';
15
16
  import { lazyBodiedSyncBlockView } from '../nodeviews/bodiedLazySyncedBlock';
16
17
  import { lazySyncBlockView } from '../nodeviews/lazySyncedBlock';
18
+ import { SyncBlock as SyncBlockView } from '../nodeviews/syncedBlock';
17
19
  import { FLAG_ID } from '../types';
18
20
  import { handleBodiedSyncBlockRemoval } from './utils/handle-bodied-sync-block-removal';
19
21
  import { shouldIgnoreDomEvent } from './utils/ignore-dom-event';
@@ -77,7 +79,22 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
77
79
  },
78
80
  props: {
79
81
  nodeViews: {
80
- syncBlock: lazySyncBlockView({
82
+ syncBlock: fg('platform_synced_block_dogfooding') ? function (node, view, getPos, _decorations) {
83
+ // To support SSR, pass `syncBlockStore` here
84
+ // and do not use lazy loading.
85
+ // We cannot start rendering and then load `syncBlockStore` asynchronously,
86
+ // because obtaining it is asynchronous (sharedPluginState.currentState() is delayed).
87
+ return new SyncBlockView({
88
+ api: api,
89
+ options: options,
90
+ node: node,
91
+ view: view,
92
+ getPos: getPos,
93
+ portalProviderAPI: pmPluginFactoryParams.portalProviderAPI,
94
+ eventDispatcher: pmPluginFactoryParams.eventDispatcher,
95
+ syncBlockStore: syncBlockStore
96
+ }).init();
97
+ } : lazySyncBlockView({
81
98
  options: options,
82
99
  pmPluginFactoryParams: pmPluginFactoryParams,
83
100
  api: api
@@ -1,3 +1,4 @@
1
+ import React from 'react';
1
2
  import type { EventDispatcher } from '@atlaskit/editor-common/event-dispatcher';
2
3
  import type { PortalProviderAPI } from '@atlaskit/editor-common/portal';
3
4
  import ReactNodeView, { type getPosHandler } from '@atlaskit/editor-common/react-node-view';
@@ -5,6 +6,7 @@ import type { ReactComponentProps } from '@atlaskit/editor-common/react-node-vie
5
6
  import type { ExtractInjectionAPI, PMPluginFactoryParams } from '@atlaskit/editor-common/types';
6
7
  import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
7
8
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
9
+ import { type SyncBlockStoreManager } from '@atlaskit/editor-synced-block-provider';
8
10
  import type { SyncedBlockPlugin, SyncedBlockPluginOptions } from '../syncedBlockPluginType';
9
11
  export interface SyncBlockNodeViewProps extends ReactComponentProps {
10
12
  api?: ExtractInjectionAPI<SyncedBlockPlugin>;
@@ -14,8 +16,19 @@ export interface SyncBlockNodeViewProps extends ReactComponentProps {
14
16
  node: PMNode;
15
17
  options: SyncedBlockPluginOptions | undefined;
16
18
  portalProviderAPI: PortalProviderAPI;
19
+ syncBlockStore?: SyncBlockStoreManager;
17
20
  view: EditorView;
18
21
  }
22
+ export declare class SyncBlock extends ReactNodeView<SyncBlockNodeViewProps> {
23
+ private options;
24
+ private api?;
25
+ private syncBlockStore?;
26
+ constructor(props: SyncBlockNodeViewProps);
27
+ unsubscribe: (() => void) | undefined;
28
+ createDomRef(): HTMLElement;
29
+ render(): React.JSX.Element | null;
30
+ destroy(): void;
31
+ }
19
32
  export interface SyncBlockNodeViewProperties {
20
33
  api?: ExtractInjectionAPI<SyncedBlockPlugin>;
21
34
  options: SyncedBlockPluginOptions | undefined;
@@ -1,3 +1,4 @@
1
+ import React from 'react';
1
2
  import type { EventDispatcher } from '@atlaskit/editor-common/event-dispatcher';
2
3
  import type { PortalProviderAPI } from '@atlaskit/editor-common/portal';
3
4
  import ReactNodeView, { type getPosHandler } from '@atlaskit/editor-common/react-node-view';
@@ -5,6 +6,7 @@ import type { ReactComponentProps } from '@atlaskit/editor-common/react-node-vie
5
6
  import type { ExtractInjectionAPI, PMPluginFactoryParams } from '@atlaskit/editor-common/types';
6
7
  import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
7
8
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
9
+ import { type SyncBlockStoreManager } from '@atlaskit/editor-synced-block-provider';
8
10
  import type { SyncedBlockPlugin, SyncedBlockPluginOptions } from '../syncedBlockPluginType';
9
11
  export interface SyncBlockNodeViewProps extends ReactComponentProps {
10
12
  api?: ExtractInjectionAPI<SyncedBlockPlugin>;
@@ -14,8 +16,19 @@ export interface SyncBlockNodeViewProps extends ReactComponentProps {
14
16
  node: PMNode;
15
17
  options: SyncedBlockPluginOptions | undefined;
16
18
  portalProviderAPI: PortalProviderAPI;
19
+ syncBlockStore?: SyncBlockStoreManager;
17
20
  view: EditorView;
18
21
  }
22
+ export declare class SyncBlock extends ReactNodeView<SyncBlockNodeViewProps> {
23
+ private options;
24
+ private api?;
25
+ private syncBlockStore?;
26
+ constructor(props: SyncBlockNodeViewProps);
27
+ unsubscribe: (() => void) | undefined;
28
+ createDomRef(): HTMLElement;
29
+ render(): React.JSX.Element | null;
30
+ destroy(): void;
31
+ }
19
32
  export interface SyncBlockNodeViewProperties {
20
33
  api?: ExtractInjectionAPI<SyncedBlockPlugin>;
21
34
  options: SyncedBlockPluginOptions | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-synced-block",
3
- "version": "5.0.0",
3
+ "version": "5.1.0",
4
4
  "description": "SyncedBlock plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -39,7 +39,7 @@
39
39
  "@atlaskit/editor-plugin-selection": "^7.0.0",
40
40
  "@atlaskit/editor-prosemirror": "^7.2.0",
41
41
  "@atlaskit/editor-shared-styles": "^3.10.0",
42
- "@atlaskit/editor-synced-block-provider": "^3.0.0",
42
+ "@atlaskit/editor-synced-block-provider": "^3.3.0",
43
43
  "@atlaskit/editor-tables": "^2.9.0",
44
44
  "@atlaskit/editor-toolbar": "^0.18.0",
45
45
  "@atlaskit/flag": "^17.7.0",
@@ -47,6 +47,7 @@
47
47
  "@atlaskit/icon-lab": "^5.13.0",
48
48
  "@atlaskit/lozenge": "^13.3.0",
49
49
  "@atlaskit/modal-dialog": "^14.9.0",
50
+ "@atlaskit/platform-feature-flags": "^1.1.0",
50
51
  "@atlaskit/primitives": "^17.0.0",
51
52
  "@atlaskit/tmp-editor-statsig": "^16.3.0",
52
53
  "@atlaskit/tokens": "9.0.0",
@@ -97,5 +98,10 @@
97
98
  "import-no-extraneous-disable-for-examples-and-docs"
98
99
  ]
99
100
  }
101
+ },
102
+ "platform-feature-flags": {
103
+ "platform_synced_block_dogfooding": {
104
+ "type": "boolean"
105
+ }
100
106
  }
101
107
  }