@odoo/o-spreadsheet 17.4.18 → 17.4.20
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/dist/o-spreadsheet.cjs.js +128 -55
- package/dist/o-spreadsheet.d.ts +18 -4
- package/dist/o-spreadsheet.esm.js +128 -55
- package/dist/o-spreadsheet.iife.js +128 -55
- package/dist/o-spreadsheet.iife.min.js +8 -8
- package/dist/o_spreadsheet.xml +4 -4
- package/package.json +1 -1
|
@@ -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 17.4.
|
|
6
|
-
* @date 2025-01-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 17.4.20
|
|
6
|
+
* @date 2025-01-31T08:00:07.103Z
|
|
7
|
+
* @hash 54a344a
|
|
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';
|
|
@@ -1952,11 +1952,11 @@ const getInvaluableSymbolsRegexp = memoize(function getInvaluableSymbolsRegexp(l
|
|
|
1952
1952
|
* number from the point of view of the isNumber function.
|
|
1953
1953
|
*/
|
|
1954
1954
|
function parseNumber(str, locale) {
|
|
1955
|
+
// remove invaluable characters
|
|
1956
|
+
str = str.replace(getInvaluableSymbolsRegexp(locale), "");
|
|
1955
1957
|
if (locale.decimalSeparator !== ".") {
|
|
1956
1958
|
str = str.replace(locale.decimalSeparator, ".");
|
|
1957
1959
|
}
|
|
1958
|
-
// remove invaluable characters
|
|
1959
|
-
str = str.replace(getInvaluableSymbolsRegexp(locale), "");
|
|
1960
1960
|
let n = Number(str);
|
|
1961
1961
|
if (isNaN(n) && str.includes("%")) {
|
|
1962
1962
|
n = Number(str.split("%")[0]);
|
|
@@ -3013,15 +3013,18 @@ function dichotomicSearch(data, target, mode, sortOrder, rangeLength, getValueIn
|
|
|
3013
3013
|
let currentIndex;
|
|
3014
3014
|
let currentVal;
|
|
3015
3015
|
let currentType;
|
|
3016
|
+
const getValue = sortOrder === "desc"
|
|
3017
|
+
? (i) => normalizeValue(getValueInData(data, rangeLength - i - 1))
|
|
3018
|
+
: (i) => normalizeValue(getValueInData(data, i));
|
|
3016
3019
|
while (indexRight - indexLeft >= 0) {
|
|
3017
3020
|
indexMedian = Math.floor((indexLeft + indexRight) / 2);
|
|
3018
3021
|
currentIndex = indexMedian;
|
|
3019
|
-
currentVal =
|
|
3022
|
+
currentVal = getValue(currentIndex);
|
|
3020
3023
|
currentType = typeof currentVal;
|
|
3021
3024
|
// 1 - linear search to find value with the same type
|
|
3022
3025
|
while (indexLeft < currentIndex && targetType !== currentType) {
|
|
3023
3026
|
currentIndex--;
|
|
3024
|
-
currentVal =
|
|
3027
|
+
currentVal = getValue(currentIndex);
|
|
3025
3028
|
currentType = typeof currentVal;
|
|
3026
3029
|
}
|
|
3027
3030
|
if (currentType !== targetType || currentVal === undefined || currentVal === null) {
|
|
@@ -3037,8 +3040,7 @@ function dichotomicSearch(data, target, mode, sortOrder, rangeLength, getValueIn
|
|
|
3037
3040
|
if (matchVal === undefined ||
|
|
3038
3041
|
matchVal === null ||
|
|
3039
3042
|
matchVal < currentVal ||
|
|
3040
|
-
(matchVal === currentVal &&
|
|
3041
|
-
(matchVal === currentVal && sortOrder === "desc" && matchValIndex > currentIndex)) {
|
|
3043
|
+
(matchVal === currentVal && matchValIndex < currentIndex)) {
|
|
3042
3044
|
matchVal = currentVal;
|
|
3043
3045
|
matchValIndex = currentIndex;
|
|
3044
3046
|
}
|
|
@@ -3046,15 +3048,13 @@ function dichotomicSearch(data, target, mode, sortOrder, rangeLength, getValueIn
|
|
|
3046
3048
|
else if (mode === "nextGreater" && currentVal >= _target) {
|
|
3047
3049
|
if (matchVal === undefined ||
|
|
3048
3050
|
matchVal > currentVal ||
|
|
3049
|
-
(matchVal === currentVal &&
|
|
3050
|
-
(matchVal === currentVal && sortOrder === "desc" && matchValIndex > currentIndex)) {
|
|
3051
|
+
(matchVal === currentVal && matchValIndex < currentIndex)) {
|
|
3051
3052
|
matchVal = currentVal;
|
|
3052
3053
|
matchValIndex = currentIndex;
|
|
3053
3054
|
}
|
|
3054
3055
|
}
|
|
3055
3056
|
// 3 - give new indexes for the Binary search
|
|
3056
|
-
if ((
|
|
3057
|
-
(sortOrder === "desc" && currentVal <= _target)) {
|
|
3057
|
+
if (currentVal > _target || (mode === "strict" && currentVal === _target)) {
|
|
3058
3058
|
indexRight = currentIndex - 1;
|
|
3059
3059
|
}
|
|
3060
3060
|
else {
|
|
@@ -3062,7 +3062,10 @@ function dichotomicSearch(data, target, mode, sortOrder, rangeLength, getValueIn
|
|
|
3062
3062
|
}
|
|
3063
3063
|
}
|
|
3064
3064
|
// note that valMinIndex could be 0
|
|
3065
|
-
|
|
3065
|
+
if (matchValIndex === undefined) {
|
|
3066
|
+
return -1;
|
|
3067
|
+
}
|
|
3068
|
+
return sortOrder === "desc" ? rangeLength - matchValIndex - 1 : matchValIndex;
|
|
3066
3069
|
}
|
|
3067
3070
|
/**
|
|
3068
3071
|
* Perform a linear search and return the index of the match.
|
|
@@ -21611,6 +21614,12 @@ class Composer extends Component {
|
|
|
21611
21614
|
}
|
|
21612
21615
|
this.contentHelper.updateEl(el);
|
|
21613
21616
|
});
|
|
21617
|
+
this.env.model.selection.observe(this, {
|
|
21618
|
+
handleEvent: () => this.autoCompleteState.hide(),
|
|
21619
|
+
});
|
|
21620
|
+
onWillUnmount(() => {
|
|
21621
|
+
this.env.model.selection.detachObserver(this);
|
|
21622
|
+
});
|
|
21614
21623
|
useEffect(() => {
|
|
21615
21624
|
this.processContent();
|
|
21616
21625
|
});
|
|
@@ -26457,6 +26466,10 @@ class Popover extends Component {
|
|
|
26457
26466
|
this.currentDisplayValue = newDisplay;
|
|
26458
26467
|
if (!anchor)
|
|
26459
26468
|
return;
|
|
26469
|
+
el.style.top = "";
|
|
26470
|
+
el.style.left = "";
|
|
26471
|
+
el.style["max-height"] = "";
|
|
26472
|
+
el.style["max-width"] = "";
|
|
26460
26473
|
const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
|
|
26461
26474
|
let elDims = {
|
|
26462
26475
|
width: el.getBoundingClientRect().width,
|
|
@@ -39449,7 +39462,7 @@ class GridComposer extends Component {
|
|
|
39449
39462
|
return;
|
|
39450
39463
|
}
|
|
39451
39464
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
39452
|
-
const zone = this.env.model.getters.
|
|
39465
|
+
const zone = positionToZone(this.env.model.getters.getSelection().anchor.cell);
|
|
39453
39466
|
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
39454
39467
|
if (!deepEquals(rect, this.rect) || sheetId !== this.composerStore.currentEditedCell.sheetId) {
|
|
39455
39468
|
this.isCellReferenceVisible = true;
|
|
@@ -41204,13 +41217,23 @@ class GridRenderer {
|
|
|
41204
41217
|
drawLayer(renderingContext, layer) {
|
|
41205
41218
|
switch (layer) {
|
|
41206
41219
|
case "Background":
|
|
41207
|
-
|
|
41208
|
-
this.
|
|
41209
|
-
|
|
41210
|
-
|
|
41211
|
-
|
|
41212
|
-
|
|
41213
|
-
|
|
41220
|
+
this.drawGlobalBackground(renderingContext);
|
|
41221
|
+
for (const zone of this.getters.getAllActiveViewportsZones()) {
|
|
41222
|
+
const { ctx } = renderingContext;
|
|
41223
|
+
ctx.save();
|
|
41224
|
+
ctx.beginPath();
|
|
41225
|
+
const rect = this.getters.getVisibleRect(zone);
|
|
41226
|
+
ctx.rect(rect.x, rect.y, rect.width, rect.height);
|
|
41227
|
+
ctx.clip();
|
|
41228
|
+
const boxes = this.getGridBoxes(zone);
|
|
41229
|
+
this.drawBackground(renderingContext, boxes);
|
|
41230
|
+
this.drawOverflowingCellBackground(renderingContext, boxes);
|
|
41231
|
+
this.drawCellBackground(renderingContext, boxes);
|
|
41232
|
+
this.drawBorders(renderingContext, boxes);
|
|
41233
|
+
this.drawTexts(renderingContext, boxes);
|
|
41234
|
+
this.drawIcon(renderingContext, boxes);
|
|
41235
|
+
ctx.restore();
|
|
41236
|
+
}
|
|
41214
41237
|
this.drawFrozenPanes(renderingContext);
|
|
41215
41238
|
break;
|
|
41216
41239
|
case "Headers":
|
|
@@ -41221,12 +41244,15 @@ class GridRenderer {
|
|
|
41221
41244
|
break;
|
|
41222
41245
|
}
|
|
41223
41246
|
}
|
|
41224
|
-
|
|
41225
|
-
const { ctx
|
|
41247
|
+
drawGlobalBackground(renderingContext) {
|
|
41248
|
+
const { ctx } = renderingContext;
|
|
41226
41249
|
const { width, height } = this.getters.getSheetViewDimensionWithHeaders();
|
|
41227
41250
|
// white background
|
|
41228
41251
|
ctx.fillStyle = "#ffffff";
|
|
41229
41252
|
ctx.fillRect(0, 0, width + CANVAS_SHIFT, height + CANVAS_SHIFT);
|
|
41253
|
+
}
|
|
41254
|
+
drawBackground(renderingContext, boxes) {
|
|
41255
|
+
const { ctx, thinLineWidth } = renderingContext;
|
|
41230
41256
|
const areGridLinesVisible = !this.getters.isDashboard() &&
|
|
41231
41257
|
this.getters.getGridLinesVisibility(this.getters.getActiveSheetId());
|
|
41232
41258
|
const inset = areGridLinesVisible ? 0.1 * thinLineWidth : 0;
|
|
@@ -41651,7 +41677,7 @@ class GridRenderer {
|
|
|
41651
41677
|
const position = { sheetId, col, row };
|
|
41652
41678
|
const cell = this.getters.getEvaluatedCell(position);
|
|
41653
41679
|
const showFormula = this.getters.shouldShowFormulas();
|
|
41654
|
-
const { x, y, width, height } = this.getters.
|
|
41680
|
+
const { x, y, width, height } = this.getters.getRect(zone);
|
|
41655
41681
|
const { verticalAlign } = this.getters.getCellStyle(position);
|
|
41656
41682
|
const box = {
|
|
41657
41683
|
x,
|
|
@@ -41767,12 +41793,16 @@ class GridRenderer {
|
|
|
41767
41793
|
}
|
|
41768
41794
|
return box;
|
|
41769
41795
|
}
|
|
41770
|
-
getGridBoxes() {
|
|
41796
|
+
getGridBoxes(zone) {
|
|
41771
41797
|
const boxes = [];
|
|
41772
|
-
const visibleCols = this.getters
|
|
41798
|
+
const visibleCols = this.getters
|
|
41799
|
+
.getSheetViewVisibleCols()
|
|
41800
|
+
.filter((col) => col >= zone.left && col <= zone.right);
|
|
41773
41801
|
const left = visibleCols[0];
|
|
41774
41802
|
const right = visibleCols[visibleCols.length - 1];
|
|
41775
|
-
const visibleRows = this.getters
|
|
41803
|
+
const visibleRows = this.getters
|
|
41804
|
+
.getSheetViewVisibleRows()
|
|
41805
|
+
.filter((row) => row >= zone.top && row <= zone.bottom);
|
|
41776
41806
|
const top = visibleRows[0];
|
|
41777
41807
|
const bottom = visibleRows[visibleRows.length - 1];
|
|
41778
41808
|
const viewport = { left, right, top, bottom };
|
|
@@ -58509,14 +58539,12 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
58509
58539
|
}
|
|
58510
58540
|
break;
|
|
58511
58541
|
case "AUTORESIZE_ROWS":
|
|
58512
|
-
|
|
58513
|
-
|
|
58514
|
-
|
|
58515
|
-
|
|
58516
|
-
|
|
58517
|
-
|
|
58518
|
-
});
|
|
58519
|
-
}
|
|
58542
|
+
this.dispatch("RESIZE_COLUMNS_ROWS", {
|
|
58543
|
+
elements: cmd.rows,
|
|
58544
|
+
dimension: "ROW",
|
|
58545
|
+
size: null,
|
|
58546
|
+
sheetId: cmd.sheetId,
|
|
58547
|
+
});
|
|
58520
58548
|
break;
|
|
58521
58549
|
}
|
|
58522
58550
|
}
|
|
@@ -60775,8 +60803,12 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
60775
60803
|
},
|
|
60776
60804
|
];
|
|
60777
60805
|
handler.paste({ zones: pasteTarget, sheetId }, data, { isCutOperation: true });
|
|
60806
|
+
const selection = pasteTarget[0];
|
|
60807
|
+
const col = selection.left;
|
|
60808
|
+
const row = selection.top;
|
|
60809
|
+
this.setSelectionMixin({ zone: selection, cell: { col, row } }, [selection]);
|
|
60778
60810
|
const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
|
|
60779
|
-
let currentIndex = cmd.base;
|
|
60811
|
+
let currentIndex = isBasedBefore ? cmd.base : cmd.base + 1;
|
|
60780
60812
|
for (const element of toRemove) {
|
|
60781
60813
|
const size = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, element);
|
|
60782
60814
|
this.dispatch("RESIZE_COLUMNS_ROWS", {
|
|
@@ -61059,22 +61091,33 @@ class InternalViewport {
|
|
|
61059
61091
|
}
|
|
61060
61092
|
/**
|
|
61061
61093
|
*
|
|
61062
|
-
*
|
|
61063
|
-
*
|
|
61094
|
+
* Computes the visible coordinates & dimensions of a given zone inside the viewport
|
|
61095
|
+
*
|
|
61064
61096
|
*/
|
|
61065
|
-
|
|
61097
|
+
getVisibleRect(zone) {
|
|
61066
61098
|
const targetZone = intersection(zone, this);
|
|
61067
61099
|
if (targetZone) {
|
|
61068
61100
|
const x = this.getters.getColRowOffset("COL", this.left, targetZone.left) + this.offsetCorrectionX;
|
|
61069
61101
|
const y = this.getters.getColRowOffset("ROW", this.top, targetZone.top) + this.offsetCorrectionY;
|
|
61070
61102
|
const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
|
|
61071
61103
|
const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
|
|
61072
|
-
return {
|
|
61073
|
-
|
|
61074
|
-
|
|
61075
|
-
|
|
61076
|
-
|
|
61077
|
-
|
|
61104
|
+
return { x, y, width, height };
|
|
61105
|
+
}
|
|
61106
|
+
return undefined;
|
|
61107
|
+
}
|
|
61108
|
+
/**
|
|
61109
|
+
*
|
|
61110
|
+
* @returns Computes the absolute coordinates & dimensions of a given zone inside the viewport
|
|
61111
|
+
*
|
|
61112
|
+
*/
|
|
61113
|
+
getFullRect(zone) {
|
|
61114
|
+
const targetZone = intersection(zone, this);
|
|
61115
|
+
if (targetZone) {
|
|
61116
|
+
const x = this.getters.getColRowOffset("COL", this.left, zone.left) + this.offsetCorrectionX;
|
|
61117
|
+
const y = this.getters.getColRowOffset("ROW", this.top, zone.top) + this.offsetCorrectionY;
|
|
61118
|
+
const width = this.getters.getColRowOffset("COL", zone.left, zone.right + 1);
|
|
61119
|
+
const height = this.getters.getColRowOffset("ROW", zone.top, zone.bottom + 1);
|
|
61120
|
+
return { x, y, width, height };
|
|
61078
61121
|
}
|
|
61079
61122
|
return undefined;
|
|
61080
61123
|
}
|
|
@@ -61244,6 +61287,8 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
61244
61287
|
"isPositionVisible",
|
|
61245
61288
|
"getColDimensionsInViewport",
|
|
61246
61289
|
"getRowDimensionsInViewport",
|
|
61290
|
+
"getAllActiveViewportsZones",
|
|
61291
|
+
"getRect",
|
|
61247
61292
|
];
|
|
61248
61293
|
viewports = {};
|
|
61249
61294
|
/**
|
|
@@ -61630,16 +61675,27 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
61630
61675
|
getVisibleRectWithoutHeaders(zone) {
|
|
61631
61676
|
const sheetId = this.getters.getActiveSheetId();
|
|
61632
61677
|
const viewportRects = this.getSubViewports(sheetId)
|
|
61633
|
-
.map((viewport) => viewport.
|
|
61678
|
+
.map((viewport) => viewport.getVisibleRect(zone))
|
|
61634
61679
|
.filter(isDefined);
|
|
61635
61680
|
if (viewportRects.length === 0) {
|
|
61636
61681
|
return { x: 0, y: 0, width: 0, height: 0 };
|
|
61637
61682
|
}
|
|
61638
|
-
|
|
61639
|
-
|
|
61640
|
-
|
|
61641
|
-
|
|
61642
|
-
|
|
61683
|
+
return this.recomposeRect(viewportRects);
|
|
61684
|
+
}
|
|
61685
|
+
/**
|
|
61686
|
+
* Computes the actual size and position (:Rect) of the zone on the canvas
|
|
61687
|
+
* regardless of the viewport dimensions.
|
|
61688
|
+
*/
|
|
61689
|
+
getRect(zone) {
|
|
61690
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
61691
|
+
const viewportRects = this.getSubViewports(sheetId)
|
|
61692
|
+
.map((viewport) => viewport.getFullRect(zone))
|
|
61693
|
+
.filter(isDefined);
|
|
61694
|
+
if (viewportRects.length === 0) {
|
|
61695
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
61696
|
+
}
|
|
61697
|
+
const rect = this.recomposeRect(viewportRects);
|
|
61698
|
+
return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
|
|
61643
61699
|
}
|
|
61644
61700
|
/**
|
|
61645
61701
|
* Returns the position of the MainViewport relatively to the start of the grid (without headers)
|
|
@@ -61683,6 +61739,10 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
61683
61739
|
end: start + (isRowHidden ? 0 : size),
|
|
61684
61740
|
};
|
|
61685
61741
|
}
|
|
61742
|
+
getAllActiveViewportsZones() {
|
|
61743
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
61744
|
+
return this.getSubViewports(sheetId);
|
|
61745
|
+
}
|
|
61686
61746
|
// ---------------------------------------------------------------------------
|
|
61687
61747
|
// Private
|
|
61688
61748
|
// ---------------------------------------------------------------------------
|
|
@@ -61873,6 +61933,13 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
61873
61933
|
const height = this.sheetViewHeight + this.gridOffsetY;
|
|
61874
61934
|
return { xRatio: offsetCorrectionX / width, yRatio: offsetCorrectionY / height };
|
|
61875
61935
|
}
|
|
61936
|
+
recomposeRect(viewportRects) {
|
|
61937
|
+
const x = Math.min(...viewportRects.map((rect) => rect.x));
|
|
61938
|
+
const y = Math.min(...viewportRects.map((rect) => rect.y));
|
|
61939
|
+
const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
|
|
61940
|
+
const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
|
|
61941
|
+
return { x, y, width, height };
|
|
61942
|
+
}
|
|
61876
61943
|
}
|
|
61877
61944
|
|
|
61878
61945
|
class HeaderPositionsUIPlugin extends UIPlugin {
|
|
@@ -65487,6 +65554,9 @@ class EventStream {
|
|
|
65487
65554
|
observe(owner, callbacks) {
|
|
65488
65555
|
this.observers.set(owner, { owner, callbacks });
|
|
65489
65556
|
}
|
|
65557
|
+
detachObserver(owner) {
|
|
65558
|
+
this.observers.delete(owner);
|
|
65559
|
+
}
|
|
65490
65560
|
/**
|
|
65491
65561
|
* Capture the stream for yourself
|
|
65492
65562
|
*/
|
|
@@ -65579,6 +65649,9 @@ class SelectionStreamProcessorImpl {
|
|
|
65579
65649
|
observe(owner, callbacks) {
|
|
65580
65650
|
this.stream.observe(owner, callbacks);
|
|
65581
65651
|
}
|
|
65652
|
+
detachObserver(owner) {
|
|
65653
|
+
this.stream.detachObserver(owner);
|
|
65654
|
+
}
|
|
65582
65655
|
release(owner) {
|
|
65583
65656
|
if (this.stream.isListening(owner)) {
|
|
65584
65657
|
this.stream.release(owner);
|
|
@@ -68755,6 +68828,6 @@ const constants = {
|
|
|
68755
68828
|
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 };
|
|
68756
68829
|
|
|
68757
68830
|
|
|
68758
|
-
__info__.version = "17.4.
|
|
68759
|
-
__info__.date = "2025-01-
|
|
68760
|
-
__info__.hash = "
|
|
68831
|
+
__info__.version = "17.4.20";
|
|
68832
|
+
__info__.date = "2025-01-31T08:00:07.103Z";
|
|
68833
|
+
__info__.hash = "54a344a";
|