@odoo/o-spreadsheet 18.0.23 → 18.0.25

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.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 18.0.23
6
- * @date 2025-04-14T17:16:35.374Z
7
- * @hash f560133
5
+ * @version 18.0.25
6
+ * @date 2025-04-25T08:08:43.377Z
7
+ * @hash 24aac2c
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -3663,11 +3663,13 @@ const CellErrorType = {
3663
3663
  NullError: "#NULL!",
3664
3664
  };
3665
3665
  const errorTypes = new Set(Object.values(CellErrorType));
3666
- class EvaluationError extends Error {
3666
+ class EvaluationError {
3667
+ message;
3667
3668
  value;
3668
3669
  constructor(message = _t("Error"), value = CellErrorType.GenericError) {
3669
- super(message);
3670
+ this.message = message;
3670
3671
  this.value = value;
3672
+ this.message = message.toString();
3671
3673
  }
3672
3674
  }
3673
3675
  class BadExpressionError extends EvaluationError {
@@ -6734,6 +6736,12 @@ function tokenizeString(chars) {
6734
6736
  }
6735
6737
  return null;
6736
6738
  }
6739
+ /**
6740
+ - \p{L} is for any letter (from any language)
6741
+ - \p{N} is for any number
6742
+ - the u flag at the end is for unicode, which enables the `\p{...}` syntax
6743
+ */
6744
+ const unicodeSymbolCharRegexp = /\p{L}|\p{N}|_|\.|!|\$/u;
6737
6745
  const SYMBOL_CHARS = new Set("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.!$");
6738
6746
  /**
6739
6747
  * A "Symbol" is just basically any word-like element that can appear in a
@@ -6774,7 +6782,8 @@ function tokenizeSymbol(chars) {
6774
6782
  };
6775
6783
  }
6776
6784
  }
6777
- while (chars.current && SYMBOL_CHARS.has(chars.current)) {
6785
+ while (chars.current &&
6786
+ (SYMBOL_CHARS.has(chars.current) || chars.current.match(unicodeSymbolCharRegexp))) {
6778
6787
  result += chars.shift();
6779
6788
  }
6780
6789
  if (result.length) {
@@ -9037,7 +9046,7 @@ function transformZone(zone, executed) {
9037
9046
  if (executed.type === "ADD_COLUMNS_ROWS") {
9038
9047
  return expandZoneOnInsertion(zone, executed.dimension === "COL" ? "left" : "top", executed.base, executed.position, executed.quantity);
9039
9048
  }
9040
- return { ...zone };
9049
+ return zone;
9041
9050
  }
9042
9051
  function transformRangeData(range, executed) {
9043
9052
  const deletedSheet = executed.type === "DELETE_SHEET" && executed.sheetId;
@@ -15659,9 +15668,11 @@ const GAUGE_TITLE_PADDING_LEFT = SCORECARD_GAUGE_CHART_PADDING;
15659
15668
  const GAUGE_TITLE_PADDING_TOP = SCORECARD_GAUGE_CHART_PADDING;
15660
15669
  function drawGaugeChart(canvas, runtime) {
15661
15670
  const canvasBoundingRect = canvas.getBoundingClientRect();
15662
- canvas.width = canvasBoundingRect.width;
15663
- canvas.height = canvasBoundingRect.height;
15671
+ const dpr = window.devicePixelRatio || 1;
15672
+ canvas.width = dpr * canvasBoundingRect.width;
15673
+ canvas.height = dpr * canvasBoundingRect.height;
15664
15674
  const ctx = canvas.getContext("2d");
15675
+ ctx.scale(dpr, dpr);
15665
15676
  const config = getGaugeRenderingConfig(canvasBoundingRect, runtime, ctx);
15666
15677
  drawBackground(ctx, config);
15667
15678
  drawGauge(ctx, config);
@@ -16223,9 +16234,11 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
16223
16234
  };
16224
16235
  function drawScoreChart(structure, canvas) {
16225
16236
  const ctx = canvas.getContext("2d");
16226
- canvas.width = structure.canvas.width;
16227
- const availableWidth = canvas.width - DEFAULT_CHART_PADDING;
16228
- canvas.height = structure.canvas.height;
16237
+ const dpr = window.devicePixelRatio || 1;
16238
+ canvas.width = dpr * structure.canvas.width;
16239
+ canvas.height = dpr * structure.canvas.height;
16240
+ ctx.scale(dpr, dpr);
16241
+ const availableWidth = structure.canvas.width - DEFAULT_CHART_PADDING;
16229
16242
  ctx.fillStyle = structure.canvas.backgroundColor;
16230
16243
  ctx.fillRect(0, 0, structure.canvas.width, structure.canvas.height);
16231
16244
  if (structure.title) {
@@ -16936,6 +16949,10 @@ class ChartJsComponent extends Component {
16936
16949
  this.currentRuntime = runtime;
16937
16950
  }
16938
16951
  });
16952
+ useEffect(() => {
16953
+ this.currentRuntime = this.chartRuntime;
16954
+ this.updateChartJs(deepCopy(this.currentRuntime));
16955
+ }, () => [window.devicePixelRatio]);
16939
16956
  }
16940
16957
  createChart(chartData) {
16941
16958
  const canvas = this.canvas.el;
@@ -16977,7 +16994,7 @@ class ScorecardChart extends Component {
16977
16994
  useEffect(this.createChart.bind(this), () => {
16978
16995
  const canvas = this.canvas.el;
16979
16996
  const rect = canvas.getBoundingClientRect();
16980
- return [rect.width, rect.height, this.runtime, this.canvas.el];
16997
+ return [rect.width, rect.height, this.runtime, this.canvas.el, window.devicePixelRatio];
16981
16998
  });
16982
16999
  }
16983
17000
  createChart() {
@@ -17445,7 +17462,7 @@ const MINVERSE = {
17445
17462
  assertSquareMatrix(_t("The argument square_matrix must have the same number of columns and rows."), _matrix);
17446
17463
  const { inverted } = invertMatrix(_matrix);
17447
17464
  if (!inverted) {
17448
- throw new EvaluationError(_t("The matrix is not invertible."));
17465
+ return new EvaluationError(_t("The matrix is not invertible."));
17449
17466
  }
17450
17467
  return inverted;
17451
17468
  },
@@ -17605,7 +17622,7 @@ const TOCOL = {
17605
17622
  .flat()
17606
17623
  .filter(shouldKeepValue(_ignore));
17607
17624
  if (result.length === 0) {
17608
- throw new NotAvailableError(_t("No results for the given arguments of TOCOL."));
17625
+ return new NotAvailableError(_t("No results for the given arguments of TOCOL."));
17609
17626
  }
17610
17627
  return [result];
17611
17628
  },
@@ -17626,7 +17643,7 @@ const TOROW = {
17626
17643
  .filter(shouldKeepValue(_ignore))
17627
17644
  .map((item) => [item]);
17628
17645
  if (result.length === 0 || result[0].length === 0) {
17629
- throw new NotAvailableError(_t("No results for the given arguments of TOROW."));
17646
+ return new NotAvailableError(_t("No results for the given arguments of TOROW."));
17630
17647
  }
17631
17648
  return result;
17632
17649
  },
@@ -18473,7 +18490,7 @@ const PRODUCT = {
18473
18490
  count += 1;
18474
18491
  }
18475
18492
  if (isEvaluationError(f)) {
18476
- throw j;
18493
+ return j;
18477
18494
  }
18478
18495
  }
18479
18496
  }
@@ -19376,7 +19393,7 @@ const MATTHEWS = {
19376
19393
  const flatY = dataY.flat();
19377
19394
  assertSameNumberOfElements(flatX, flatY);
19378
19395
  if (flatX.length === 0) {
19379
- throw new EvaluationError(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
19396
+ return new EvaluationError(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
19380
19397
  }
19381
19398
  const n = flatX.length;
19382
19399
  let trueN = 0, trueP = 0, falseP = 0, falseN = 0;
@@ -19739,7 +19756,7 @@ const RANK = {
19739
19756
  }
19740
19757
  }
19741
19758
  if (!found) {
19742
- throw new NotAvailableError(_t("Value not found in the given data."));
19759
+ return new NotAvailableError(_t("Value not found in the given data."));
19743
19760
  }
19744
19761
  return rank;
19745
19762
  },
@@ -21364,7 +21381,7 @@ const FILTER = {
21364
21381
  }
21365
21382
  }
21366
21383
  if (!result.length) {
21367
- throw new NotAvailableError(_t("No match found in FILTER evaluation"));
21384
+ return new NotAvailableError(_t("No match found in FILTER evaluation"));
21368
21385
  }
21369
21386
  return mode === "row" ? transposeMatrix(result) : result;
21370
21387
  },
@@ -21493,7 +21510,7 @@ const UNIQUE = {
21493
21510
  result.push(row.data);
21494
21511
  }
21495
21512
  if (!result.length)
21496
- throw new EvaluationError(_t("No unique values found"));
21513
+ return new EvaluationError(_t("No unique values found"));
21497
21514
  return _byColumn ? result : transposeMatrix(result);
21498
21515
  },
21499
21516
  isExported: true,
@@ -24419,7 +24436,7 @@ const IFS = {
24419
24436
  return result;
24420
24437
  }
24421
24438
  }
24422
- throw new EvaluationError(_t("No match."));
24439
+ return new EvaluationError(_t("No match."));
24423
24440
  },
24424
24441
  isExported: true,
24425
24442
  };
@@ -24610,7 +24627,7 @@ const COLUMN = {
24610
24627
  ],
24611
24628
  compute: function (cellReference) {
24612
24629
  if (isEvaluationError(cellReference?.value)) {
24613
- throw cellReference;
24630
+ return cellReference;
24614
24631
  }
24615
24632
  const column = cellReference === undefined
24616
24633
  ? this.__originCellPosition?.col
@@ -24628,7 +24645,7 @@ const COLUMNS = {
24628
24645
  args: [arg("range (meta)", _t("The range whose column count will be returned."))],
24629
24646
  compute: function (range) {
24630
24647
  if (isEvaluationError(range?.value)) {
24631
- throw range;
24648
+ return range;
24632
24649
  }
24633
24650
  const zone = toZone(range.value);
24634
24651
  return zone.right - zone.left + 1;
@@ -24706,11 +24723,11 @@ const INDIRECT = {
24706
24723
  compute: function (reference, useA1Notation = { value: true }) {
24707
24724
  let _reference = reference?.value?.toString();
24708
24725
  if (!_reference) {
24709
- throw new InvalidReferenceError(_t("Reference should be defined."));
24726
+ return new InvalidReferenceError(_t("Reference should be defined."));
24710
24727
  }
24711
24728
  const _useA1Notation = toBoolean(useA1Notation);
24712
24729
  if (!_useA1Notation) {
24713
- throw new EvaluationError(_t("R1C1 notation is not supported."));
24730
+ return new EvaluationError(_t("R1C1 notation is not supported."));
24714
24731
  }
24715
24732
  const sheetId = this.__originSheetId;
24716
24733
  const originPosition = this.__originCellPosition;
@@ -24722,7 +24739,7 @@ const INDIRECT = {
24722
24739
  }
24723
24740
  const range = this.getters.getRangeFromSheetXC(sheetId, _reference);
24724
24741
  if (range === undefined || range.invalidXc || range.invalidSheetName) {
24725
- throw new InvalidReferenceError();
24742
+ return new InvalidReferenceError();
24726
24743
  }
24727
24744
  if (originPosition) {
24728
24745
  this.addDependencies?.(originPosition, [range]);
@@ -24833,7 +24850,7 @@ const ROW = {
24833
24850
  ],
24834
24851
  compute: function (cellReference) {
24835
24852
  if (isEvaluationError(cellReference?.value)) {
24836
- throw cellReference;
24853
+ return cellReference;
24837
24854
  }
24838
24855
  const row = cellReference === undefined
24839
24856
  ? this.__originCellPosition?.row
@@ -24851,7 +24868,7 @@ const ROWS = {
24851
24868
  args: [arg("range (meta)", _t("The range whose row count will be returned."))],
24852
24869
  compute: function (range) {
24853
24870
  if (isEvaluationError(range?.value)) {
24854
- throw range;
24871
+ return range;
24855
24872
  }
24856
24873
  const zone = toZone(range.value);
24857
24874
  return zone.bottom - zone.top + 1;
@@ -25037,11 +25054,11 @@ const PIVOT = {
25037
25054
  const _pivotFormulaId = toString(pivotFormulaId);
25038
25055
  const _rowCount = toNumber(rowCount, this.locale);
25039
25056
  if (_rowCount < 0) {
25040
- throw new EvaluationError(_t("The number of rows must be positive."));
25057
+ return new EvaluationError(_t("The number of rows must be positive."));
25041
25058
  }
25042
25059
  const _columnCount = toNumber(columnCount, this.locale);
25043
25060
  if (_columnCount < 0) {
25044
- throw new EvaluationError(_t("The number of columns must be positive."));
25061
+ return new EvaluationError(_t("The number of columns must be positive."));
25045
25062
  }
25046
25063
  const _includeColumnHeaders = toBoolean(includeColumnHeaders);
25047
25064
  const _includedTotal = toBoolean(includeTotal);
@@ -25109,7 +25126,7 @@ const OFFSET = {
25109
25126
  }
25110
25127
  const _cellReference = cellReference?.value;
25111
25128
  if (!_cellReference) {
25112
- throw new Error("In this context, the function OFFSET needs to have a cell or range in parameter.");
25129
+ return new EvaluationError("In this context, the function OFFSET needs to have a cell or range in parameter.");
25113
25130
  }
25114
25131
  const zone = toZone(_cellReference);
25115
25132
  let offsetHeight = zone.bottom - zone.top + 1;
@@ -28915,7 +28932,7 @@ class GaugeChartComponent extends Component {
28915
28932
  useEffect(() => drawGaugeChart(this.canvas.el, this.runtime), () => {
28916
28933
  const canvas = this.canvas.el;
28917
28934
  const rect = canvas.getBoundingClientRect();
28918
- return [rect.width, rect.height, this.runtime, this.canvas.el];
28935
+ return [rect.width, rect.height, this.runtime, this.canvas.el, window.devicePixelRatio];
28919
28936
  });
28920
28937
  }
28921
28938
  }
@@ -37473,7 +37490,7 @@ class ColorPicker extends Component {
37473
37490
  }
37474
37491
  setHexColor(ev) {
37475
37492
  // only support HEX code input
37476
- const val = ev.target.value.slice(0, 7);
37493
+ const val = ev.target.value.replace("##", "#").slice(0, 7);
37477
37494
  this.state.customHexColor = val;
37478
37495
  if (!isColorValid(val)) ;
37479
37496
  else {
@@ -48008,39 +48025,6 @@ function useCellHovered(env, gridRef, callback) {
48008
48025
  }
48009
48026
  return hoveredPosition;
48010
48027
  }
48011
- function useTouchMove(gridRef, handler, canMoveUp) {
48012
- let x = null;
48013
- let y = null;
48014
- function onTouchStart(ev) {
48015
- if (ev.touches.length !== 1)
48016
- return;
48017
- x = ev.touches[0].clientX;
48018
- y = ev.touches[0].clientY;
48019
- }
48020
- function onTouchEnd() {
48021
- x = null;
48022
- y = null;
48023
- }
48024
- function onTouchMove(ev) {
48025
- if (ev.touches.length !== 1)
48026
- return;
48027
- // On mobile browsers, swiping down is often associated with "pull to refresh".
48028
- // We only want this behavior if the grid is already at the top.
48029
- // Otherwise we only want to move the canvas up, without triggering any refresh.
48030
- if (canMoveUp()) {
48031
- ev.preventDefault();
48032
- ev.stopPropagation();
48033
- }
48034
- const currentX = ev.touches[0].clientX;
48035
- const currentY = ev.touches[0].clientY;
48036
- handler(x - currentX, y - currentY);
48037
- x = currentX;
48038
- y = currentY;
48039
- }
48040
- useRefListener(gridRef, "touchstart", onTouchStart);
48041
- useRefListener(gridRef, "touchend", onTouchEnd);
48042
- useRefListener(gridRef, "touchmove", onTouchMove);
48043
- }
48044
48028
  class GridOverlay extends Component {
48045
48029
  static template = "o-spreadsheet-GridOverlay";
48046
48030
  static props = {
@@ -48088,10 +48072,6 @@ class GridOverlay extends Component {
48088
48072
  onWillUnmount(() => {
48089
48073
  resizeObserver.disconnect();
48090
48074
  });
48091
- useTouchMove(this.gridOverlay, this.props.onGridMoved, () => {
48092
- const { scrollY } = this.env.model.getters.getActiveSheetDOMScrollInfo();
48093
- return scrollY > 0;
48094
- });
48095
48075
  this.cellPopovers = useStore(CellPopoverStore);
48096
48076
  this.paintFormatStore = useStore(PaintFormatStore);
48097
48077
  }
@@ -49440,6 +49420,73 @@ function useGridDrawing(refName, model, canvasSize) {
49440
49420
  }
49441
49421
  }
49442
49422
 
49423
+ const friction = 0.95;
49424
+ const verticalScrollFactor = 1;
49425
+ const horizontalScrollFactor = 1;
49426
+ function useTouchScroll(ref, updateScroll, canMoveUp) {
49427
+ let lastX = 0;
49428
+ let lastY = 0;
49429
+ let velocityX = 0;
49430
+ let velocityY = 0;
49431
+ let isMouseDown = false;
49432
+ let lastTime = 0;
49433
+ useRefListener(ref, "touchstart", onTouchStart, { capture: false });
49434
+ useRefListener(ref, "touchmove", onTouchMove, { capture: false });
49435
+ useRefListener(ref, "touchend", onTouchEnd, { capture: false });
49436
+ function onTouchStart(event) {
49437
+ isMouseDown = true;
49438
+ ({ clientX: lastX, clientY: lastY } = event.touches[0]);
49439
+ velocityX = 0;
49440
+ velocityY = 0;
49441
+ }
49442
+ function onTouchMove(event) {
49443
+ if (!isMouseDown)
49444
+ return;
49445
+ const currentTime = Date.now();
49446
+ const { clientX, clientY } = event.touches[0];
49447
+ let deltaX = lastX - clientX;
49448
+ let deltaY = lastY - clientY;
49449
+ const elapsedTime = currentTime - lastTime;
49450
+ velocityX = deltaX / elapsedTime;
49451
+ velocityY = deltaY / elapsedTime;
49452
+ lastX = clientX;
49453
+ lastY = clientY;
49454
+ lastTime = currentTime;
49455
+ if (canMoveUp()) {
49456
+ if (event.cancelable) {
49457
+ event.preventDefault();
49458
+ }
49459
+ event.stopPropagation();
49460
+ }
49461
+ updateScroll(deltaX * horizontalScrollFactor, deltaY * verticalScrollFactor);
49462
+ }
49463
+ function onTouchEnd(ev) {
49464
+ isMouseDown = false;
49465
+ lastX = lastY = 0;
49466
+ requestAnimationFrame(scroll);
49467
+ }
49468
+ function scroll() {
49469
+ if (Math.abs(velocityX) < 0.05) {
49470
+ velocityX = 0;
49471
+ }
49472
+ if (Math.abs(velocityY) < 0.05) {
49473
+ velocityY = 0;
49474
+ }
49475
+ if (!velocityX && !velocityY) {
49476
+ return;
49477
+ }
49478
+ const currentTime = Date.now();
49479
+ const elapsedTime = Math.abs(currentTime - lastTime);
49480
+ const deltaX = velocityX * elapsedTime;
49481
+ const deltaY = velocityY * elapsedTime;
49482
+ updateScroll(deltaX * horizontalScrollFactor, deltaY * verticalScrollFactor);
49483
+ lastTime = currentTime;
49484
+ velocityX *= friction;
49485
+ velocityY *= friction;
49486
+ requestAnimationFrame(scroll);
49487
+ }
49488
+ }
49489
+
49443
49490
  function useWheelHandler(handler) {
49444
49491
  function normalize(val, deltaMode) {
49445
49492
  return val * (deltaMode === 0 ? 1 : DEFAULT_CELL_HEIGHT);
@@ -50060,6 +50107,10 @@ class Grid extends Component {
50060
50107
  this.DOMFocusableElementStore.focusableElement?.focus();
50061
50108
  }
50062
50109
  }, () => [this.sidePanel.isOpen]);
50110
+ useTouchScroll(this.gridRef, this.moveCanvas.bind(this), () => {
50111
+ const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
50112
+ return scrollY > 0;
50113
+ });
50063
50114
  }
50064
50115
  onCellHovered({ col, row }) {
50065
50116
  this.hoveredCell.hover({ col, row });
@@ -59855,6 +59906,16 @@ function withPivotPresentationLayer (PivotClass) {
59855
59906
  }
59856
59907
  return values;
59857
59908
  }
59909
+ else if (rowDomain.length === this.definition.rows.length &&
59910
+ colDomain.length &&
59911
+ colDomain.length < this.definition.columns.length) {
59912
+ const colSubTree = this.getSubTreeMatchingDomain(table.getColTree(), colDomain);
59913
+ const domains = this.treeToLeafDomains(colSubTree, colDomain);
59914
+ for (const domain of domains) {
59915
+ values.push(this._getPivotCellValueAndFormat(measure.id, rowDomain.concat(domain)));
59916
+ }
59917
+ return values;
59918
+ }
59858
59919
  else {
59859
59920
  const tree = table.getRowTree();
59860
59921
  const subTree = this.getSubTreeMatchingDomain(tree, rowDomain);
@@ -61386,10 +61447,8 @@ function mergeTransformation(toTransform, executed) {
61386
61447
  }
61387
61448
  const target = [];
61388
61449
  for (const zone1 of toTransform.target) {
61389
- for (const zone2 of executed.target) {
61390
- if (!overlap(zone1, zone2)) {
61391
- target.push({ ...zone1 });
61392
- }
61450
+ if (executed.target.every((zone2) => !overlap(zone1, zone2))) {
61451
+ target.push(zone1);
61393
61452
  }
61394
61453
  }
61395
61454
  if (target.length) {
@@ -67617,6 +67676,10 @@ class SpreadsheetDashboard extends Component {
67617
67676
  this.hoveredCell.clear();
67618
67677
  });
67619
67678
  this.cellPopovers = useStore(CellPopoverStore);
67679
+ useTouchScroll(gridRef, this.moveCanvas.bind(this), () => {
67680
+ const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
67681
+ return scrollY > 0;
67682
+ });
67620
67683
  }
67621
67684
  onCellHovered({ col, row }) {
67622
67685
  this.hoveredCell.hover({ col, row });
@@ -73669,6 +73732,6 @@ const constants = {
73669
73732
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
73670
73733
 
73671
73734
 
73672
- __info__.version = "18.0.23";
73673
- __info__.date = "2025-04-14T17:16:35.374Z";
73674
- __info__.hash = "f560133";
73735
+ __info__.version = "18.0.25";
73736
+ __info__.date = "2025-04-25T08:08:43.377Z";
73737
+ __info__.hash = "24aac2c";