@typeonce/effect-machine-devtools 0.31.1 → 0.32.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 (33) hide show
  1. package/dist/MachineRegistry.d.ts +4 -3
  2. package/dist/MachineRegistry.d.ts.map +1 -1
  3. package/dist/MachineRegistry.js +4 -3
  4. package/dist/MachineRegistry.js.map +1 -1
  5. package/dist/client/assets/index-2uvShdlX.js +37 -0
  6. package/dist/client/index.html +1 -1
  7. package/dist/internal/devServer.d.ts +3 -1
  8. package/dist/internal/devServer.d.ts.map +1 -1
  9. package/dist/internal/devServer.js +8 -6
  10. package/dist/internal/devServer.js.map +1 -1
  11. package/dist/internal/machineRegistry.js +9 -6
  12. package/dist/internal/machineRegistry.js.map +1 -1
  13. package/package.json +2 -2
  14. package/src/MachineRegistry.ts +4 -3
  15. package/src/internal/browser/chart-layout-policy.ts +2 -2
  16. package/src/internal/browser/chart-layout.ts +236 -51
  17. package/src/internal/browser/chart-model.ts +3 -0
  18. package/src/internal/browser/chart-renderer.ts +5 -4
  19. package/src/internal/browser/example-machine.ts +94 -85
  20. package/src/internal/browser/hierarchy-routing-example.ts +67 -58
  21. package/src/internal/browser/invoke-outcomes-example.ts +153 -143
  22. package/src/internal/browser/layout-resilience-example.ts +115 -104
  23. package/src/internal/browser/parallel-completion-example.ts +117 -107
  24. package/src/internal/browser/parallel-owner-routing-example.ts +104 -0
  25. package/src/internal/browser/planner-example.ts +44 -38
  26. package/src/internal/browser/protocol-events-example.ts +123 -102
  27. package/src/internal/browser/shared-terminal-routing-example.ts +125 -120
  28. package/src/internal/browser/text-tree.ts +2 -2
  29. package/src/internal/browser/transition-semantics-example.ts +143 -131
  30. package/src/internal/browser/visualizer-model.ts +7 -7
  31. package/src/internal/devServer.ts +15 -12
  32. package/src/internal/machineRegistry.ts +17 -17
  33. package/dist/client/assets/index-CSgOYHLh.js +0 -37
@@ -9,27 +9,33 @@ class ChildDone extends Schema.TaggedClass<ChildDone>("InvokeGalleryChildDone")(
9
9
  }) {}
10
10
  class FinishChild extends Schema.TaggedClass<FinishChild>("InvokeGalleryFinishChild")("FinishChild", {}) {}
11
11
 
12
- const ChildStates = Machine.states({
13
- Working: ChildWorking,
14
- Done: { schema: ChildDone, type: "final", output: Schema.String }
12
+ const ChildStates = Machine.state({
13
+ initial: "Working",
14
+ states: {
15
+ Working: ChildWorking,
16
+ Done: { schema: ChildDone, type: "final", output: Schema.String }
17
+ }
15
18
  })
16
19
 
17
20
  export const invokeGalleryChildMachine = Machine.make({
18
21
  id: "invoke-gallery-child",
19
- states: ChildStates.states,
20
- events: Machine.events(FinishChild),
21
- initial: (to) => to.Working().resolve(({ target }) => target.decoded(new ChildWorking({ task: "render-preview" })))
22
+ root: ChildStates,
23
+ events: Machine.eventsFromSchemas(FinishChild),
24
+ initialConfiguration: (root) =>
25
+ root.resolve(({ target }) => target.from((to) => to.Working.decoded(new ChildWorking({ task: "render-preview" }))))
22
26
  }).handle({
23
- Working: {
24
- on: {
25
- FinishChild: (to) =>
26
- to.full.Done().resolve(({ state, target }) =>
27
- target.decoded(new ChildDone({ result: `${state.task}:complete` }))
28
- )
27
+ states: {
28
+ Working: {
29
+ on: {
30
+ FinishChild: (to) =>
31
+ to.branch.Done().resolve(({ state, target }) =>
32
+ target.decoded(new ChildDone({ result: `${state.task}:complete` }))
33
+ )
34
+ }
35
+ },
36
+ Done: {
37
+ output: ({ state }) => state.result
29
38
  }
30
- },
31
- Done: {
32
- output: ({ state }) => state.result
33
39
  }
34
40
  })
35
41
 
@@ -77,155 +83,159 @@ class StreamValue extends Schema.TaggedClass<StreamValue>("InvokeGalleryStreamVa
77
83
  value: Schema.Number
78
84
  }) {}
79
85
 
80
- const GalleryEvents = Machine.events(RunEffect, RunStream, RunTimer, RunProcess, RunChild, Reset)
81
- const GalleryInternalEvents = Machine.internalEvents(StreamValue)
86
+ const GalleryEvents = Machine.eventsFromSchemas(RunEffect, RunStream, RunTimer, RunProcess, RunChild, Reset)
87
+ const GalleryInternalEvents = Machine.internalEventsFromSchemas(StreamValue)
82
88
  const processLogic = Machine.logic({
83
89
  initial: "starting" as "starting" | "ready",
84
90
  run: () => Effect.fail("process stopped")
85
91
  })
86
92
 
87
- const GalleryStates = Machine.states({
88
- Gallery: {
89
- schema: Gallery,
90
- initial: "Choose",
91
- states: {
92
- Choose,
93
- LoadingDocument,
94
- StreamingUpdates,
95
- WaitingForTimeout,
96
- WatchingProcess,
97
- RunningChild
98
- }
99
- },
100
- Completed,
101
- Failed
93
+ const GalleryStates = Machine.state({
94
+ initial: "Gallery",
95
+ states: {
96
+ Gallery: {
97
+ schema: Gallery,
98
+ initial: "Choose",
99
+ states: {
100
+ Choose,
101
+ LoadingDocument,
102
+ StreamingUpdates,
103
+ WaitingForTimeout,
104
+ WatchingProcess,
105
+ RunningChild
106
+ }
107
+ },
108
+ Completed,
109
+ Failed
110
+ }
102
111
  })
103
112
 
104
113
  export const invokeOutcomesMachine = Machine.make({
105
114
  id: "invoke-outcomes",
106
- states: GalleryStates.states,
115
+ root: GalleryStates,
107
116
  events: GalleryEvents,
108
117
  internalEvents: GalleryInternalEvents,
109
- initial: (to) =>
110
- to.Gallery.initial.resolve(({ target }) =>
111
- target.decoded(
112
- new Gallery({ selectedDemo: null }),
113
- (gallery) => gallery.Choose.decoded(new Choose({}))
118
+ initialConfiguration: (root) =>
119
+ root.resolve(({ target }) =>
120
+ target.from((to) =>
121
+ to.Gallery.decoded(new Gallery({ selectedDemo: null }), (gallery) => gallery.Choose.decoded(new Choose({})))
114
122
  )
115
123
  )
116
124
  }).handle({
117
- Gallery: {
118
- initialize: ({ builder }) => builder.decoded(new Choose({})),
119
- on: {
120
- Reset: (to) => to.local.Choose().resolve(({ target }) => target.decoded(new Choose({})))
121
- },
122
- states: {
123
- Choose: {
124
- on: {
125
- RunEffect: (to) =>
126
- to.local.LoadingDocument().resolve(({ event, target }) =>
127
- target.decoded(new LoadingDocument({ request: event.request }))
128
- ),
129
- RunStream: (to) =>
130
- to.local.StreamingUpdates().resolve(({ target }) => target.decoded(new StreamingUpdates({ values: [] }))),
131
- RunTimer: (to) =>
132
- to.local.WaitingForTimeout().resolve(({ target }) =>
133
- target.decoded(new WaitingForTimeout({ delay: "2 seconds" }))
134
- ),
135
- RunProcess: (to) =>
136
- to.local.WatchingProcess().resolve(({ target }) => target.decoded(new WatchingProcess({ revision: 1 }))),
137
- RunChild: (to) => to.local.RunningChild().resolve(({ target }) => target.decoded(new RunningChild({})))
138
- }
125
+ states: {
126
+ Gallery: {
127
+ initialize: ({ builder }) => builder.decoded(new Choose({})),
128
+ on: {
129
+ Reset: (to) => to.local.Choose().resolve(({ target }) => target.decoded(new Choose({})))
139
130
  },
140
- LoadingDocument: {
141
- invoke: (from) =>
142
- from.effect(
143
- "load-document",
144
- ({ state }) =>
145
- state.request === "fail" ? Effect.fail("document unavailable") : Effect.succeed("document loaded")
146
- ).onDone((to) =>
147
- to.full.Completed().resolve(({ output, target }) =>
148
- target.decoded(new Completed({ source: "effect", result: output }))
131
+ states: {
132
+ Choose: {
133
+ on: {
134
+ RunEffect: (to) =>
135
+ to.local.LoadingDocument().resolve(({ event, target }) =>
136
+ target.decoded(new LoadingDocument({ request: event.request }))
137
+ ),
138
+ RunStream: (to) =>
139
+ to.local.StreamingUpdates().resolve(({ target }) => target.decoded(new StreamingUpdates({ values: [] }))),
140
+ RunTimer: (to) =>
141
+ to.local.WaitingForTimeout().resolve(({ target }) =>
142
+ target.decoded(new WaitingForTimeout({ delay: "2 seconds" }))
143
+ ),
144
+ RunProcess: (to) =>
145
+ to.local.WatchingProcess().resolve(({ target }) => target.decoded(new WatchingProcess({ revision: 1 }))),
146
+ RunChild: (to) => to.local.RunningChild().resolve(({ target }) => target.decoded(new RunningChild({})))
147
+ }
148
+ },
149
+ LoadingDocument: {
150
+ invoke: (from) =>
151
+ from.effect(
152
+ "load-document",
153
+ ({ state }) =>
154
+ state.request === "fail" ? Effect.fail("document unavailable") : Effect.succeed("document loaded")
155
+ ).onDone((to) =>
156
+ to.branch.Completed().resolve(({ output, target }) =>
157
+ target.decoded(new Completed({ source: "effect", result: output }))
158
+ )
159
+ ).onFailure((to) =>
160
+ to.branch.Failed().resolve(({ error, target }) =>
161
+ target.decoded(new Failed({ source: "effect", message: error }))
162
+ )
149
163
  )
150
- ).onFailure((to) =>
151
- to.full.Failed().resolve(({ error, target }) =>
152
- target.decoded(new Failed({ source: "effect", message: error }))
153
- )
154
- )
155
- },
156
- StreamingUpdates: {
157
- invoke: (from) =>
158
- from.stream(
159
- "document-updates",
160
- () => Stream.fromIterable([1, 2, 3]).pipe(Stream.concat(Stream.fail("stream disconnected")))
161
- ).onElement((to) =>
162
- to.none.resolve(({ element }, enqueue) => {
163
- enqueue.raise(GalleryInternalEvents.StreamValue({ value: element }))
164
- })
165
- ).onDone((to) =>
166
- to.full.Completed().resolve(({ state, target }) =>
167
- target.decoded(new Completed({ source: "stream", result: state.values.join(", ") }))
164
+ },
165
+ StreamingUpdates: {
166
+ invoke: (from) =>
167
+ from.stream(
168
+ "document-updates",
169
+ () => Stream.fromIterable([1, 2, 3]).pipe(Stream.concat(Stream.fail("stream disconnected")))
170
+ ).onElement((to) =>
171
+ to.none.resolve(({ element }, enqueue) => {
172
+ enqueue.raise(GalleryInternalEvents.StreamValue({ value: element }))
173
+ })
174
+ ).onDone((to) =>
175
+ to.branch.Completed().resolve(({ state, target }) =>
176
+ target.decoded(new Completed({ source: "stream", result: state.values.join(", ") }))
177
+ )
178
+ ).onFailure((to) =>
179
+ to.branch.Failed().resolve(({ error, target }) =>
180
+ target.decoded(new Failed({ source: "stream", message: error }))
181
+ )
182
+ ),
183
+ on: {
184
+ StreamValue: (to) =>
185
+ to.local.StreamingUpdates().resolve(({ event, state, target }) =>
186
+ target.decoded(new StreamingUpdates({ values: [...state.values, event.value] }))
187
+ )
188
+ }
189
+ },
190
+ WaitingForTimeout: {
191
+ invoke: (from) =>
192
+ from.timer("request-timeout", "2 seconds").onDone((to) =>
193
+ to.branch.Completed().resolve(({ target }) =>
194
+ target.decoded(new Completed({ source: "timer", result: "timeout elapsed" }))
195
+ )
168
196
  )
169
- ).onFailure((to) =>
170
- to.full.Failed().resolve(({ error, target }) =>
171
- target.decoded(new Failed({ source: "stream", message: error }))
197
+ },
198
+ WatchingProcess: {
199
+ invoke: (from) =>
200
+ from.logic("status-worker", {
201
+ address: Machine.childAddress("status-worker"),
202
+ logic: processLogic
203
+ }).onFailure((to) =>
204
+ to.branch.Failed().resolve(({ error, target }) =>
205
+ target.decoded(new Failed({ source: "process", message: String(error) }))
206
+ )
207
+ ).onSnapshot((to) =>
208
+ to.branches({
209
+ ready: { title: "Worker reports ready", target: to.branch.Completed() },
210
+ waiting: { title: "Worker is still starting", target: to.none }
211
+ }).resolve(({ select, snapshot }) =>
212
+ snapshot.state === "ready"
213
+ ? select.ready.decoded(new Completed({ source: "process", result: "ready" }))
214
+ : select.waiting()
215
+ )
172
216
  )
173
- ),
174
- on: {
175
- StreamValue: (to) =>
176
- to.local.StreamingUpdates().resolve(({ event, state, target }) =>
177
- target.decoded(new StreamingUpdates({ values: [...state.values, event.value] }))
217
+ },
218
+ RunningChild: {
219
+ invoke: (from) =>
220
+ from.child(InvokedChild).onDone((to) =>
221
+ to.branch.Completed().resolve(({ output, target }) =>
222
+ target.decoded(new Completed({ source: "child machine", result: output }))
223
+ )
178
224
  )
179
225
  }
180
- },
181
- WaitingForTimeout: {
182
- invoke: (from) =>
183
- from.timer("request-timeout", "2 seconds").onDone((to) =>
184
- to.full.Completed().resolve(({ target }) =>
185
- target.decoded(new Completed({ source: "timer", result: "timeout elapsed" }))
186
- )
187
- )
188
- },
189
- WatchingProcess: {
190
- invoke: (from) =>
191
- from.logic("status-worker", {
192
- address: Machine.childAddress("status-worker"),
193
- logic: processLogic
194
- }).onFailure((to) =>
195
- to.full.Failed().resolve(({ error, target }) =>
196
- target.decoded(new Failed({ source: "process", message: String(error) }))
197
- )
198
- ).onSnapshot((to) =>
199
- to.branches({
200
- ready: { title: "Worker reports ready", target: to.full.Completed() },
201
- waiting: { title: "Worker is still starting", target: to.none }
202
- }).resolve(({ select, snapshot }) =>
203
- snapshot.state === "ready"
204
- ? select.ready.decoded(new Completed({ source: "process", result: "ready" }))
205
- : select.waiting()
206
- )
207
- )
208
- },
209
- RunningChild: {
210
- invoke: (from) =>
211
- from.child(InvokedChild).onDone((to) =>
212
- to.full.Completed().resolve(({ output, target }) =>
213
- target.decoded(new Completed({ source: "child machine", result: output }))
214
- )
215
- )
216
226
  }
217
- }
218
- },
219
- Completed: {
220
- on: {
221
- Reset: (to) =>
222
- to.full.Gallery.initial.resolve(({ target }) => target.decoded(new Gallery({ selectedDemo: null })))
223
- }
224
- },
225
- Failed: {
226
- on: {
227
- Reset: (to) =>
228
- to.full.Gallery.initial.resolve(({ target }) => target.decoded(new Gallery({ selectedDemo: null })))
227
+ },
228
+ Completed: {
229
+ on: {
230
+ Reset: (to) =>
231
+ to.branch.Gallery.initial.resolve(({ target }) => target.decoded(new Gallery({ selectedDemo: null })))
232
+ }
233
+ },
234
+ Failed: {
235
+ on: {
236
+ Reset: (to) =>
237
+ to.branch.Gallery.initial.resolve(({ target }) => target.decoded(new Gallery({ selectedDemo: null })))
238
+ }
229
239
  }
230
240
  }
231
241
  })
@@ -20,33 +20,36 @@ const AuthState = Schema.TaggedUnion({
20
20
  Navigating: { href: Schema.String }
21
21
  })
22
22
 
23
- const AuthStates = Machine.states({
24
- Editing: {
25
- schema: AuthState.cases.Editing,
26
- initial: "Form",
27
- states: {
28
- Form: {
29
- initial: "Ready",
30
- states: {
31
- Ready: {},
32
- Failed: AuthState.cases.EditingFailed
33
- }
34
- },
35
- SubmittingLogin: {},
36
- RequestingVerification: {}
37
- }
38
- },
39
- Verification: {
40
- schema: AuthState.cases.Verification,
41
- initial: "CodeEntry",
42
- states: {
43
- CodeEntry: {}
44
- }
45
- },
46
- Navigating: AuthState.cases.Navigating
23
+ const AuthStates = Machine.state({
24
+ initial: "Editing",
25
+ states: {
26
+ Editing: {
27
+ schema: AuthState.cases.Editing,
28
+ initial: "Form",
29
+ states: {
30
+ Form: {
31
+ initial: "Ready",
32
+ states: {
33
+ Ready: {},
34
+ Failed: AuthState.cases.EditingFailed
35
+ }
36
+ },
37
+ SubmittingLogin: {},
38
+ RequestingVerification: {}
39
+ }
40
+ },
41
+ Verification: {
42
+ schema: AuthState.cases.Verification,
43
+ initial: "CodeEntry",
44
+ states: {
45
+ CodeEntry: {}
46
+ }
47
+ },
48
+ Navigating: AuthState.cases.Navigating
49
+ }
47
50
  })
48
51
 
49
- const AuthEvents = Machine.events(
52
+ const AuthEvents = Machine.eventsFromSchemas(
50
53
  Schema.TaggedUnion({
51
54
  EmailChanged: { value: Schema.String },
52
55
  LoginMethodChanged: { value: LoginMethod },
@@ -57,89 +60,97 @@ const AuthEvents = Machine.events(
57
60
 
58
61
  export const layoutResilienceMachine = Machine.make({
59
62
  id: "layout-resilience",
60
- states: AuthStates.states,
63
+ root: AuthStates,
61
64
  events: AuthEvents,
62
- initial: (to) =>
63
- to.Editing.initial.resolve(({ target }) =>
64
- target.from({
65
- mode: "login",
66
- email: "",
67
- loginMethod: "code",
68
- password: ""
69
- }, (editing) => editing.Form.from((form) => form.Ready.from()))
65
+ initialConfiguration: (root) =>
66
+ root.resolve(({ target }) =>
67
+ target.from((to) =>
68
+ to.Editing.from({
69
+ mode: "login",
70
+ email: "",
71
+ loginMethod: "code",
72
+ password: ""
73
+ }, (editing) => editing.Form.from((form) => form.Ready.from()))
74
+ )
70
75
  )
71
76
  }).handle({
72
- Editing: {
73
- states: {
74
- Form: {
75
- on: {
76
- EmailChanged: (to) =>
77
- to.branch.Editing.update(({ current, event, owner }) => owner.from({ ...current, email: event.value })),
78
- LoginMethodChanged: (to) =>
79
- to.branch.Editing.update(({ current, event, owner }) =>
80
- owner.from({ ...current, loginMethod: event.value })
81
- ),
82
- PasswordChanged: (to) =>
83
- to.branch.Editing.update(({ current, event, owner }) => owner.from({ ...current, password: event.value })),
84
- Submit: (to) =>
85
- to.branches({
86
- requestVerification: {
87
- title: "Request a verification code",
88
- target: to.branch.Editing.RequestingVerification()
89
- },
90
- login: {
91
- title: "Submit password login",
92
- target: to.branch.Editing.SubmittingLogin()
93
- },
94
- invalid: {
95
- title: "Show validation failure",
96
- target: to.local.Failed()
97
- }
98
- }).resolve(({ event, select }) => {
99
- if (event.route === "login") return select.login.from()
100
- if (event.route === "verification") return select.requestVerification.from()
101
- return select.invalid.from({ message: "Enter valid authentication details." })
102
- })
77
+ states: {
78
+ Editing: {
79
+ states: {
80
+ Form: {
81
+ on: {
82
+ EmailChanged: (to) =>
83
+ to.branch.Editing.update.resolve(({ current, event, owner }) =>
84
+ owner.from({ ...current, email: event.value })
85
+ ),
86
+ LoginMethodChanged: (to) =>
87
+ to.branch.Editing.update.resolve(({ current, event, owner }) =>
88
+ owner.from({ ...current, loginMethod: event.value })
89
+ ),
90
+ PasswordChanged: (to) =>
91
+ to.branch.Editing.update.resolve(({ current, event, owner }) =>
92
+ owner.from({ ...current, password: event.value })
93
+ ),
94
+ Submit: (to) =>
95
+ to.branches({
96
+ requestVerification: {
97
+ title: "Request a verification code",
98
+ target: to.branch.Editing.RequestingVerification()
99
+ },
100
+ login: {
101
+ title: "Submit password login",
102
+ target: to.branch.Editing.SubmittingLogin()
103
+ },
104
+ invalid: {
105
+ title: "Show validation failure",
106
+ target: to.local.Failed()
107
+ }
108
+ }).resolve(({ event, select }) => {
109
+ if (event.route === "login") return select.login.from()
110
+ if (event.route === "verification") return select.requestVerification.from()
111
+ return select.invalid.from({ message: "Enter valid authentication details." })
112
+ })
113
+ },
114
+ states: {
115
+ Ready: {},
116
+ Failed: {}
117
+ }
103
118
  },
104
- states: {
105
- Ready: {},
106
- Failed: {}
119
+ SubmittingLogin: {
120
+ invoke: (from) =>
121
+ from.effect("submit-login", ({ containingState }) =>
122
+ containingState.email === "fail"
123
+ ? Effect.fail("invalid credentials")
124
+ : Effect.succeed("/creator")).onDone((to) =>
125
+ to.branch.Navigating().resolve(({ output, target }) => target.from({ href: output }))).onFailure((to) =>
126
+ to.branch.Editing.Form.Failed().resolve(({ target }) =>
127
+ target.from({ message: "Email or password is incorrect." })
128
+ ))
129
+ },
130
+ RequestingVerification: {
131
+ invoke: (from) =>
132
+ from.effect("request-verification", ({ containingState }) =>
133
+ containingState.email === "fail"
134
+ ? Effect.fail("verification unavailable")
135
+ : Effect.succeed(undefined)).onDone((to) =>
136
+ to.branch.Verification.initial.resolve(({ containingState, target }) =>
137
+ target.from({
138
+ mode: containingState.mode,
139
+ email: containingState.email,
140
+ code: ""
141
+ })
142
+ )).onFailure((to) =>
143
+ to.branch.Editing.Form.Failed().resolve(({ target }) =>
144
+ target.from({ message: "The verification code could not be sent." })
145
+ ))
107
146
  }
108
- },
109
- SubmittingLogin: {
110
- invoke: (from) =>
111
- from.effect("submit-login", ({ containingState }) =>
112
- containingState.email === "fail"
113
- ? Effect.fail("invalid credentials")
114
- : Effect.succeed("/creator")).onDone((to) =>
115
- to.full.Navigating().resolve(({ output, target }) => target.from({ href: output }))).onFailure((to) =>
116
- to.branch.Editing.Form.Failed().resolve(({ target }) =>
117
- target.from({ message: "Email or password is incorrect." })
118
- ))
119
- },
120
- RequestingVerification: {
121
- invoke: (from) =>
122
- from.effect("request-verification", ({ containingState }) =>
123
- containingState.email === "fail"
124
- ? Effect.fail("verification unavailable")
125
- : Effect.succeed(undefined)).onDone((to) =>
126
- to.full.Verification.initial.resolve(({ containingState, target }) =>
127
- target.from({
128
- mode: containingState.mode,
129
- email: containingState.email,
130
- code: ""
131
- })
132
- )).onFailure((to) =>
133
- to.branch.Editing.Form.Failed().resolve(({ target }) =>
134
- target.from({ message: "The verification code could not be sent." })
135
- ))
136
147
  }
137
- }
138
- },
139
- Verification: {
140
- states: {
141
- CodeEntry: {}
142
- }
143
- },
144
- Navigating: {}
148
+ },
149
+ Verification: {
150
+ states: {
151
+ CodeEntry: {}
152
+ }
153
+ },
154
+ Navigating: {}
155
+ }
145
156
  })