@mintjamsinc/ichigojs 0.1.6 → 0.1.8

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.
@@ -59,6 +59,8 @@
59
59
  StandardDirectiveName["V_ON"] = "v-on";
60
60
  StandardDirectiveName["V_BIND"] = "v-bind";
61
61
  StandardDirectiveName["V_MODEL"] = "v-model";
62
+ StandardDirectiveName["V_RESIZE"] = "v-resize";
63
+ StandardDirectiveName["V_INTERSECTION"] = "v-intersection";
62
64
  })(StandardDirectiveName || (StandardDirectiveName = {}));
63
65
 
64
66
  // This file was generated. Do not modify manually!
@@ -6873,6 +6875,19 @@
6873
6875
  get isKey() {
6874
6876
  return (this.#attributeName === 'key');
6875
6877
  }
6878
+ /**
6879
+ * Indicates if this directive is binding the "options" attribute or any of its sub-properties (e.g., "options.intersection").
6880
+ * The "options" attribute is special and is used for passing options to certain directives like VIntersectionDirective.
6881
+ */
6882
+ get isOptions() {
6883
+ return (this.#attributeName === 'options' || this.#attributeName?.startsWith('options.') === true);
6884
+ }
6885
+ /**
6886
+ * Gets the name of the attribute being bound (e.g., "src", "class", "options", "options.intersection").
6887
+ */
6888
+ get attributeName() {
6889
+ return this.#attributeName;
6890
+ }
6876
6891
  /**
6877
6892
  * Gets the original expression string from the directive.
6878
6893
  */
@@ -6925,8 +6940,8 @@
6925
6940
  * Renders the bound attribute by evaluating the expression and updating the DOM element.
6926
6941
  */
6927
6942
  #render() {
6928
- // If this directive is binding the "key" attribute, do nothing
6929
- if (this.isKey) {
6943
+ // Do nothing for special attributes
6944
+ if (this.isKey || this.isOptions) {
6930
6945
  return;
6931
6946
  }
6932
6947
  const element = this.#vNode.node;
@@ -7370,16 +7385,47 @@
7370
7385
  }
7371
7386
 
7372
7387
  // Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
7388
+ /**
7389
+ * Manages directives associated with a virtual node (VNode).
7390
+ * This class is responsible for parsing, storing, and managing the lifecycle of directives.
7391
+ * It also provides access to bindings preparers and DOM updaters from the associated directives.
7392
+ */
7373
7393
  class VDirectiveManager {
7374
7394
  /**
7375
7395
  * The virtual node to which this directive handler is associated.
7376
7396
  */
7377
7397
  #vNode;
7398
+ /**
7399
+ * The list of directives associated with the virtual node.
7400
+ * This may be undefined if there are no directives.
7401
+ */
7378
7402
  #directives;
7403
+ /**
7404
+ * The anchor comment node used for certain directives (e.g., v-if, v-for).
7405
+ * This may be undefined if no directive requires an anchor.
7406
+ */
7379
7407
  #anchorNode;
7408
+ /**
7409
+ * The list of bindings preparers from the associated directives.
7410
+ * This may be undefined if no directive provides a bindings preparer.
7411
+ */
7380
7412
  #bindingsPreparers;
7413
+ /**
7414
+ * The list of DOM updaters from the associated directives.
7415
+ * This may be undefined if no directive provides a DOM updater.
7416
+ */
7381
7417
  #domUpdaters;
7418
+ /**
7419
+ * The directive that binds the ":key" or "v-bind:key" attribute, if any.
7420
+ * This directive is special and is used for optimizing rendering of lists.
7421
+ * If no such directive exists, this is undefined.
7422
+ */
7382
7423
  #keyDirective;
7424
+ /**
7425
+ * A cache of VBindDirectives for options specific to certain directives.
7426
+ * The keys are directive names (e.g., 'options', 'options.intersection').
7427
+ */
7428
+ #optionsDirectives = {};
7383
7429
  constructor(vNode) {
7384
7430
  // Directives can only be associated with element nodes
7385
7431
  if (vNode.nodeType !== Node.ELEMENT_NODE) {
@@ -7437,6 +7483,35 @@
7437
7483
  get keyDirective() {
7438
7484
  return this.#keyDirective;
7439
7485
  }
7486
+ /**
7487
+ * Gets a record of VBindDirectives for options specific to certain directives.
7488
+ * The keys are directive names (e.g., 'options', 'options.intersection').
7489
+ */
7490
+ get optionsDirectives() {
7491
+ return this.#optionsDirectives;
7492
+ }
7493
+ /**
7494
+ * Gets the VBindDirective for options specific to the given directive name.
7495
+ * Searches in order: `:options.{directive}` -> `:options`
7496
+ *
7497
+ * @param directive The directive name (e.g., 'intersection', 'resize')
7498
+ * @returns The VBindDirective instance or undefined
7499
+ */
7500
+ optionsDirective(directive) {
7501
+ if (!this.#directives || this.#directives.length === 0) {
7502
+ return undefined;
7503
+ }
7504
+ // Search for `:options.{directive}` or `v-bind:options.{directive}` first
7505
+ const specificAttrName = `options.${directive}`;
7506
+ if (this.#optionsDirectives[specificAttrName]) {
7507
+ return this.#optionsDirectives[specificAttrName];
7508
+ }
7509
+ // Fallback: search for `:options` or `v-bind:options`
7510
+ if (this.#optionsDirectives['options']) {
7511
+ return this.#optionsDirectives['options'];
7512
+ }
7513
+ return undefined;
7514
+ }
7440
7515
  /**
7441
7516
  * Cleans up any resources used by the directive handler.
7442
7517
  */
@@ -7496,6 +7571,10 @@
7496
7571
  if (directive.name === StandardDirectiveName.V_BIND && directive.isKey) {
7497
7572
  this.#keyDirective = directive;
7498
7573
  }
7574
+ // If this is an options binding directive, cache it
7575
+ if (directive.name === StandardDirectiveName.V_BIND && directive.isOptions) {
7576
+ this.#optionsDirectives[directive.name] = directive;
7577
+ }
7499
7578
  }
7500
7579
  }
7501
7580
  // Sort directives by priority: v-for > v-if > v-else-if > v-else > v-show > others
@@ -8983,6 +9062,209 @@
8983
9062
  }
8984
9063
  }
8985
9064
 
9065
+ // Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
9066
+ /**
9067
+ * Directive for observing element intersection with viewport or ancestor elements using IntersectionObserver.
9068
+ * The `v-intersection` directive allows you to respond to changes in an element's visibility.
9069
+ *
9070
+ * Example usage:
9071
+ * <div v-intersection="handleIntersection">Observable content</div>
9072
+ * <div v-intersection="handleIntersection" :options.intersection="{threshold: 0.5}">Observable content</div>
9073
+ *
9074
+ * The handler receives IntersectionObserverEntry array as the first argument and $ctx as the second:
9075
+ * handleIntersection(entries, $ctx) {
9076
+ * const entry = entries[0];
9077
+ * if (entry.isIntersecting) {
9078
+ * console.log('Element is visible!');
9079
+ * }
9080
+ * }
9081
+ *
9082
+ * Options can be provided via :options or :options.intersection attribute:
9083
+ * :options="{root: null, threshold: 0.5, rootMargin: '0px'}"
9084
+ * :options.intersection="{root: null, threshold: 0.5, rootMargin: '0px'}"
9085
+ *
9086
+ * This directive is useful for lazy-loading, infinite scrolling, animation triggers,
9087
+ * and other features that depend on element visibility.
9088
+ */
9089
+ class VIntersectionDirective {
9090
+ /**
9091
+ * The virtual node to which this directive is applied.
9092
+ */
9093
+ #vNode;
9094
+ /**
9095
+ * A list of variable and function names used in the directive's expression.
9096
+ */
9097
+ #dependentIdentifiers;
9098
+ /**
9099
+ * The intersection handler wrapper function.
9100
+ */
9101
+ #handlerWrapper;
9102
+ /**
9103
+ * The IntersectionObserver instance.
9104
+ */
9105
+ #intersectionObserver;
9106
+ /**
9107
+ * @param context The context for parsing the directive.
9108
+ */
9109
+ constructor(context) {
9110
+ this.#vNode = context.vNode;
9111
+ // Parse the expression to extract identifiers and create the handler wrapper
9112
+ const expression = context.attribute.value;
9113
+ if (expression) {
9114
+ this.#dependentIdentifiers = ExpressionUtils.extractIdentifiers(expression, context.vNode.vApplication.functionDependencies);
9115
+ this.#handlerWrapper = this.#createIntersectionHandlerWrapper(expression);
9116
+ }
9117
+ // Remove the directive attribute from the element
9118
+ this.#vNode.node.removeAttribute(context.attribute.name);
9119
+ }
9120
+ /**
9121
+ * @inheritdoc
9122
+ */
9123
+ get name() {
9124
+ return StandardDirectiveName.V_INTERSECTION;
9125
+ }
9126
+ /**
9127
+ * @inheritdoc
9128
+ */
9129
+ get vNode() {
9130
+ return this.#vNode;
9131
+ }
9132
+ /**
9133
+ * @inheritdoc
9134
+ */
9135
+ get needsAnchor() {
9136
+ return false;
9137
+ }
9138
+ /**
9139
+ * @inheritdoc
9140
+ */
9141
+ get bindingsPreparer() {
9142
+ return undefined;
9143
+ }
9144
+ /**
9145
+ * @inheritdoc
9146
+ */
9147
+ get domUpdater() {
9148
+ return undefined;
9149
+ }
9150
+ /**
9151
+ * @inheritdoc
9152
+ */
9153
+ get templatize() {
9154
+ return false;
9155
+ }
9156
+ /**
9157
+ * @inheritdoc
9158
+ */
9159
+ get dependentIdentifiers() {
9160
+ return this.#dependentIdentifiers ?? [];
9161
+ }
9162
+ /**
9163
+ * @inheritdoc
9164
+ */
9165
+ get onMount() {
9166
+ return undefined;
9167
+ }
9168
+ /**
9169
+ * @inheritdoc
9170
+ */
9171
+ get onMounted() {
9172
+ if (!this.#handlerWrapper) {
9173
+ return undefined;
9174
+ }
9175
+ const element = this.#vNode.node;
9176
+ const handler = this.#handlerWrapper;
9177
+ return () => {
9178
+ // Get options from :options.intersection or :options directive
9179
+ let optionsDirective = this.#vNode.directiveManager?.optionsDirective('intersection');
9180
+ // Evaluate the options expression
9181
+ let options;
9182
+ if (optionsDirective && optionsDirective.expression) {
9183
+ // Evaluate the options expression
9184
+ const identifiers = optionsDirective.dependentIdentifiers;
9185
+ const values = identifiers.map(id => this.#vNode.bindings?.get(id));
9186
+ const args = identifiers.join(", ");
9187
+ const funcBody = `return (${optionsDirective.expression});`;
9188
+ const func = new Function(args, funcBody);
9189
+ options = func(...values);
9190
+ }
9191
+ // Create IntersectionObserver and start observing
9192
+ this.#intersectionObserver = new IntersectionObserver((entries) => {
9193
+ handler(entries);
9194
+ }, options);
9195
+ this.#intersectionObserver.observe(element);
9196
+ };
9197
+ }
9198
+ /**
9199
+ * @inheritdoc
9200
+ */
9201
+ get onUpdate() {
9202
+ return undefined;
9203
+ }
9204
+ /**
9205
+ * @inheritdoc
9206
+ */
9207
+ get onUpdated() {
9208
+ return undefined;
9209
+ }
9210
+ /**
9211
+ * @inheritdoc
9212
+ */
9213
+ get onUnmount() {
9214
+ return undefined;
9215
+ }
9216
+ /**
9217
+ * @inheritdoc
9218
+ */
9219
+ get onUnmounted() {
9220
+ return undefined;
9221
+ }
9222
+ /**
9223
+ * @inheritdoc
9224
+ */
9225
+ destroy() {
9226
+ // Disconnect the IntersectionObserver when the directive is destroyed
9227
+ if (this.#intersectionObserver) {
9228
+ this.#intersectionObserver.disconnect();
9229
+ this.#intersectionObserver = undefined;
9230
+ }
9231
+ }
9232
+ /**
9233
+ * Creates a wrapper function for intersection handlers.
9234
+ * @param expression The expression string to evaluate.
9235
+ * @returns A function that handles the intersection event.
9236
+ */
9237
+ #createIntersectionHandlerWrapper(expression) {
9238
+ const identifiers = this.#dependentIdentifiers ?? [];
9239
+ const vNode = this.#vNode;
9240
+ // Return a function that handles the intersection event with proper scope
9241
+ return (entries) => {
9242
+ const bindings = vNode.bindings;
9243
+ const $ctx = {
9244
+ element: vNode.node,
9245
+ vnode: vNode,
9246
+ userData: vNode.userData
9247
+ };
9248
+ // If the expression is just a method name, call it with bindings as 'this'
9249
+ const trimmedExpr = expression.trim();
9250
+ if (identifiers.includes(trimmedExpr) && typeof bindings?.get(trimmedExpr) === 'function') {
9251
+ const methodName = trimmedExpr;
9252
+ const originalMethod = bindings?.get(methodName);
9253
+ // Call the method with bindings as 'this' context
9254
+ // Pass entries as first argument and $ctx as second argument
9255
+ return originalMethod(entries, $ctx);
9256
+ }
9257
+ // For inline expressions, evaluate normally
9258
+ // Note: inline expressions receive entries and $ctx as parameters
9259
+ const values = identifiers.map(id => vNode.bindings?.get(id));
9260
+ const args = [...identifiers, 'entries', '$ctx'].join(", ");
9261
+ const funcBody = `return (${expression});`;
9262
+ const func = new Function(args, funcBody);
9263
+ return func.call(bindings?.raw, ...values, entries, $ctx);
9264
+ };
9265
+ }
9266
+ }
9267
+
8986
9268
  // Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
8987
9269
  /**
8988
9270
  * Directive for two-way data binding on form input elements.
@@ -9308,8 +9590,8 @@
9308
9590
  * @mounted="onMounted" - Called after the element is inserted into the DOM
9309
9591
  * @update="onUpdate" - Called before the element is updated
9310
9592
  * @updated="onUpdated" - Called after the element is updated
9311
- * @unmount="onUnmount" - Called before the element is removed from the DOM
9312
- * @unmounted="onUnmounted" - Called after the element is removed from the DOM
9593
+ * @unmount="onUnmount" - Called before VNode cleanup begins
9594
+ * @unmounted="onUnmounted" - Called after VNode cleanup is complete (element reference still available)
9313
9595
  *
9314
9596
  * This directive is essential for handling user interactions and lifecycle events in your application.
9315
9597
  * Note that the methods referenced in the directive should be defined in the component's methods object.
@@ -9585,7 +9867,7 @@
9585
9867
  };
9586
9868
  }
9587
9869
  /**
9588
- * Creates a wrapper function for DOM event handlers (with event parameter).
9870
+ * Creates a wrapper function for DOM event handlers (with event and $ctx parameters).
9589
9871
  * @param expression The expression string to evaluate.
9590
9872
  * @returns A function that handles the event.
9591
9873
  */
@@ -9595,21 +9877,210 @@
9595
9877
  // Return a function that handles the event with proper scope
9596
9878
  return (event) => {
9597
9879
  const bindings = vNode.bindings;
9880
+ const $ctx = {
9881
+ element: vNode.node,
9882
+ vnode: vNode,
9883
+ userData: vNode.userData
9884
+ };
9885
+ // If the expression is just a method name, call it with bindings as 'this'
9886
+ const trimmedExpr = expression.trim();
9887
+ if (identifiers.includes(trimmedExpr) && typeof bindings?.get(trimmedExpr) === 'function') {
9888
+ const methodName = trimmedExpr;
9889
+ const originalMethod = bindings?.get(methodName);
9890
+ // Call the method with bindings as 'this' context
9891
+ // Pass event as first argument and $ctx as second argument
9892
+ return originalMethod(event, $ctx);
9893
+ }
9894
+ // For inline expressions, evaluate normally
9895
+ // Note: inline expressions receive event and $ctx as parameters
9896
+ const values = identifiers.map(id => vNode.bindings?.get(id));
9897
+ const args = [...identifiers, 'event', '$ctx'].join(", ");
9898
+ const funcBody = `return (${expression});`;
9899
+ const func = new Function(args, funcBody);
9900
+ return func.call(bindings?.raw, ...values, event, $ctx);
9901
+ };
9902
+ }
9903
+ }
9904
+
9905
+ // Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
9906
+ /**
9907
+ * Directive for observing element resize events using ResizeObserver.
9908
+ * The `v-resize` directive allows you to respond to changes in an element's size.
9909
+ *
9910
+ * Example usage:
9911
+ * <div v-resize="handleResize">Resizable content</div>
9912
+ *
9913
+ * The handler receives ResizeObserverEntry array as the first argument and $ctx as the second:
9914
+ * handleResize(entries, $ctx) {
9915
+ * const { width, height } = entries[0].contentRect;
9916
+ * console.log(`Size: ${width}x${height}`);
9917
+ * }
9918
+ *
9919
+ * This directive is useful for responsive layouts, charts, and other components
9920
+ * that need to adapt to size changes.
9921
+ */
9922
+ class VResizeDirective {
9923
+ /**
9924
+ * The virtual node to which this directive is applied.
9925
+ */
9926
+ #vNode;
9927
+ /**
9928
+ * A list of variable and function names used in the directive's expression.
9929
+ */
9930
+ #dependentIdentifiers;
9931
+ /**
9932
+ * The resize handler wrapper function.
9933
+ */
9934
+ #handlerWrapper;
9935
+ /**
9936
+ * The ResizeObserver instance.
9937
+ */
9938
+ #resizeObserver;
9939
+ /**
9940
+ * @param context The context for parsing the directive.
9941
+ */
9942
+ constructor(context) {
9943
+ this.#vNode = context.vNode;
9944
+ // Parse the expression to extract identifiers and create the handler wrapper
9945
+ const expression = context.attribute.value;
9946
+ if (expression) {
9947
+ this.#dependentIdentifiers = ExpressionUtils.extractIdentifiers(expression, context.vNode.vApplication.functionDependencies);
9948
+ this.#handlerWrapper = this.#createResizeHandlerWrapper(expression);
9949
+ }
9950
+ // Remove the directive attribute from the element
9951
+ this.#vNode.node.removeAttribute(context.attribute.name);
9952
+ }
9953
+ /**
9954
+ * @inheritdoc
9955
+ */
9956
+ get name() {
9957
+ return StandardDirectiveName.V_RESIZE;
9958
+ }
9959
+ /**
9960
+ * @inheritdoc
9961
+ */
9962
+ get vNode() {
9963
+ return this.#vNode;
9964
+ }
9965
+ /**
9966
+ * @inheritdoc
9967
+ */
9968
+ get needsAnchor() {
9969
+ return false;
9970
+ }
9971
+ /**
9972
+ * @inheritdoc
9973
+ */
9974
+ get bindingsPreparer() {
9975
+ return undefined;
9976
+ }
9977
+ /**
9978
+ * @inheritdoc
9979
+ */
9980
+ get domUpdater() {
9981
+ return undefined;
9982
+ }
9983
+ /**
9984
+ * @inheritdoc
9985
+ */
9986
+ get templatize() {
9987
+ return false;
9988
+ }
9989
+ /**
9990
+ * @inheritdoc
9991
+ */
9992
+ get dependentIdentifiers() {
9993
+ return this.#dependentIdentifiers ?? [];
9994
+ }
9995
+ /**
9996
+ * @inheritdoc
9997
+ */
9998
+ get onMount() {
9999
+ return undefined;
10000
+ }
10001
+ /**
10002
+ * @inheritdoc
10003
+ */
10004
+ get onMounted() {
10005
+ if (!this.#handlerWrapper) {
10006
+ return undefined;
10007
+ }
10008
+ const element = this.#vNode.node;
10009
+ const handler = this.#handlerWrapper;
10010
+ return () => {
10011
+ // Create ResizeObserver and start observing
10012
+ this.#resizeObserver = new ResizeObserver((entries) => {
10013
+ handler(entries);
10014
+ });
10015
+ this.#resizeObserver.observe(element);
10016
+ };
10017
+ }
10018
+ /**
10019
+ * @inheritdoc
10020
+ */
10021
+ get onUpdate() {
10022
+ return undefined;
10023
+ }
10024
+ /**
10025
+ * @inheritdoc
10026
+ */
10027
+ get onUpdated() {
10028
+ return undefined;
10029
+ }
10030
+ /**
10031
+ * @inheritdoc
10032
+ */
10033
+ get onUnmount() {
10034
+ return undefined;
10035
+ }
10036
+ /**
10037
+ * @inheritdoc
10038
+ */
10039
+ get onUnmounted() {
10040
+ return undefined;
10041
+ }
10042
+ /**
10043
+ * @inheritdoc
10044
+ */
10045
+ destroy() {
10046
+ // Disconnect the ResizeObserver when the directive is destroyed
10047
+ if (this.#resizeObserver) {
10048
+ this.#resizeObserver.disconnect();
10049
+ this.#resizeObserver = undefined;
10050
+ }
10051
+ }
10052
+ /**
10053
+ * Creates a wrapper function for resize handlers.
10054
+ * @param expression The expression string to evaluate.
10055
+ * @returns A function that handles the resize event.
10056
+ */
10057
+ #createResizeHandlerWrapper(expression) {
10058
+ const identifiers = this.#dependentIdentifiers ?? [];
10059
+ const vNode = this.#vNode;
10060
+ // Return a function that handles the resize event with proper scope
10061
+ return (entries) => {
10062
+ const bindings = vNode.bindings;
10063
+ const $ctx = {
10064
+ element: vNode.node,
10065
+ vnode: vNode,
10066
+ userData: vNode.userData
10067
+ };
9598
10068
  // If the expression is just a method name, call it with bindings as 'this'
9599
10069
  const trimmedExpr = expression.trim();
9600
10070
  if (identifiers.includes(trimmedExpr) && typeof bindings?.get(trimmedExpr) === 'function') {
9601
10071
  const methodName = trimmedExpr;
9602
10072
  const originalMethod = bindings?.get(methodName);
9603
10073
  // Call the method with bindings as 'this' context
9604
- // This allows the method to access and modify bindings properties via 'this'
9605
- return originalMethod(event);
10074
+ // Pass entries as first argument and $ctx as second argument
10075
+ return originalMethod(entries, $ctx);
9606
10076
  }
9607
10077
  // For inline expressions, evaluate normally
10078
+ // Note: inline expressions receive entries and $ctx as parameters
9608
10079
  const values = identifiers.map(id => vNode.bindings?.get(id));
9609
- const args = identifiers.join(", ");
10080
+ const args = [...identifiers, 'entries', '$ctx'].join(", ");
9610
10081
  const funcBody = `return (${expression});`;
9611
10082
  const func = new Function(args, funcBody);
9612
- return func.call(bindings?.raw, ...values, event);
10083
+ return func.call(bindings?.raw, ...values, entries, $ctx);
9613
10084
  };
9614
10085
  }
9615
10086
  }
@@ -9839,7 +10310,11 @@
9839
10310
  context.attribute.name.startsWith(":") ||
9840
10311
  // v-model, v-model.<modifier>
9841
10312
  context.attribute.name === StandardDirectiveName.V_MODEL ||
9842
- context.attribute.name.startsWith(StandardDirectiveName.V_MODEL + ".")) {
10313
+ context.attribute.name.startsWith(StandardDirectiveName.V_MODEL + ".") ||
10314
+ // v-resize
10315
+ context.attribute.name === StandardDirectiveName.V_RESIZE ||
10316
+ // v-intersection
10317
+ context.attribute.name === StandardDirectiveName.V_INTERSECTION) {
9843
10318
  return true;
9844
10319
  }
9845
10320
  return false;
@@ -9878,6 +10353,14 @@
9878
10353
  context.attribute.name.startsWith(StandardDirectiveName.V_MODEL + ".")) {
9879
10354
  return new VModelDirective(context);
9880
10355
  }
10356
+ // v-resize
10357
+ if (context.attribute.name === StandardDirectiveName.V_RESIZE) {
10358
+ return new VResizeDirective(context);
10359
+ }
10360
+ // v-intersection
10361
+ if (context.attribute.name === StandardDirectiveName.V_INTERSECTION) {
10362
+ return new VIntersectionDirective(context);
10363
+ }
9881
10364
  throw new Error(`The attribute "${context.attribute.name}" cannot be parsed by ${this.name}.`);
9882
10365
  }
9883
10366
  }