@threadlabs/looma 0.18.5 → 0.19.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 (215) hide show
  1. package/components/ui-editor-table-overlay/ui-editor-table-overlay.html +34 -3
  2. package/components/ui-editor-table-overlay/ui-editor-table-overlay.js +55 -0
  3. package/components/ui-editor-table-toolbar/ui-editor-table-toolbar.html +7 -2
  4. package/components/ui-editor-table-toolbar/ui-editor-table-toolbar.js +29 -0
  5. package/dist/index.js +1 -1
  6. package/editor/chunks/extensions.js +39 -3
  7. package/editor/extensions/preset.d.ts +2 -0
  8. package/editor/extensions/table-commands.d.ts +1 -1
  9. package/editor/table-overlay.d.ts +8 -3
  10. package/package.json +2 -1
  11. package/styles/ui-editor-table-overlay.css +30 -0
  12. package/styles/ui-editor-table-toolbar.css +7 -2
  13. package/vanilla/UiEditorTableOverlay.d.ts +1 -1
  14. package/vanilla/UiEditorTableOverlay.js +9 -3
  15. package/vue/UiEditorTableOverlay.d.ts +8 -0
  16. package/vue/UiEditorTableOverlay.vue +45 -2
  17. package/vue/UiEditorTableToolbar.vue +7 -2
  18. package/vue/chunks/1c.js +106 -0
  19. package/vue/chunks/UiEditorTableOverlay.js +14 -4
  20. package/vue/chunks/UiEditorTableToolbar.js +1 -1
  21. package/vue/chunks/abnf.js +61 -0
  22. package/vue/chunks/accesslog.js +72 -0
  23. package/vue/chunks/actionscript.js +139 -0
  24. package/vue/chunks/ada.js +183 -0
  25. package/vue/chunks/angelscript.js +141 -0
  26. package/vue/chunks/apache.js +88 -0
  27. package/vue/chunks/applescript.js +99 -0
  28. package/vue/chunks/arcade.js +405 -0
  29. package/vue/chunks/arduino.js +871 -0
  30. package/vue/chunks/armasm.js +65 -0
  31. package/vue/chunks/asciidoc.js +181 -0
  32. package/vue/chunks/aspectj.js +202 -0
  33. package/vue/chunks/autohotkey.js +54 -0
  34. package/vue/chunks/autoit.js +132 -0
  35. package/vue/chunks/avrasm.js +46 -0
  36. package/vue/chunks/awk.js +58 -0
  37. package/vue/chunks/axapta.js +167 -0
  38. package/vue/chunks/bash.js +358 -0
  39. package/vue/chunks/basic.js +221 -0
  40. package/vue/chunks/bnf.js +27 -0
  41. package/vue/chunks/brainfuck.js +40 -0
  42. package/vue/chunks/c.js +265 -0
  43. package/vue/chunks/cal.js +136 -0
  44. package/vue/chunks/capnproto.js +86 -0
  45. package/vue/chunks/ceylon.js +125 -0
  46. package/vue/chunks/clean.js +54 -0
  47. package/vue/chunks/clojure-repl.js +17 -0
  48. package/vue/chunks/clojure.js +133 -0
  49. package/vue/chunks/cmake.js +23 -0
  50. package/vue/chunks/coffeescript.js +291 -0
  51. package/vue/chunks/coq.js +436 -0
  52. package/vue/chunks/cos.js +77 -0
  53. package/vue/chunks/cpp.js +492 -0
  54. package/vue/chunks/crmsh.js +80 -0
  55. package/vue/chunks/crystal.js +260 -0
  56. package/vue/chunks/csharp.js +376 -0
  57. package/vue/chunks/csp.js +52 -0
  58. package/vue/chunks/css.js +890 -0
  59. package/vue/chunks/d.js +184 -0
  60. package/vue/chunks/dart.js +226 -0
  61. package/vue/chunks/delphi.js +227 -0
  62. package/vue/chunks/diff.js +40 -0
  63. package/vue/chunks/django.js +43 -0
  64. package/vue/chunks/dns.js +66 -0
  65. package/vue/chunks/dockerfile.js +35 -0
  66. package/vue/chunks/dos.js +147 -0
  67. package/vue/chunks/dsconfig.js +55 -0
  68. package/vue/chunks/dts.js +119 -0
  69. package/vue/chunks/dust.js +33 -0
  70. package/vue/chunks/ebnf.js +40 -0
  71. package/vue/chunks/elixir.js +241 -0
  72. package/vue/chunks/elm.js +103 -0
  73. package/vue/chunks/erb.js +17 -0
  74. package/vue/chunks/erlang-repl.js +41 -0
  75. package/vue/chunks/erlang.js +236 -0
  76. package/vue/chunks/excel.js +562 -0
  77. package/vue/chunks/fix.js +30 -0
  78. package/vue/chunks/flix.js +60 -0
  79. package/vue/chunks/fortran.js +543 -0
  80. package/vue/chunks/fsharp.js +440 -0
  81. package/vue/chunks/gams.js +134 -0
  82. package/vue/chunks/gauss.js +167 -0
  83. package/vue/chunks/gcode.js +131 -0
  84. package/vue/chunks/gherkin.js +41 -0
  85. package/vue/chunks/glsl.js +25 -0
  86. package/vue/chunks/gml.js +3119 -0
  87. package/vue/chunks/go.js +140 -0
  88. package/vue/chunks/golo.js +72 -0
  89. package/vue/chunks/gradle.js +181 -0
  90. package/vue/chunks/graphql.js +68 -0
  91. package/vue/chunks/groovy.js +159 -0
  92. package/vue/chunks/haml.js +96 -0
  93. package/vue/chunks/handlebars.js +191 -0
  94. package/vue/chunks/haskell.js +149 -0
  95. package/vue/chunks/haxe.js +142 -0
  96. package/vue/chunks/hsp.js +45 -0
  97. package/vue/chunks/http.js +77 -0
  98. package/vue/chunks/hy.js +92 -0
  99. package/vue/chunks/inform7.js +45 -0
  100. package/vue/chunks/ini.js +94 -0
  101. package/vue/chunks/irpf90.js +52 -0
  102. package/vue/chunks/isbl.js +112 -0
  103. package/vue/chunks/java.js +237 -0
  104. package/vue/chunks/javascript.js +570 -0
  105. package/vue/chunks/jboss-cli.js +46 -0
  106. package/vue/chunks/json.js +45 -0
  107. package/vue/chunks/julia-repl.js +18 -0
  108. package/vue/chunks/julia.js +353 -0
  109. package/vue/chunks/kotlin.js +216 -0
  110. package/vue/chunks/lasso.js +127 -0
  111. package/vue/chunks/latex.js +206 -0
  112. package/vue/chunks/ldif.js +25 -0
  113. package/vue/chunks/leaf.js +72 -0
  114. package/vue/chunks/less.js +953 -0
  115. package/vue/chunks/lisp.js +119 -0
  116. package/vue/chunks/livecodeserver.js +86 -0
  117. package/vue/chunks/livescript.js +309 -0
  118. package/vue/chunks/llvm.js +77 -0
  119. package/vue/chunks/lsl.js +55 -0
  120. package/vue/chunks/lua.js +49 -0
  121. package/vue/chunks/makefile.js +62 -0
  122. package/vue/chunks/markdown.js +194 -0
  123. package/vue/chunks/mathematica.js +7317 -0
  124. package/vue/chunks/matlab.js +70 -0
  125. package/vue/chunks/maxima.js +38 -0
  126. package/vue/chunks/mel.js +24 -0
  127. package/vue/chunks/mercury.js +62 -0
  128. package/vue/chunks/mipsasm.js +53 -0
  129. package/vue/chunks/mizar.js +10 -0
  130. package/vue/chunks/mojolicious.js +27 -0
  131. package/vue/chunks/monkey.js +158 -0
  132. package/vue/chunks/moonscript.js +102 -0
  133. package/vue/chunks/n1ql.js +346 -0
  134. package/vue/chunks/nestedtext.js +66 -0
  135. package/vue/chunks/nginx.js +127 -0
  136. package/vue/chunks/nim.js +174 -0
  137. package/vue/chunks/nix.js +334 -0
  138. package/vue/chunks/node-repl.js +20 -0
  139. package/vue/chunks/nsis.js +515 -0
  140. package/vue/chunks/objectivec.js +235 -0
  141. package/vue/chunks/ocaml.js +52 -0
  142. package/vue/chunks/openscad.js +66 -0
  143. package/vue/chunks/oxygene.js +58 -0
  144. package/vue/chunks/parser3.js +40 -0
  145. package/vue/chunks/perl.js +454 -0
  146. package/vue/chunks/pf.js +30 -0
  147. package/vue/chunks/pgsql.js +196 -0
  148. package/vue/chunks/php-template.js +43 -0
  149. package/vue/chunks/php.js +527 -0
  150. package/vue/chunks/plaintext.js +10 -0
  151. package/vue/chunks/pony.js +60 -0
  152. package/vue/chunks/powershell.js +208 -0
  153. package/vue/chunks/processing.js +407 -0
  154. package/vue/chunks/profile.js +38 -0
  155. package/vue/chunks/prolog.js +62 -0
  156. package/vue/chunks/properties.js +45 -0
  157. package/vue/chunks/protobuf.js +63 -0
  158. package/vue/chunks/puppet.js +87 -0
  159. package/vue/chunks/purebasic.js +42 -0
  160. package/vue/chunks/python-repl.js +19 -0
  161. package/vue/chunks/python.js +357 -0
  162. package/vue/chunks/q.js +21 -0
  163. package/vue/chunks/qml.js +134 -0
  164. package/vue/chunks/r.js +145 -0
  165. package/vue/chunks/reasonml.js +134 -0
  166. package/vue/chunks/rib.js +16 -0
  167. package/vue/chunks/roboconf.js +54 -0
  168. package/vue/chunks/routeros.js +109 -0
  169. package/vue/chunks/rsl.js +138 -0
  170. package/vue/chunks/ruby.js +322 -0
  171. package/vue/chunks/ruleslanguage.js +26 -0
  172. package/vue/chunks/rust.js +296 -0
  173. package/vue/chunks/sas.js +533 -0
  174. package/vue/chunks/scala.js +173 -0
  175. package/vue/chunks/scheme.js +118 -0
  176. package/vue/chunks/scilab.js +45 -0
  177. package/vue/chunks/scss.js +900 -0
  178. package/vue/chunks/shell.js +18 -0
  179. package/vue/chunks/smali.js +113 -0
  180. package/vue/chunks/smalltalk.js +59 -0
  181. package/vue/chunks/sml.js +49 -0
  182. package/vue/chunks/sqf.js +2599 -0
  183. package/vue/chunks/sql.js +624 -0
  184. package/vue/chunks/stan.js +471 -0
  185. package/vue/chunks/stata.js +33 -0
  186. package/vue/chunks/step21.js +53 -0
  187. package/vue/chunks/stylus.js +925 -0
  188. package/vue/chunks/subunit.js +34 -0
  189. package/vue/chunks/swift.js +699 -0
  190. package/vue/chunks/taggerscript.js +37 -0
  191. package/vue/chunks/tap.js +30 -0
  192. package/vue/chunks/tcl.js +165 -0
  193. package/vue/chunks/thrift.js +65 -0
  194. package/vue/chunks/tp.js +155 -0
  195. package/vue/chunks/twig.js +232 -0
  196. package/vue/chunks/typescript.js +672 -0
  197. package/vue/chunks/vala.js +39 -0
  198. package/vue/chunks/vbnet.js +86 -0
  199. package/vue/chunks/vbscript-html.js +14 -0
  200. package/vue/chunks/vbscript.js +200 -0
  201. package/vue/chunks/verilog.js +534 -0
  202. package/vue/chunks/vhdl.js +190 -0
  203. package/vue/chunks/vim.js +54 -0
  204. package/vue/chunks/wasm.js +111 -0
  205. package/vue/chunks/wren.js +229 -0
  206. package/vue/chunks/x86asm.js +64 -0
  207. package/vue/chunks/xl.js +192 -0
  208. package/vue/chunks/xml.js +175 -0
  209. package/vue/chunks/xquery.js +303 -0
  210. package/vue/chunks/yaml.js +159 -0
  211. package/vue/chunks/zephir.js +74 -0
  212. package/vue/components.css +119 -85
  213. package/vue/editor/LoomaEditor.d.ts +7 -7
  214. package/vue/editor/code-language-catalog.d.ts +196 -0
  215. package/vue/editor/index.js +290 -20
@@ -29,7 +29,7 @@
29
29
  <state name="activeKey" :value="''"></state>
30
30
  <event
31
31
  name="action"
32
- type="object({ action: add-row-before | add-row-after | add-column-before | add-column-after, boundaryIndex: integer }) | object({ action: select-row | select-column, rowIndex: integer, columnIndex: integer }) | object({ action: open-cell-menu | open-row-menu | open-column-menu, rowIndex: integer, columnIndex: integer, anchor: object({ left: number, top: number, right: number, bottom: number }) })"
32
+ type="object({ action: add-row-before | add-row-after | add-column-before | add-column-after, boundaryIndex: integer }) | object({ action: select-row | select-column, rowIndex: integer, columnIndex: integer }) | object({ action: reorder-row | reorder-column, fromIndex: integer, toIndex: integer }) | object({ action: open-cell-menu | open-row-menu | open-column-menu, rowIndex: integer, columnIndex: integer, anchor: object({ left: number, top: number, right: number, bottom: number }) })"
33
33
  ></event>
34
34
  </defs>
35
35
  <div aria-label="Table controls" :hidden="not open">
@@ -89,7 +89,7 @@
89
89
  data-action="select-row"
90
90
  :data-row-index="hovered.rowIndex"
91
91
  :data-column-index="hovered.columnIndex"
92
- title="Row actions"
92
+ title="Drag row to reorder; click for actions"
93
93
  aria-label="Row actions"
94
94
  >
95
95
  <span class="glyph"><ui-icon name="grip-vertical"></ui-icon></span>
@@ -101,7 +101,7 @@
101
101
  data-action="select-column"
102
102
  :data-row-index="hovered.rowIndex"
103
103
  :data-column-index="hovered.columnIndex"
104
- title="Column actions"
104
+ title="Drag column to reorder; click for actions"
105
105
  aria-label="Column actions"
106
106
  >
107
107
  <span class="glyph"><ui-icon name="grip-horizontal"></ui-icon></span>
@@ -121,6 +121,7 @@
121
121
  >
122
122
  <ui-icon name="chevron-down"></ui-icon>
123
123
  </button>
124
+ <span class="drop-indicator" data-drop-indicator hidden aria-hidden="true"></span>
124
125
  </div>
125
126
  <style>
126
127
  :host {
@@ -346,6 +347,12 @@
346
347
 
347
348
  .selector {
348
349
  border-radius: var(--ui-radius-round);
350
+ touch-action: none;
351
+ cursor: grab;
352
+ }
353
+
354
+ .selector:active {
355
+ cursor: grabbing;
349
356
  }
350
357
 
351
358
  .selector::before {
@@ -431,6 +438,30 @@
431
438
  --_ui-default-icon-stroke-width: 2;
432
439
  }
433
440
 
441
+ .drop-indicator {
442
+ position: absolute;
443
+ z-index: 3;
444
+ background: var(--ui-accent-solid);
445
+ box-shadow: 0 0 0 2px var(--ui-surface);
446
+ pointer-events: none;
447
+ }
448
+
449
+ .drop-indicator.row {
450
+ left: 0;
451
+ width: 100%;
452
+ height: 2px;
453
+ }
454
+
455
+ .drop-indicator.column {
456
+ top: 0;
457
+ width: 2px;
458
+ height: 100%;
459
+ }
460
+
461
+ .drop-indicator[hidden] {
462
+ display: none;
463
+ }
464
+
434
465
  :host[hidden] {
435
466
  display: none;
436
467
  }
@@ -52,6 +52,52 @@ function createProximity(scope, selector = ".handle[data-ui-affordance]", radius
52
52
  export default function controller(host) {
53
53
  const element = host.element;
54
54
  const proximity = createProximity(element);
55
+ let drag = null;
56
+ let suppressClick = false;
57
+ const indicator = () => element.querySelector("[data-drop-indicator]");
58
+ const clearDrag = () => {
59
+ drag = null;
60
+ const guide = indicator();
61
+ if (guide) {
62
+ guide.hidden = true;
63
+ guide.classList.remove("row", "column");
64
+ }
65
+ };
66
+ const onPointerDown = (event) => {
67
+ const button = event.target.closest?.("button.selector[data-action]");
68
+ if (!button || event.button !== 0) return;
69
+ const axis = button.dataset.action === "select-row" ? "row" : "column";
70
+ drag = { pointerId: event.pointerId, axis, from: Number(button.dataset[axis === "row" ? "rowIndex" : "columnIndex"]), x: event.clientX, y: event.clientY, to: null };
71
+ button.setPointerCapture(event.pointerId);
72
+ event.preventDefault();
73
+ };
74
+ const onPointerMove = (event) => {
75
+ if (!drag || event.pointerId !== drag.pointerId) return;
76
+ if (Math.hypot(event.clientX - drag.x, event.clientY - drag.y) < 5 && drag.to === null) return;
77
+ const rect = element.getBoundingClientRect();
78
+ const values = boundaries(drag.axis);
79
+ const coordinate = drag.axis === "row" ? event.clientY - rect.top : event.clientX - rect.left;
80
+ const found = values.findIndex((_, index) => index < values.length - 1 && coordinate < values[index + 1]);
81
+ const to = found < 0 ? values.length - 2 : found;
82
+ drag.to = to;
83
+ const guide = indicator();
84
+ if (!guide) return;
85
+ guide.hidden = false;
86
+ guide.classList.toggle("row", drag.axis === "row");
87
+ guide.classList.toggle("column", drag.axis === "column");
88
+ const boundary = to > drag.from ? values[to + 1] : values[to];
89
+ if (drag.axis === "row") guide.style.top = `${boundary}px`;
90
+ else guide.style.left = `${boundary}px`;
91
+ };
92
+ const onPointerUp = (event) => {
93
+ if (!drag || event.pointerId !== drag.pointerId) return;
94
+ const { axis, from, to } = drag;
95
+ clearDrag();
96
+ if (to === null) return;
97
+ suppressClick = true;
98
+ setTimeout(() => { suppressClick = false; }, 0);
99
+ if (to !== from) host.dispatch("action", { action: axis === "row" ? "reorder-row" : "reorder-column", fromIndex: from, toIndex: to });
100
+ };
55
101
  const boundaries = (axis) => {
56
102
  const values = host.state.geometry?.[axis === "row" ? "rowBoundaries" : "columnBoundaries"];
57
103
  if (Array.isArray(values) && values.length >= 2 && values.every(Number.isFinite)) return values;
@@ -89,6 +135,7 @@ export default function controller(host) {
89
135
  queueMicrotask(proximity.refresh);
90
136
  });
91
137
  const onClick = (event) => {
138
+ if (suppressClick) { event.preventDefault(); return; }
92
139
  const button = event.target.closest?.("button[data-action]");
93
140
  if (!button) return;
94
141
  const action = button.dataset.action;
@@ -106,6 +153,10 @@ export default function controller(host) {
106
153
  const enter = (event) => { host.state.activeKey = keyOf(event.target); };
107
154
  const leave = (event) => { host.state.activeKey = keyOf(event.relatedTarget); };
108
155
  element.addEventListener("click", onClick);
156
+ element.addEventListener("pointerdown", onPointerDown);
157
+ document.addEventListener("pointermove", onPointerMove, true);
158
+ document.addEventListener("pointerup", onPointerUp, true);
159
+ document.addEventListener("pointercancel", clearDrag, true);
109
160
  element.addEventListener("pointerover", enter);
110
161
  element.addEventListener("pointerout", leave);
111
162
  element.addEventListener("focusin", enter);
@@ -114,6 +165,10 @@ export default function controller(host) {
114
165
  stop();
115
166
  proximity.destroy();
116
167
  element.removeEventListener("click", onClick);
168
+ element.removeEventListener("pointerdown", onPointerDown);
169
+ document.removeEventListener("pointermove", onPointerMove, true);
170
+ document.removeEventListener("pointerup", onPointerUp, true);
171
+ document.removeEventListener("pointercancel", clearDrag, true);
117
172
  element.removeEventListener("pointerover", enter);
118
173
  element.removeEventListener("pointerout", leave);
119
174
  element.removeEventListener("focusin", enter);
@@ -211,10 +211,12 @@
211
211
  }
212
212
 
213
213
  .menu {
214
+ box-sizing: border-box;
214
215
  position: absolute;
215
216
  top: calc(100% + var(--ui-space-2));
216
217
  right: 0;
217
218
  min-width: 12rem;
219
+ max-width: min(17rem, calc(100vw - 24px));
218
220
  padding: var(--ui-space-1);
219
221
  background: var(--ui-surface);
220
222
  border: 1px solid var(--ui-border-strong);
@@ -224,6 +226,9 @@
224
226
  flex-direction: column;
225
227
  gap: 2px;
226
228
  z-index: 2;
229
+ overflow-y: auto;
230
+ overscroll-behavior: contain;
231
+ scrollbar-width: thin;
227
232
  }
228
233
 
229
234
  .menu-section + .menu-section {
@@ -250,7 +255,7 @@
250
255
 
251
256
  .swatches {
252
257
  display: grid;
253
- grid-template-columns: repeat(3, minmax(0, 1fr));
258
+ grid-template-columns: repeat(2, minmax(0, 1fr));
254
259
  gap: 2px;
255
260
  }
256
261
 
@@ -264,7 +269,7 @@
264
269
  height: 14px;
265
270
  flex: 0 0 14px;
266
271
  border: 1px solid color-mix(in srgb, var(--ui-border) 80%, #000);
267
- border-radius: 3px;
272
+ border-radius: var(--ui-radius-round);
268
273
  background: var(--_swatch);
269
274
  }
270
275
 
@@ -9,6 +9,20 @@ const overflowSections = [
9
9
  // Lists the actions the table selection permits; the overflow menu opens and closes here.
10
10
  export default function controller(host) {
11
11
  const element = host.element;
12
+ const positionMenu = () => {
13
+ const button = element.querySelector(".more");
14
+ const menu = element.querySelector(".menu");
15
+ if (!button || !menu) return;
16
+ const rect = button.getBoundingClientRect();
17
+ const viewport = window.visualViewport;
18
+ const top = viewport?.offsetTop ?? 0;
19
+ const bottom = top + (viewport?.height ?? window.innerHeight);
20
+ const above = rect.top - top - 20;
21
+ const below = bottom - rect.bottom - 20;
22
+ menu.style.maxHeight = `${Math.max(80, Math.floor(Math.max(above, below)))}px`;
23
+ menu.style.top = below >= above ? "calc(100% + var(--ui-space-2))" : "auto";
24
+ menu.style.bottom = below >= above ? "auto" : "calc(100% + var(--ui-space-2))";
25
+ };
12
26
  const stop = host.effect(() => {
13
27
  const enabled = new Set(Array.isArray(host.state.actions) ? host.state.actions : []);
14
28
  const alignment = host.state.cellAlignment === "center" || host.state.cellAlignment === "right" ? host.state.cellAlignment : "left";
@@ -36,6 +50,7 @@ export default function controller(host) {
36
50
  if (!action) return;
37
51
  if (action === "toggle-overflow") {
38
52
  host.state.overflowOpen = !host.state.overflowOpen;
53
+ if (host.state.overflowOpen) requestAnimationFrame(positionMenu);
39
54
  return;
40
55
  }
41
56
  host.state.overflowOpen = false;
@@ -44,11 +59,25 @@ export default function controller(host) {
44
59
  const onOutside = (event) => {
45
60
  if (host.state.overflowOpen && !event.composedPath().includes(element)) host.state.overflowOpen = false;
46
61
  };
62
+ const onKeydown = (event) => {
63
+ if (event.key === "Escape" && host.state.overflowOpen) {
64
+ host.state.overflowOpen = false;
65
+ event.preventDefault();
66
+ event.stopPropagation();
67
+ element.querySelector(".more")?.focus();
68
+ }
69
+ };
47
70
  element.addEventListener("click", onClick);
48
71
  document.addEventListener("pointerdown", onOutside, true);
72
+ document.addEventListener("keydown", onKeydown, true);
73
+ window.addEventListener("resize", positionMenu);
74
+ window.visualViewport?.addEventListener("resize", positionMenu);
49
75
  return () => {
50
76
  stop();
51
77
  element.removeEventListener("click", onClick);
52
78
  document.removeEventListener("pointerdown", onOutside, true);
79
+ document.removeEventListener("keydown", onKeydown, true);
80
+ window.removeEventListener("resize", positionMenu);
81
+ window.visualViewport?.removeEventListener("resize", positionMenu);
53
82
  };
54
83
  }