@odoo/o-spreadsheet 19.1.20 → 19.1.22

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 19.1.20
6
- * @date 2026-05-15T07:06:03.182Z
7
- * @hash b6a68b8
5
+ * @version 19.1.22
6
+ * @date 2026-06-06T06:23:19.222Z
7
+ * @hash 97a02db
8
8
  */
9
9
 
10
10
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
@@ -4303,6 +4303,7 @@ const DEFAULT_LOCALE = DEFAULT_LOCALES[0];
4303
4303
  //#endregion
4304
4304
  //#region src/helpers/format/format_tokenizer.ts
4305
4305
  function tokenizeFormat(str) {
4306
+ str = str.replace(/\s/g, " ");
4306
4307
  const chars = new TokenizingChars(str);
4307
4308
  const result = [];
4308
4309
  let currentFormatPart = [];
@@ -6428,8 +6429,13 @@ function getApplyRangeChangeAddColRow(cmd) {
6428
6429
  changeType: "NONE",
6429
6430
  range
6430
6431
  };
6432
+ const isUnboundedAtEnd = range.unboundedZone[end] === void 0;
6433
+ if (isUnboundedAtEnd && !range.unboundedZone.hasHeader) return {
6434
+ changeType: "RESIZE",
6435
+ range: createAdaptedRange(range, dimension, "RESIZE", cmd.quantity)
6436
+ };
6431
6437
  if (cmd.position === "after") {
6432
- if (range.zone[start] <= cmd.base && cmd.base < range.zone[end]) return {
6438
+ if (range.zone[start] <= cmd.base && (cmd.base < range.zone[end] || isUnboundedAtEnd)) return {
6433
6439
  changeType: "RESIZE",
6434
6440
  range: createAdaptedRange(range, dimension, "RESIZE", cmd.quantity)
6435
6441
  };
@@ -7022,40 +7028,9 @@ var UuidGenerator = class {
7022
7028
  }
7023
7029
  };
7024
7030
 
7025
- //#endregion
7026
- //#region src/registry.ts
7027
- var Registry$1 = class {
7028
- content = {};
7029
- add(key, value) {
7030
- if (key in this.content) throw new Error(`${key} is already present in this registry!`);
7031
- return this.replace(key, value);
7032
- }
7033
- replace(key, value) {
7034
- this.content[key] = value;
7035
- return this;
7036
- }
7037
- get(key) {
7038
- const content = this.content[key];
7039
- if (!content && !(key in this.content)) throw new Error(`Cannot find ${key} in this registry!`);
7040
- return content;
7041
- }
7042
- contains(key) {
7043
- return key in this.content;
7044
- }
7045
- getAll() {
7046
- return Object.values(this.content);
7047
- }
7048
- getKeys() {
7049
- return Object.keys(this.content);
7050
- }
7051
- remove(key) {
7052
- delete this.content[key];
7053
- }
7054
- };
7055
-
7056
7031
  //#endregion
7057
7032
  //#region src/helpers/figures/charts/chart_js_extension.ts
7058
- const chartJsExtensionRegistry = new Registry$1();
7033
+ const chartJsExtensionRegistry = new Registry();
7059
7034
  function areChartJSExtensionsLoaded() {
7060
7035
  return globalThis.Chart ? !!globalThis.Chart.registry.plugins.get("chartShowValuesPlugin") : true;
7061
7036
  }
@@ -7358,6 +7333,10 @@ const FORCE_DEFAULT_ARGS_FUNCTIONS = {
7358
7333
  ROUNDDOWN: [{
7359
7334
  type: "NUMBER",
7360
7335
  value: 0
7336
+ }],
7337
+ IFERROR: [{
7338
+ type: "NUMBER",
7339
+ value: 0
7361
7340
  }]
7362
7341
  };
7363
7342
  /**
@@ -26299,7 +26278,7 @@ const HYPERLINK = {
26299
26278
  //#endregion
26300
26279
  //#region src/functions/function_registry.ts
26301
26280
  const functionNameRegex = /^[A-Z0-9\_\.]+$/;
26302
- var FunctionRegistry = class extends Registry$1 {
26281
+ var FunctionRegistry = class extends Registry {
26303
26282
  mapping = {};
26304
26283
  add(name, addDescr) {
26305
26284
  name = name.toUpperCase();
@@ -35789,7 +35768,7 @@ const WEEK_START = {
35789
35768
 
35790
35769
  //#endregion
35791
35770
  //#region src/migrations/migration_steps.ts
35792
- const migrationStepRegistry = new Registry$1();
35771
+ const migrationStepRegistry = new Registry();
35793
35772
  migrationStepRegistry.add("0.1", { migrate(data) {
35794
35773
  if (data.sheets && data.sheets[0]) data.activeSheet = data.sheets[0].name;
35795
35774
  return data;
@@ -36951,11 +36930,10 @@ const INSERT_TABLE = (env) => {
36951
36930
  if (interactiveCreateTable(env, env.model.getters.getActiveSheetId()).isSuccessful) env.openSidePanel("TableSidePanel", {});
36952
36931
  };
36953
36932
  const DELETE_SELECTED_TABLE = (env) => {
36954
- const position = env.model.getters.getActivePosition();
36955
- const table = env.model.getters.getTable(position);
36933
+ const table = env.model.getters.getFirstTableInSelection();
36956
36934
  if (!table) return;
36957
36935
  env.model.dispatch("REMOVE_TABLE", {
36958
- sheetId: position.sheetId,
36936
+ sheetId: env.model.getters.getActiveSheetId(),
36959
36937
  target: [table.range.zone]
36960
36938
  });
36961
36939
  };
@@ -39324,7 +39302,7 @@ var SpreadsheetPivot = class {
39324
39302
 
39325
39303
  //#endregion
39326
39304
  //#region src/helpers/pivot/pivot_registry.ts
39327
- const pivotRegistry = new Registry$1();
39305
+ const pivotRegistry = new Registry();
39328
39306
  const dateGranularities = [
39329
39307
  "year",
39330
39308
  "quarter_number",
@@ -49477,7 +49455,7 @@ function getVisiblePivotCellPositions(getters, pivotId) {
49477
49455
  col,
49478
49456
  row
49479
49457
  };
49480
- if (pivotId === getters.getPivotIdFromPosition(position)) positions.push(position);
49458
+ if (getters.getPivotIdsFromPosition(position).includes(pivotId)) positions.push(position);
49481
49459
  }
49482
49460
  return positions;
49483
49461
  }
@@ -50577,6 +50555,9 @@ const PIVOT_FUNCTIONS = [
50577
50555
  function getFirstPivotFunction(tokens) {
50578
50556
  return getFunctionsFromTokens(tokens, PIVOT_FUNCTIONS)[0];
50579
50557
  }
50558
+ function getPivotFunctions(tokens) {
50559
+ return getFunctionsFromTokens(tokens, PIVOT_FUNCTIONS);
50560
+ }
50580
50561
  /**
50581
50562
  * Parse a spreadsheet formula and detect the number of PIVOT functions that are
50582
50563
  * present in the given formula.
@@ -61409,6 +61390,7 @@ var PivotUIPlugin = class extends CoreViewPlugin {
61409
61390
  "getFirstPivotFunction",
61410
61391
  "getPivotCellSortDirection",
61411
61392
  "getPivotIdFromPosition",
61393
+ "getPivotIdsFromPosition",
61412
61394
  "getPivotCellFromPosition",
61413
61395
  "generateNewCalculatedMeasureName",
61414
61396
  "isPivotUnused",
@@ -61433,9 +61415,11 @@ var PivotUIPlugin = class extends CoreViewPlugin {
61433
61415
  this.refreshPivot(cmd.id);
61434
61416
  break;
61435
61417
  case "ADD_PIVOT":
61418
+ this.unusedPivotsInFormulas?.push(cmd.pivotId);
61436
61419
  this.setupPivot(cmd.pivotId);
61437
61420
  break;
61438
61421
  case "DUPLICATE_PIVOT":
61422
+ this.unusedPivotsInFormulas?.push(cmd.newPivotId);
61439
61423
  this.setupPivot(cmd.newPivotId);
61440
61424
  break;
61441
61425
  case "UPDATE_PIVOT":
@@ -61466,37 +61450,52 @@ var PivotUIPlugin = class extends CoreViewPlugin {
61466
61450
  }
61467
61451
  }
61468
61452
  /**
61469
- * Get the id of the pivot at the given position. Returns undefined if there
61453
+ * Get the id of the first pivot in the formula at the given position. Returns undefined if there
61470
61454
  * is no pivot at this position
61471
61455
  */
61472
61456
  getPivotIdFromPosition(position) {
61457
+ return this.getPivotIdsFromPosition(position)[0];
61458
+ }
61459
+ /**
61460
+ * Get all of the ids of the pivot present in the formula at the given position.
61461
+ */
61462
+ getPivotIdsFromPosition(position) {
61473
61463
  const cell = this.getters.getCorrespondingFormulaCell(position);
61474
- if (cell && cell.isFormula) {
61475
- const pivotFunction = this.getFirstPivotFunction(position.sheetId, cell.compiledFormula.tokens);
61476
- if (pivotFunction) {
61477
- const pivotId = pivotFunction.args[0]?.toString();
61478
- return pivotId && this.getters.getPivotId(pivotId);
61479
- }
61480
- }
61464
+ if (cell && cell.isFormula) return this.getPivotIdsFromFormula(position.sheetId, cell.compiledFormula);
61465
+ return [];
61466
+ }
61467
+ getPivotIdsFromFormula(sheetId, formula) {
61468
+ return this.getPivotFunctions(sheetId, formula.tokens).map((pivotFunction) => {
61469
+ const pivotId = pivotFunction.args[0]?.toString();
61470
+ return pivotId && this.getters.getPivotId(pivotId);
61471
+ }).filter(isDefined);
61481
61472
  }
61482
61473
  isSpillPivotFormula(position) {
61483
61474
  const cell = this.getters.getCorrespondingFormulaCell(position);
61484
61475
  if (cell && cell.isFormula) return this.getFirstPivotFunction(position.sheetId, cell.compiledFormula.tokens)?.functionName === "PIVOT";
61485
61476
  return false;
61486
61477
  }
61487
- getFirstPivotFunction(sheetId, tokens) {
61488
- const pivotFunction = getFirstPivotFunction(tokens);
61489
- if (!pivotFunction) return;
61490
- const { functionName, args } = pivotFunction;
61491
- return {
61492
- functionName,
61493
- args: args.map((argAst) => {
61478
+ getPivotFunctions(sheetId, tokens) {
61479
+ const pivotFunctions = getPivotFunctions(tokens);
61480
+ if (!pivotFunctions.length) return [];
61481
+ const evaluatedPivotFunctions = [];
61482
+ for (const pivotFunction of pivotFunctions) {
61483
+ const { functionName, args } = pivotFunction;
61484
+ const evaluatedArgs = args.map((argAst) => {
61494
61485
  if (argAst.type === "EMPTY") return;
61495
61486
  else if (argAst.type === "STRING" || argAst.type === "BOOLEAN" || argAst.type === "NUMBER") return argAst.value;
61496
61487
  const argsString = astToFormula(argAst);
61497
61488
  return this.getters.evaluateFormula(sheetId, argsString);
61498
- })
61499
- };
61489
+ });
61490
+ evaluatedPivotFunctions.push({
61491
+ functionName,
61492
+ args: evaluatedArgs
61493
+ });
61494
+ }
61495
+ return evaluatedPivotFunctions;
61496
+ }
61497
+ getFirstPivotFunction(sheetId, tokens) {
61498
+ return this.getPivotFunctions(sheetId, tokens)[0];
61500
61499
  }
61501
61500
  /**
61502
61501
  * Returns the domain args of a pivot formula from a position.
@@ -61602,8 +61601,8 @@ var PivotUIPlugin = class extends CoreViewPlugin {
61602
61601
  const unusedPivots = new Set(this.getters.getPivotIds());
61603
61602
  for (const sheetId of this.getters.getSheetIds()) for (const cellId in this.getters.getCells(sheetId)) {
61604
61603
  const position = this.getters.getCellPosition(cellId);
61605
- const pivotId = this.getPivotIdFromPosition(position);
61606
- if (pivotId) {
61604
+ const pivotIds = this.getPivotIdsFromPosition(position);
61605
+ for (const pivotId of pivotIds) {
61607
61606
  unusedPivots.delete(pivotId);
61608
61607
  if (!unusedPivots.size) {
61609
61608
  this.unusedPivotsInFormulas = [];
@@ -61611,6 +61610,21 @@ var PivotUIPlugin = class extends CoreViewPlugin {
61611
61610
  }
61612
61611
  }
61613
61612
  }
61613
+ for (const pivotId of this.getters.getPivotIds()) {
61614
+ const pivot = this.getters.getPivotCoreDefinition(pivotId);
61615
+ for (const measure of pivot.measures) if (measure.computedBy) {
61616
+ const { sheetId } = measure.computedBy;
61617
+ const formula = this.getters.getMeasureCompiledFormula(pivotId, measure);
61618
+ const relatedPivotIds = this.getPivotIdsFromFormula(sheetId, formula);
61619
+ for (const relatedPivotId of relatedPivotIds) {
61620
+ unusedPivots.delete(relatedPivotId);
61621
+ if (!unusedPivots.size) {
61622
+ this.unusedPivotsInFormulas = [];
61623
+ return [];
61624
+ }
61625
+ }
61626
+ }
61627
+ }
61614
61628
  this.unusedPivotsInFormulas = [...unusedPivots];
61615
61629
  return this.unusedPivotsInFormulas;
61616
61630
  }
@@ -63278,7 +63292,8 @@ const invalidateTableStyleCommandsSet = new Set([
63278
63292
  "REMOVE_TABLE",
63279
63293
  "RESIZE_TABLE",
63280
63294
  "CREATE_TABLE_STYLE",
63281
- "REMOVE_TABLE_STYLE"
63295
+ "REMOVE_TABLE_STYLE",
63296
+ "DELETE_CONTENT"
63282
63297
  ]);
63283
63298
  function doesCommandInvalidatesTableStyle(cmd) {
63284
63299
  return invalidateTableStyleCommandsSet.has(cmd.type);
@@ -68486,10 +68501,10 @@ var SheetViewPlugin = class extends UIPlugin {
68486
68501
 
68487
68502
  //#endregion
68488
68503
  //#region src/plugins/index.ts
68489
- const corePluginRegistry = new Registry$1().add("settings", SettingsPlugin).add("sheet", SheetPlugin).add("header grouping", HeaderGroupingPlugin).add("header visibility", HeaderVisibilityPlugin).add("tables", TablePlugin).add("dataValidation", DataValidationPlugin).add("cell", CellPlugin).add("merge", MergePlugin).add("style", StylePlugin).add("headerSize", HeaderSizePlugin).add("borders", BordersPlugin).add("conditional formatting", ConditionalFormatPlugin).add("figures", FigurePlugin).add("chart", ChartPlugin).add("carousel", CarouselPlugin).add("image", ImagePlugin).add("pivot_core", PivotCorePlugin).add("spreadsheet_pivot_core", SpreadsheetPivotCorePlugin).add("tableStyle", TableStylePlugin);
68490
- const featurePluginRegistry = new Registry$1().add("ui_sheet", SheetUIPlugin).add("ui_options", UIOptionsPlugin).add("autofill", AutofillPlugin).add("sort", SortPlugin).add("automatic_sum", AutomaticSumPlugin).add("format", FormatPlugin).add("insert_pivot", InsertPivotPlugin).add("pivot_presence", PivotPresencePlugin).add("split_to_columns", SplitToColumnsPlugin).add("subtotal_evaluation", SubtotalEvaluationPlugin).add("collaborative", CollaborativePlugin).add("history", HistoryPlugin).add("table_autofill", TableAutofillPlugin).add("table_ui_resize", TableResizeUI).add("datavalidation_insert", DataValidationInsertionPlugin).add("checkbox_toggle", CheckboxTogglePlugin).add("dynamic_translate", DynamicTranslate).add("geo_features", GeoFeaturePlugin).add("data_cleanup", DataCleanupPlugin);
68491
- const statefulUIPluginRegistry = new Registry$1().add("selection", GridSelectionPlugin).add("evaluation_filter", FilterEvaluationPlugin).add("header_visibility_ui", HeaderVisibilityUIPlugin).add("cell_computed_style", CellComputedStylePlugin).add("table_computed_style", TableComputedStylePlugin).add("header_positions", HeaderPositionsUIPlugin).add("viewport", SheetViewPlugin).add("clipboard", ClipboardPlugin).add("carousel_ui", CarouselUIPlugin);
68492
- const coreViewsPluginRegistry = new Registry$1().add("evaluation", EvaluationPlugin).add("evaluation_chart", EvaluationChartPlugin).add("evaluation_cf", EvaluationConditionalFormatPlugin).add("row_size", HeaderSizeUIPlugin).add("data_validation_ui", EvaluationDataValidationPlugin).add("dynamic_tables", DynamicTablesPlugin).add("custom_colors", CustomColorsPlugin).add("pivot_ui", PivotUIPlugin).add("cell_icon", CellIconPlugin);
68504
+ const corePluginRegistry = new Registry().add("settings", SettingsPlugin).add("sheet", SheetPlugin).add("header grouping", HeaderGroupingPlugin).add("header visibility", HeaderVisibilityPlugin).add("tables", TablePlugin).add("dataValidation", DataValidationPlugin).add("cell", CellPlugin).add("merge", MergePlugin).add("style", StylePlugin).add("headerSize", HeaderSizePlugin).add("borders", BordersPlugin).add("conditional formatting", ConditionalFormatPlugin).add("figures", FigurePlugin).add("chart", ChartPlugin).add("carousel", CarouselPlugin).add("image", ImagePlugin).add("pivot_core", PivotCorePlugin).add("spreadsheet_pivot_core", SpreadsheetPivotCorePlugin).add("tableStyle", TableStylePlugin);
68505
+ const featurePluginRegistry = new Registry().add("ui_sheet", SheetUIPlugin).add("ui_options", UIOptionsPlugin).add("autofill", AutofillPlugin).add("sort", SortPlugin).add("automatic_sum", AutomaticSumPlugin).add("format", FormatPlugin).add("insert_pivot", InsertPivotPlugin).add("pivot_presence", PivotPresencePlugin).add("split_to_columns", SplitToColumnsPlugin).add("subtotal_evaluation", SubtotalEvaluationPlugin).add("collaborative", CollaborativePlugin).add("history", HistoryPlugin).add("table_autofill", TableAutofillPlugin).add("table_ui_resize", TableResizeUI).add("datavalidation_insert", DataValidationInsertionPlugin).add("checkbox_toggle", CheckboxTogglePlugin).add("dynamic_translate", DynamicTranslate).add("geo_features", GeoFeaturePlugin).add("data_cleanup", DataCleanupPlugin);
68506
+ const statefulUIPluginRegistry = new Registry().add("selection", GridSelectionPlugin).add("evaluation_filter", FilterEvaluationPlugin).add("header_visibility_ui", HeaderVisibilityUIPlugin).add("cell_computed_style", CellComputedStylePlugin).add("table_computed_style", TableComputedStylePlugin).add("header_positions", HeaderPositionsUIPlugin).add("viewport", SheetViewPlugin).add("clipboard", ClipboardPlugin).add("carousel_ui", CarouselUIPlugin);
68507
+ const coreViewsPluginRegistry = new Registry().add("evaluation", EvaluationPlugin).add("evaluation_chart", EvaluationChartPlugin).add("evaluation_cf", EvaluationConditionalFormatPlugin).add("row_size", HeaderSizeUIPlugin).add("data_validation_ui", EvaluationDataValidationPlugin).add("dynamic_tables", DynamicTablesPlugin).add("custom_colors", CustomColorsPlugin).add("pivot_ui", PivotUIPlugin).add("cell_icon", CellIconPlugin);
68493
68508
 
68494
68509
  //#endregion
68495
68510
  //#region src/registries/auto_completes/data_validation_auto_complete.ts
@@ -74258,6 +74273,11 @@ function lineAttributes(params) {
74258
74273
  `;
74259
74274
  }
74260
74275
  function insertText(text, fontColor = "000000", fontsize = 16, style = {}) {
74276
+ const textProperties = [
74277
+ ["b", style.bold ? "1" : "0"],
74278
+ ["i", style.italic ? "1" : "0"],
74279
+ ["sz", fontsize * 100]
74280
+ ];
74261
74281
  return escapeXml`
74262
74282
  <c:tx>
74263
74283
  <c:rich>
@@ -74265,13 +74285,13 @@ function insertText(text, fontColor = "000000", fontsize = 16, style = {}) {
74265
74285
  <a:lstStyle />
74266
74286
  <a:p>
74267
74287
  <a:pPr lvl="0">
74268
- <a:defRPr b="${style?.bold ? 1 : 0}" i="${style?.italic ? 1 : 0}">
74288
+ <a:defRPr ${formatAttributes(textProperties)}>
74269
74289
  ${solidFill(fontColor)}
74270
74290
  <a:latin typeface="+mn-lt"/>
74271
74291
  </a:defRPr>
74272
74292
  </a:pPr>
74273
74293
  <a:r> <!-- Runs -->
74274
- <a:rPr b="${style?.bold ? 1 : 0}" i="${style?.italic ? 1 : 0}" sz="${fontsize * 100}"/>
74294
+ <a:rPr ${formatAttributes(textProperties)}/>
74275
74295
  <a:t>${text}</a:t>
74276
74296
  </a:r>
74277
74297
  </a:p>
@@ -79284,6 +79304,6 @@ exports.stores = stores;
79284
79304
  exports.tokenColors = tokenColors;
79285
79305
  exports.tokenize = tokenize;
79286
79306
 
79287
- __info__.version = "19.1.20";
79288
- __info__.date = "2026-05-15T07:06:03.182Z";
79289
- __info__.hash = "b6a68b8";
79307
+ __info__.version = "19.1.22";
79308
+ __info__.date = "2026-06-06T06:23:19.222Z";
79309
+ __info__.hash = "97a02db";
@@ -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 19.1.20
6
- * @date 2026-05-15T07:06:04.872Z
7
- * @hash b6a68b8
5
+ * @version 19.1.22
6
+ * @date 2026-06-06T06:23:20.902Z
7
+ * @hash 97a02db
8
8
  */
9
9
  :root {
10
10
  --os-gray-100: light-dark(#f9fafb, #1b1d26);
@@ -2001,6 +2001,7 @@
2001
2001
  right: var(--os-scrollbar-width);
2002
2002
  height: var(--os-header-height);
2003
2003
  width: calc(100% - var(--os-header-width) + var(--os-scrollbar-width));
2004
+ color-scheme: light;
2004
2005
  &.o-dragging {
2005
2006
  cursor: grabbing;
2006
2007
  }
@@ -2036,9 +2037,12 @@
2036
2037
  height: 10000px;
2037
2038
  background-color: var(--os-selection-border-color);
2038
2039
  }
2039
- .o-unhide:hover {
2040
- z-index: calc(var(--os-components-importance-grid) + 1);
2041
- background-color: var(--os-gray-400);
2040
+ .o-unhide {
2041
+ color: var(--os-text-body);
2042
+ &:hover {
2043
+ z-index: calc(var(--os-components-importance-grid) + 1);
2044
+ background-color: var(--os-gray-400);
2045
+ }
2042
2046
  }
2043
2047
  }
2044
2048
 
@@ -2048,6 +2052,7 @@
2048
2052
  left: 0;
2049
2053
  bottom: var(--os-scrollbar-width);
2050
2054
  width: var(--os-header-width);
2055
+ color-scheme: light;
2051
2056
  &.o-dragging {
2052
2057
  cursor: grabbing;
2053
2058
  }
@@ -2083,9 +2088,12 @@
2083
2088
  height: 1px;
2084
2089
  background-color: var(--os-selection-border-color);
2085
2090
  }
2086
- .o-unhide:hover {
2087
- z-index: calc(var(--os-components-importance-grid) + 1);
2088
- background-color: var(--os-gray-400);
2091
+ .o-unhide {
2092
+ color: var(--os-text-body);
2093
+ &:hover {
2094
+ z-index: calc(var(--os-components-importance-grid) + 1);
2095
+ background-color: var(--os-gray-400);
2096
+ }
2089
2097
  }
2090
2098
  }
2091
2099